summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Jamtop3
-rw-r--r--Readme.txt4
-rw-r--r--ccast/axTLS/tls1.c2
-rw-r--r--ccast/ccmdns.c3
-rw-r--r--ccast/ccpacket.c2
-rw-r--r--ccast/dpat.c2
-rw-r--r--ccast/filt.c1
-rw-r--r--debian/README.Debian16
-rw-r--r--debian/argyll-dbg.postinst40
-rw-r--r--debian/argyll-dbg.postrm33
-rw-r--r--debian/argyll-dbg.preinst31
-rw-r--r--debian/argyll-doc.doc-base7
-rw-r--r--debian/argyll-doc.docs2
-rw-r--r--debian/argyll-ref.install1
-rw-r--r--debian/argyll-ref.postinst40
-rw-r--r--debian/argyll-ref.postrm33
-rw-r--r--debian/argyll-ref.preinst31
-rw-r--r--debian/argyll.install3
-rw-r--r--debian/argyll.manpages1
-rw-r--r--debian/argyll.postinst40
-rw-r--r--debian/argyll.postrm34
-rw-r--r--debian/argyll.preinst32
-rw-r--r--debian/changelog707
-rw-r--r--debian/compat1
-rw-r--r--debian/control91
-rw-r--r--debian/copyright965
-rw-r--r--debian/icc-utils.postinst41
-rw-r--r--debian/icc-utils.postrm33
-rw-r--r--debian/icc-utils.preinst32
-rw-r--r--debian/man/applycal.130
-rw-r--r--debian/man/average.129
-rw-r--r--debian/man/cb2ti3.121
-rw-r--r--debian/man/cctiff.173
-rw-r--r--debian/man/ccxxmake.191
-rw-r--r--debian/man/chartread.196
-rw-r--r--debian/man/collink.1241
-rw-r--r--debian/man/colprof.1186
-rw-r--r--debian/man/colverify.168
-rw-r--r--debian/man/dispcal.1156
-rw-r--r--debian/man/dispread.1103
-rw-r--r--debian/man/dispwin.181
-rw-r--r--debian/man/extracticc.112
-rw-r--r--debian/man/extractttag.118
-rw-r--r--debian/man/fakeCMY.121
-rw-r--r--debian/man/fakeread.190
-rw-r--r--debian/man/greytiff.118
-rw-r--r--debian/man/iccdump.121
-rw-r--r--debian/man/iccgamut.197
-rw-r--r--debian/man/icclu.134
-rw-r--r--debian/man/illumread.141
-rw-r--r--debian/man/invprofcheck.145
-rw-r--r--debian/man/kodak2ti3.124
-rw-r--r--debian/man/ls2ti3.113
-rw-r--r--debian/man/mppcheck.129
-rw-r--r--debian/man/mpplu.157
-rw-r--r--debian/man/mppprof.130
-rw-r--r--debian/man/oeminst.128
-rw-r--r--debian/man/printcal.177
-rw-r--r--debian/man/printtarg.1125
-rw-r--r--debian/man/profcheck.161
-rw-r--r--debian/man/refine.157
-rw-r--r--debian/man/revfix.149
-rw-r--r--debian/man/scanin.1114
-rw-r--r--debian/man/spec2cie.147
-rw-r--r--debian/man/specplot.128
-rw-r--r--debian/man/splitti3.133
-rw-r--r--debian/man/spotread.1123
-rw-r--r--debian/man/synthcal.147
-rw-r--r--debian/man/synthread.145
-rw-r--r--debian/man/targen.1112
-rw-r--r--debian/man/tiffgamut.190
-rw-r--r--debian/man/timage.133
-rw-r--r--debian/man/txt2ti3.133
-rw-r--r--debian/man/viewgam.142
-rw-r--r--debian/man/xicclu.1162
-rw-r--r--debian/missing-sources/deep_arrays.json18
-rw-r--r--debian/missing-sources/difficult_json_c_test_case.json7
-rw-r--r--debian/missing-sources/difficult_json_c_test_case_with_comments.json7
-rw-r--r--debian/missing-sources/non_utf8_char_in_string.json88
-rw-r--r--debian/missing-sources/x3dom.debug.js53578
-rw-r--r--debian/patches/100_spelling.patch660
-rw-r--r--debian/patches/110_dispwin_segfault.patch20
-rw-r--r--debian/patches/120_usb-db_new.patch19
-rw-r--r--debian/patches/15_jam.patch143
-rw-r--r--debian/patches/20_hurd_PATH_MAX.patch81
-rw-r--r--debian/patches/25_kfreebsd.patch55
-rw-r--r--debian/patches/30_gcc5.patch20
-rw-r--r--debian/patches/series7
-rwxr-xr-xdebian/rules122
-rw-r--r--debian/source/format1
-rw-r--r--debian/tools/buildman.sh13
-rw-r--r--debian/watch5
-rw-r--r--doc/ArgyllDoc.html2506
-rw-r--r--doc/ChangesSummary.html46
-rw-r--r--doc/File_Formats.html2
-rw-r--r--doc/Installing_OSX.html590
-rw-r--r--doc/Scenarios.html5779
-rw-r--r--doc/SpyderChecker24.jpgbin7270 -> 0 bytes
-rw-r--r--doc/afiles1
-rw-r--r--doc/chartread.html51
-rw-r--r--doc/collink.html208
-rw-r--r--doc/colprof.html107
-rw-r--r--doc/dispcal.html2836
-rw-r--r--doc/dispread.html1304
-rw-r--r--doc/dispwin.html914
-rw-r--r--doc/fakeread.html2
-rw-r--r--doc/iccgamut.html4
-rw-r--r--doc/illumread.html554
-rw-r--r--doc/instruments.html3548
-rw-r--r--doc/targen.html10
-rw-r--r--doc/tiffgamut.html26
-rw-r--r--doc/viewgam.html2
-rw-r--r--doc/xicclu.html2
-rw-r--r--gamut/gammap.c667
-rw-r--r--gamut/gamut.c682
-rw-r--r--gamut/gamut.h25
-rw-r--r--gamut/maptest.c3
-rw-r--r--gamut/nearsmth.c1803
-rw-r--r--gamut/nearsmth.h48
-rw-r--r--gamut/smthtest.c35
-rw-r--r--h/aconfig.h27
-rw-r--r--icc/icc.c53
-rw-r--r--icc/icc.h3
-rw-r--r--link/collink.c223
-rw-r--r--link/monoplot.c30
-rw-r--r--log.txt53
-rw-r--r--makepackagebin.sh5
-rw-r--r--namedc/namedc.c4
-rw-r--r--numlib/Jamfile4
-rw-r--r--numlib/numsup.c310
-rw-r--r--numlib/numsup.h19
-rw-r--r--numlib/ui.c21
-rw-r--r--plot/plot.c7
-rw-r--r--plot/vrml.c2
-rw-r--r--profile/colprof.c2
-rw-r--r--profile/colverify.c2
-rw-r--r--profile/profcheck.c2
-rw-r--r--profile/profout.c16
-rw-r--r--ref/ColorCheckerPassport.cht102
-rw-r--r--ref/SpyderChecker24.cht59
-rw-r--r--ref/SpyderChecker24.cie38
-rw-r--r--ref/afiles2
-rw-r--r--ref/linear.cal2
-rw-r--r--ref/strange.cal2
-rw-r--r--rspl/gam.c46
-rw-r--r--scanin/Jamfile3
-rw-r--r--scanin/SpyderChecker24.cht59
-rw-r--r--scanin/SpyderChecker24.cie38
-rw-r--r--scanin/afiles2
-rw-r--r--spectro/aglob.c1
-rw-r--r--spectro/ccxxmake.c5
-rw-r--r--spectro/chartread.c19
-rw-r--r--spectro/colorhug.c1
-rw-r--r--spectro/conv.c9
-rw-r--r--spectro/dispwin.c7
-rw-r--r--spectro/dtp20.c5
-rw-r--r--spectro/dtp22.c3
-rw-r--r--spectro/dtp41.c5
-rw-r--r--spectro/dtp51.c3
-rw-r--r--spectro/dtp92.c3
-rw-r--r--spectro/ex1.c11
-rw-r--r--spectro/hcfr.c1
-rw-r--r--spectro/huey.c5
-rw-r--r--spectro/i1d3.c58
-rw-r--r--spectro/i1d3.h1
-rw-r--r--spectro/i1disp.c3
-rw-r--r--spectro/i1pro.c3
-rw-r--r--spectro/i1pro_imp.c123
-rw-r--r--spectro/i1pro_imp.h8
-rw-r--r--spectro/inst.c18
-rw-r--r--spectro/inst.h4
-rw-r--r--spectro/instappsup.c2
-rw-r--r--spectro/kleink10.c114
-rw-r--r--spectro/linear.cal272
-rw-r--r--spectro/munki.c3
-rw-r--r--spectro/rspec.c4
-rw-r--r--spectro/rspec.h6
-rw-r--r--spectro/smcube.c13
-rw-r--r--spectro/spec2cie.c2
-rw-r--r--spectro/specbos.c1
-rw-r--r--spectro/spyd2.c30
-rw-r--r--spectro/spyd2.h1
-rw-r--r--spectro/ss.c3
-rw-r--r--spectro/strange.cal272
-rw-r--r--spectro/usbio.c4
-rw-r--r--spectro/usbio_nt.c2
-rw-r--r--target/ifarp.c4
-rw-r--r--target/ifarp.h5
-rw-r--r--target/printtarg.c14
-rw-r--r--target/targen.c2
-rw-r--r--usb/ArgyllCMS.catbin3551 -> 3551 bytes
-rw-r--r--usb/ArgyllCMS.inf458
-rw-r--r--usb/ArgyllCMS.inf.d78
-rw-r--r--usb/ArgyllCMS.inf.t224
-rw-r--r--usb/ArgyllCMS_x64.catbin3535 -> 3535 bytes
-rw-r--r--xicc/bt1886.c2
-rw-r--r--xicc/cam02.c28
-rw-r--r--xicc/iccgamut.c2
-rw-r--r--xicc/tiffgamut.c2
-rw-r--r--xicc/tiffgmts.c4
-rw-r--r--xicc/xicc.c90
-rw-r--r--xicc/xicc.h3
-rw-r--r--xicc/xicclu.c2
-rw-r--r--yajl/afiles2
205 files changed, 71091 insertions, 13854 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6c270cd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.bzr
+.bzrignore
+.pc \ No newline at end of file
diff --git a/Jamtop b/Jamtop
index 6864931..141abd2 100644
--- a/Jamtop
+++ b/Jamtop
@@ -60,7 +60,7 @@ if $(USE_LIBUSB) = true {
}
# For testing CCast
-#DEFINES += CCTEST_PATTERN ;
+DEFINES += CCTEST_PATTERN ;
# Information for compiling and linking GUI programs
@@ -170,7 +170,6 @@ rule CheckForLibrary {
# See if we have a system TIFF, JPEG, PNG or ZLIB library.
# Note this generates: $(TIFFLIB) $(TIFFINC) $(JPEGLIB) $(JPEGINC) $(PNGLIB)
# $(PNGINC) $(ZLIBLIB) $(ZINC)
-# !!!!! Add to makepackagebin.sh -sBUILTIN_XXX=true !!!!!
CheckForLibrary "TIFF" ;
CheckForLibrary "JPEG" ;
CheckForLibrary "PNG" ;
diff --git a/Readme.txt b/Readme.txt
index 1550f1b..3bb253a 100644
--- a/Readme.txt
+++ b/Readme.txt
@@ -2,7 +2,7 @@
Argyll CMS README file - Version 1.8.2
--------------------------------------
-Date: 26th October 2015
+Date: 7th September 2015
Author: Graeme Gill
Introduction
@@ -26,7 +26,7 @@ provided for each major tool, and a general guide to using the tools for
typical color management tasks is also available. A mailing list provides
support for more advanced usage.
-This is Version 1.8.3, a bug fix update to V1.8.2.
+This is Version 1.8.2, a bug fix update to V1.8.1.
The first public release of icclib was in November 1998,
and of Argyll was in October 2000. Code development commenced in 1995. See
Changes Summary for an overview of changes since the last release. Changes
diff --git a/ccast/axTLS/tls1.c b/ccast/axTLS/tls1.c
index d8ce892..b635263 100644
--- a/ccast/axTLS/tls1.c
+++ b/ccast/axTLS/tls1.c
@@ -309,8 +309,6 @@ EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data)
return ret;
}
-int basic_readi(SSL *ssl, uint8_t **in_data);
-
/*
* Internal read the SSL connection used for setup
*/
diff --git a/ccast/ccmdns.c b/ccast/ccmdns.c
index 76ae4d1..0ba3318 100644
--- a/ccast/ccmdns.c
+++ b/ccast/ccmdns.c
@@ -75,7 +75,6 @@
#else
#include "numsup.h"
#endif
-#include "conv.h"
#include "ccmdns.h"
#undef DEBUG
@@ -224,7 +223,7 @@ static int init_send_mDNS(SOCKET *psock) {
// If we're doing a one-shot, we shouldn't transmit from port 5353, */
// but ChromCast won't see the packet if we don't. */
- /* We can't send from port 5353 if someone else is using it, */
+ /* We cant send from port 5353 if someone else is using it, */
/* so set the SO_REUSEADDR option (which is enough for MSWin), */
/* and SO_REUSEPORT for OS X and Linux */
{
diff --git a/ccast/ccpacket.c b/ccast/ccpacket.c
index 2efc11f..97e28d7 100644
--- a/ccast/ccpacket.c
+++ b/ccast/ccpacket.c
@@ -231,7 +231,7 @@ static ccpacket_err connect_ccpacket_imp(
}
/* Connect */
- if ((rv = (connect(p->sock, (struct sockaddr *)&server, sizeof(server)))) != 0) {
+ if (rv = (connect(p->sock, (struct sockaddr *)&server, sizeof(server))) != 0) {
DBG((g_log,0, "TCP connect IP '%s' port %d failed with %d, errno %d\n",p->dip, p->dport,rv,ERRNO))
return ccpacket_connect;
}
diff --git a/ccast/dpat.c b/ccast/dpat.c
index a8792fe..106c52a 100644
--- a/ccast/dpat.c
+++ b/ccast/dpat.c
@@ -440,7 +440,7 @@ double get_ccast_dith(double ipat[DISIZE][DISIZE][3], double val[3]) {
if (vv) {
printf("There are %d unique surrounders:\n",nsur);
for (n = 0; n < nsur; n++) {
- printf("sur %f %f %f\n",ressur[n][0], ressur[n][1], ressur[n][2]);
+ printf("sur %f %f %f\n",ressur[n][0], ressur[n][1], ressur[n][2], ressur[n][3]);
}
}
#endif
diff --git a/ccast/filt.c b/ccast/filt.c
index 65cf7bd..ab075ae 100644
--- a/ccast/filt.c
+++ b/ccast/filt.c
@@ -33,7 +33,6 @@
#include "ccpacket.h"
#include "ccmes.h"
#include "yajl.h"
-#include "ccast.h"
#define DO_WEIGHTING
#define SUM_CONSTRAINT
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 0000000..b707ba4
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,16 @@
+argyll for Debian
+-----------------
+
+Notes for KFreeBSD-*:
+
+From spectro/usbio_bsd.c:
+
+ !!!! This driver is incomplete and non-functional !!!!
+ BSD uses fd per end point, so simplifies things.
+ No clear ep or abort i/o though, so we could try clear halt,
+ or close fd and see if that works in aborting transaction ?
+ Posix aio would probably work, but it's not loaded by default :-(
+ Could use libusb20 API, but not backwards or cross compatible,
+ and is very likely to be buggy ?
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Mon, 29 Sep 2014 09:17:15 +0200
diff --git a/debian/argyll-dbg.postinst b/debian/argyll-dbg.postinst
new file mode 100644
index 0000000..66ce5b3
--- /dev/null
+++ b/debian/argyll-dbg.postinst
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <postinst> `abort-remove'
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+# source debconf library
+#. /usr/share/debconf/confmodule
+
+
+case "$1" in
+
+ configure|abort-upgrade|abort-remove|abort-deconfigure)
+ # Replace documentation directory symlink
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll-dbg /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+
+esac
+
+#DEBHELPER#
+
+
+exit 0
diff --git a/debian/argyll-dbg.postrm b/debian/argyll-dbg.postrm
new file mode 100644
index 0000000..0ebb9d3
--- /dev/null
+++ b/debian/argyll-dbg.postrm
@@ -0,0 +1,33 @@
+#! /bin/sh
+# postrm script for argyll
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
+# for details, see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll-dbg /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 0
+
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
diff --git a/debian/argyll-dbg.preinst b/debian/argyll-dbg.preinst
new file mode 100644
index 0000000..94caee7
--- /dev/null
+++ b/debian/argyll-dbg.preinst
@@ -0,0 +1,31 @@
+#!/bin/sh
+# preinst script for #PACKAGE#
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <new-preinst> `install'
+# * <new-preinst> `install' <old-version>
+# * <new-preinst> `upgrade' <old-version>
+# * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+ install|upgrade|abort-upgrade)
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll-dbg /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/argyll-doc.doc-base b/debian/argyll-doc.doc-base
new file mode 100644
index 0000000..962b063
--- /dev/null
+++ b/debian/argyll-doc.doc-base
@@ -0,0 +1,7 @@
+Document: argyll
+Title: Argyll Documentation
+Section: Graphics
+
+Format: HTML
+Index: /usr/share/doc/argyll-doc/ArgyllDoc.html
+Files: /usr/share/doc/argyll-doc/*.html
diff --git a/debian/argyll-doc.docs b/debian/argyll-doc.docs
new file mode 100644
index 0000000..f7d7b3b
--- /dev/null
+++ b/debian/argyll-doc.docs
@@ -0,0 +1,2 @@
+doc/*
+Readme.txt
diff --git a/debian/argyll-ref.install b/debian/argyll-ref.install
new file mode 100644
index 0000000..beefdac
--- /dev/null
+++ b/debian/argyll-ref.install
@@ -0,0 +1 @@
+usr/share/color/argyll/ref
diff --git a/debian/argyll-ref.postinst b/debian/argyll-ref.postinst
new file mode 100644
index 0000000..5584c80
--- /dev/null
+++ b/debian/argyll-ref.postinst
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <postinst> `abort-remove'
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+# source debconf library
+#. /usr/share/debconf/confmodule
+
+
+case "$1" in
+
+ configure|abort-upgrade|abort-remove|abort-deconfigure)
+ # Replace documentation directory symlink
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll-ref /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+
+esac
+
+#DEBHELPER#
+
+
+exit 0
diff --git a/debian/argyll-ref.postrm b/debian/argyll-ref.postrm
new file mode 100644
index 0000000..3741e51
--- /dev/null
+++ b/debian/argyll-ref.postrm
@@ -0,0 +1,33 @@
+#! /bin/sh
+# postrm script for argyll
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
+# for details, see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll-ref /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 0
+
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
diff --git a/debian/argyll-ref.preinst b/debian/argyll-ref.preinst
new file mode 100644
index 0000000..d5fdfc6
--- /dev/null
+++ b/debian/argyll-ref.preinst
@@ -0,0 +1,31 @@
+#!/bin/sh
+# preinst script for #PACKAGE#
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <new-preinst> `install'
+# * <new-preinst> `install' <old-version>
+# * <new-preinst> `upgrade' <old-version>
+# * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+ install|upgrade|abort-upgrade)
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll-ref /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/argyll.install b/debian/argyll.install
new file mode 100644
index 0000000..0b1afee
--- /dev/null
+++ b/debian/argyll.install
@@ -0,0 +1,3 @@
+usb/55-Argyll.rules lib/udev/rules.d/
+usb/Argyll.usermap etc/hotplug/usb
+usr/bin/*
diff --git a/debian/argyll.manpages b/debian/argyll.manpages
new file mode 100644
index 0000000..13cdaf4
--- /dev/null
+++ b/debian/argyll.manpages
@@ -0,0 +1 @@
+debian/man/*.1
diff --git a/debian/argyll.postinst b/debian/argyll.postinst
new file mode 100644
index 0000000..7621237
--- /dev/null
+++ b/debian/argyll.postinst
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <postinst> `abort-remove'
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+# source debconf library
+#. /usr/share/debconf/confmodule
+
+
+case "$1" in
+
+ configure|abort-upgrade|abort-remove|abort-deconfigure)
+ # Replace documentation directory symlink
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+
+esac
+
+#DEBHELPER#
+
+
+exit 0
diff --git a/debian/argyll.postrm b/debian/argyll.postrm
new file mode 100644
index 0000000..f9614cb
--- /dev/null
+++ b/debian/argyll.postrm
@@ -0,0 +1,34 @@
+#! /bin/sh
+# postrm script for argyll
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
+# for details, see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ rm -rf /var/lib/argyll
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 0
+
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
diff --git a/debian/argyll.preinst b/debian/argyll.preinst
new file mode 100644
index 0000000..a3bdca6
--- /dev/null
+++ b/debian/argyll.preinst
@@ -0,0 +1,32 @@
+#!/bin/sh
+# preinst script for #PACKAGE#
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <new-preinst> `install'
+# * <new-preinst> `install' <old-version>
+# * <new-preinst> `upgrade' <old-version>
+# * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ install|upgrade|abort-upgrade)
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/argyll /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..b8f6ba4
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,707 @@
+argyll (1.8.2+repack-1) unstable; urgency=medium
+
+ * New upstream release.
+ * Add x3dom.debug.js to debian/missing-sources.
+ * debian/control:
+ - For use of the system library instead of the Argyll library
+ add libssl-dev to Build-Depends
+ * debian/patches/100_spelling.patch:
+ - Add some more typos.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Wed, 30 Sep 2015 16:03:54 +0200
+
+argyll (1.8.0+repack-1) unstable; urgency=low
+
+ * New upstream release.
+ * Refresh patches:
+ - debian/patches/15_jam.patch
+ - debian/patches/100_spelling.patch
+ - debian/patches/110_dispwin_segfault.patch
+ * debian/rules:
+ - Rewrite VERSION sniplet.
+ - get-orig-source:
+ + Remove executable flag from source.
+ * Refresh debian/copyright.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Sun, 23 Aug 2015 17:27:26 +0200
+
+argyll (1.7.0+repack-4) unstable; urgency=medium
+
+ * debian/rules:
+ - Add --utc to the command date for CRDATE to make the results
+ reproducible over different timezones.
+ * New debian/patches/30_gcc5.patch:
+ - Add gcc-5 support (Closes: #777779).
+ + Thanks to James Cowgill <james410@cowgill.org.uk>.
+ * Re-enable and refresh debian/patches/20_hurd_PATH_MAX.patch.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Sun, 05 Jul 2015 12:30:03 +0200
+
+argyll (1.7.0+repack-3) unstable; urgency=medium
+
+ * debian/watch:
+ - change opts to support for "+repack".
+ * debian/patches/15_jam.patch:
+ - Add support for mips64el (Closes: #788447).
+ * debian/control:
+ - Correct some priorities.
+ - Remove package icc-utils because last version
+ in stable is greater then 1.6.3-1.
+ * Remove useless debian/argyll.lintian-overrides.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Fri, 12 Jun 2015 12:13:59 +0200
+
+argyll (1.7.0+repack-2) unstable; urgency=medium
+
+ * debian/patches/15_jam.patch:
+ - Rewrite rules to find libraries on all architectures.
+ * debian/control:
+ - Add zlib1g-dev to Build-Depends.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Mon, 04 May 2015 10:15:34 +0200
+
+argyll (1.7.0+repack-1) unstable; urgency=low
+
+ * Set package type to +repack.
+ * debian/control:
+ - Add libpng12-dev to build-Depends.
+ - Set Priority to optional.
+ - At package icc-utils and argyll-dbg set the Priority to extra.
+ * Make debian/man/scanin.1 more readable (LP: #1192368).
+ * Make build results reproducible:
+ - debian/rules:
+ + Replace build timestamps from ref files with date/time from
+ debian/changelog.
+ - debian/control:
+ + Add dpkg-dev to Build-Depends.
+ * debian/rules:
+ - get-orig-source:
+ + Remove unwanted Windows binaries.
+ + Remove unused sources: tiff, jpeg, zlib, png.
+ - Add ls2ti3 to build-manpages.
+ - New override_dh_compress:
+ + Don't compress html files.
+ * debian/copyright:
+ - Remove unused tags.
+ - Add new files.
+ - Set year 2015.
+ - Reorder files to prevend lintian warnings.
+ * Remove patches:
+ - 120_usb-db_new.patch applied upstream.
+ - 20_hurd_PATH_MAX.patch & 25_kfreebsd.patch not more needed.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Sun, 03 May 2015 19:36:05 +0200
+
+argyll (1.6.3-4) unstable; urgency=medium
+
+ * debian/control:
+ - On package argyll replace the wrong Replaces & Conflicts of argyll-bin
+ with the right Breaks & Replaces to icc-utils (<< 1.6.3-1).
+ (Closes: #767837)
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Tue, 04 Nov 2014 07:59:20 +0100
+
+argyll (1.6.3-3) unstable; urgency=medium
+
+ * debian/control:
+ - Replace Architecture: any with linux-any to prevent KFreeBSD-* and
+ hurd-i386 from build during unusable usb system (Closes: #762773).
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Sun, 05 Oct 2014 19:31:16 +0200
+
+argyll (1.6.3-2) unstable; urgency=medium
+
+ * debian/control:
+ - Bump Standards-Version to 3.9.6 (no changes required).
+ - Add Replaces: argyll (<< 1.6.3-1) and
+ Breaks (<< 1.6.3-1) to argyll-ref (Closes: #762780).
+ - At argyll move argyll-doc from Depends to Suggests (Closes: #762850).
+ - Remove from Build-Depends libusbhid-dev [kfreebsd-any].
+ - Remove ${shlibs:Depends} from Depends on argyll-doc and argyll-ref.
+ * debian/patches/15_jam.patch:
+ - To avoid use of the builtin libtiff and libjpeg add multiarch directories
+ for searching libraries and header files by using DEB_HOST_MULTIARCH
+ (Closes: #762772).
+ * New debian/patches/20_hurd_PATH_MAX.patch:
+ - Add missing PATH_MAX for hurd-i386 (Closes: #762774).
+ * debian/rules:
+ - Remove the move of the html docs into a subdirectory (Closes: #762771).
+ - Remove useless BUILTIN_TIFF=false from JAMCMDLINE.
+ - Remove "-A --link-doc=argyll-doc" from dh_installdocs (Closes: #762853).
+ * debian/*.(postinst|preinst|postrm):
+ - Replace dpkg-maintscript-helper dir_to_symlink to sysmlink_to_dir.
+ * Remove useless debian/argyll.examples
+ * Remove obsolete debian/patches/03_usb-db.diff.
+ * New debian/patches/120_usb-db_new.patch: (Closes: #762887)
+ - Instead of the obsolete usb-db use the builtin hwdb in the udev rules.
+ Thanks to Michael Biebl <biebl@debian.org>
+ * New debian/patches/25_kfreebsd.patch:
+ - Prevent build errors on kfreebsd-* (Closes: #762773).
+ Thanks to Steven Chamberlain <steven@pyro.eu.org>
+ * New debian/README.debian with notes to KFreeBSD-*.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Mon, 29 Sep 2014 09:22:15 +0200
+
+argyll (1.6.3-1) unstable; urgency=medium
+
+ * New Maintainer (Closes: #720178).
+ * New upstream release (Closes: #742658).
+ * debian/rules:
+ - Add get-orig-source.
+ - Remove useless --with quilt from dh $@
+ - Remove section for not included spyder2 firmware.
+ - Rewrite for use of upstream build system.
+ * debian/control:
+ - Set myself as maintainer.
+ - Update Build-Depends:
+ + Remove automake | automaken
+ - For previously not existing Vcs
+ + Create a new git repository on alioth.
+ + Add the fields Vcs-Browser and Vcs-Git.
+ - Change Priority from optional to extra.
+ - Remove useless packages:
+ + icc-utils
+ Now in argyll. Now only dummy package.
+ Change section to oldlibs
+ + libicc2 & libicc-dev
+ Useless. Only linked to argyll & icc-utils.
+ + libimdi0 & libimdi-dev
+ Useless. Only linked to argyll & icc-utils.
+ - Move documentation to new package argyll-doc
+ and symlink into the other packages.
+ - Add Pre-Depends:
+ * dpkg (>= 1.17.5) for use of the dpkg-maintscript-helper.
+ * debian/copyright:
+ - Rewrite into DEP-5 format.
+ - Add myself to the list of authors for debian/*.
+ - Add missing licenses and authors.
+ * debian/*.1
+ - Move to debian/man/*.1.
+ * debian/man/*
+ - Rewrite the help2man generated man pages (Closes: #670857)
+ * debian/patches/
+ - New 110_dispwin_segfault.patch to prevent segfault by
+ wrong parameter (Closes: #700253)
+ - Rewrite 03_usb-db.diff for new upstream release.
+ - Remove patches that included into new upstream release or useless:
+ + 01_autotools-support.diff
+ + 02_firmware-package-builder.diff
+ + 03_kfreebsd.diff
+ + 04_CVE-2012-4405.diff
+ + 05_external-yajl.diff
+ + 06_fix_udev_rule.patch
+ * New debian/*.(postinst|preinst|postrm):
+ - Remove existing doc directory and replace it with
+ a symlink to argyll-doc with dpkg-maintscript-helper dir_to_symlink.
+ * debian/argyll.preinst:
+ - Remove useless rm_conffile(). First version in Debian was 1.1.1-1,
+ rm_conffile was for version less equal 1.1.0-3.
+
+ -- Jörg Frings-Fürst <debian@jff-webhosting.net> Wed, 17 Sep 2014 08:47:26 +0200
+
+argyll (1.5.1-8) unstable; urgency=medium
+
+ * QA upload.
+ * Add a symbols file for libicc2 and libimdi0.
+
+ -- Iain Lane <laney@debian.org> Mon, 09 Jun 2014 12:52:11 +0100
+
+argyll (1.5.1-7) unstable; urgency=medium
+
+ * QA upload.
+ * debian/control: Bump udev recommended version to >= 196
+
+ -- Laurent Bigonville <bigon@debian.org> Sun, 04 May 2014 22:30:57 +0200
+
+argyll (1.5.1-6) unstable; urgency=medium
+
+ * QA upload.
+ * debian/patches/03_usb-db.diff: Use hwdb builtin, instead of the obsolete
+ usb-db in the udev rules.
+ * debian/patches/06_fix_udev_rule.patch: Fix udev rules to actually work;
+ ENV{ACL_MANAGE} has stopped working ages ago, and with logind it's now the
+ "uaccess" tag. Dropping also consolekit from Recommends. (Closes: #746974)
+ * debian/rules: Add libpam-systemd as a recommends to be sure we have a
+ session registered, this is needed for the permissions on the devices.
+ * debian/control: Build-depend on libtiff-dev rather than libtiff4-dev.
+ (Closes: #733126)
+ * debian/control: Drop Uploaders as the package has been orphaned
+ * debian/control: Bump Standards-Version to 3.9.5 (no further changes)
+
+ -- Laurent Bigonville <bigon@debian.org> Sun, 04 May 2014 21:36:24 +0200
+
+argyll (1.5.1-5) unstable; urgency=low
+
+ * Package orphaned. I don't intent to support the work of an agressive
+ upstream author more longer and realy good luck for the next maintainer.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 19 Aug 2013 14:18:29 +0200
+
+argyll (1.5.1-4) unstable; urgency=low
+
+ * Revert previous yajl patch this break argyll.
+ * Regenerate all manpages.
+ * Add colord and gir1.2-colordgtk-1.0 in Suggests.
+ * Don't package .a and .la files.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 12 Aug 2013 15:51:54 +0200
+
+argyll (1.5.1-3) unstable; urgency=low
+
+ * Uptade patch 01_autotools-support with patch from bug report to link
+ argyll against external yajl also add an one line patch called
+ 05_external-yajl (Closes: #544223)
+
+ -- Christian Marillat <marillat@debian.org> Fri, 02 Aug 2013 08:10:38 +0200
+
+argyll (1.5.1-2) unstable; urgency=low
+
+ * Package iccdump.1 and icclu.1 only in icc-utils package
+ (Closes: #717990, # 717993).
+
+ -- Christian Marillat <marillat@debian.org> Sat, 27 Jul 2013 21:43:59 +0200
+
+argyll (1.5.1-1) unstable; urgency=low
+
+ * New upstream release.
+ * Removed 03_kfreebsd patch.
+ * Refresh 01_autotools-support patch (CLoses: 713545)
+ * New patch 03_usb-db to add support for newer udev (Closes: 717504)
+
+ -- Christian Marillat <marillat@debian.org> Fri, 26 Jul 2013 16:25:19 +0200
+
+argyll (1.4.0-8) unstable; urgency=low
+
+ * Add a Breaks field and update the version in the Replaces field for the
+ icc-utils package (Closes: #694287)
+
+ -- Christian Marillat <marillat@debian.org> Sun, 25 Nov 2012 09:59:35 +0100
+
+argyll (1.4.0-7) unstable; urgency=high
+
+ * New patch 04_CVE-2012-4405.diff to fix CVE-2012-4405 issue
+ (Closes: #687275)
+
+ -- Christian Marillat <marillat@debian.org> Tue, 11 Sep 2012 13:45:12 +0200
+
+argyll (1.4.0-6) unstable; urgency=low
+
+ * Use dh_autoreconf (Closes: #678909)
+
+ -- Christian Marillat <marillat@debian.org> Mon, 25 Jun 2012 07:52:56 +0200
+
+argyll (1.4.0-5) unstable; urgency=low
+
+ * Refresh 01_autotools-support patch (Closes: #678750).
+
+ -- Christian Marillat <marillat@debian.org> Mon, 25 Jun 2012 00:01:31 +0200
+
+argyll (1.4.0-4) unstable; urgency=low
+
+ * Should Build-Depends on libusb-dev (Closes: #670329).
+
+ -- Christian Marillat <marillat@debian.org> Wed, 25 Apr 2012 07:46:07 +0200
+
+argyll (1.4.0-3) unstable; urgency=low
+
+ * Fix kfreebsd build. Thanks to Robert Millan for the patch.
+ (Closes: #595951 #630208).
+
+ -- Christian Marillat <marillat@debian.org> Tue, 24 Apr 2012 07:49:03 +0200
+
+argyll (1.4.0-2) unstable; urgency=low
+
+ * Move binaries from libicc2 package to a new icc-utils package (Closes:
+ #670003).
+
+ -- Christian Marillat <marillat@debian.org> Sun, 22 Apr 2012 16:07:43 +0200
+
+argyll (1.4.0-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Christian Marillat <marillat@debian.org> Sat, 21 Apr 2012 15:53:50 +0200
+
+argyll (1.3.7-1.1) unstable; urgency=low
+
+ * Use DEB_LDFLAGS_MAINT_APPEND to add more LDFLAGS (Closes: #667924)
+
+ -- Christian Marillat <marillat@debian.org> Mon, 09 Apr 2012 10:45:56 +0200
+
+argyll (1.3.7-1) unstable; urgency=low
+
+ * New upstream release.
+ * Try to fix the build (Thanks to Dmitry Nezhevenko) (Closes: #665055).
+ * Move to debhelper 9 for multi-arch and hardened flags.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 03 Apr 2012 08:46:37 +0200
+
+argyll (1.3.6-3) unstable; urgency=low
+
+ * Call dh_quilt_unpatch after MAKE distclean.
+ * Rework Makefile test to be sure we don't call upstream Makefile with
+ missing distclean target.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 20 Mar 2012 14:44:40 +0100
+
+argyll (1.3.6-2) unstable; urgency=low
+
+ * debian/rules Fix clean target.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 19 Mar 2012 16:50:40 +0100
+
+argyll (1.3.6-1) unstable; urgency=low
+
+ * New upstream release.
+ * Removed 03_add-ColorHug_sensor_driver patch, but beware the support for
+ ColorHug is experimental.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 19 Mar 2012 10:55:20 +0100
+
+argyll (1.3.5-7) unstable; urgency=low
+
+ * Really fix previous bug.
+ * Use debhelper 9.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 13 Mar 2012 08:41:01 +0100
+
+argyll (1.3.5-6) unstable; urgency=low
+
+ * Fix another bug in ColorHugColorHug (Closes: #661643)
+
+ -- Christian Marillat <marillat@debian.org> Sun, 11 Mar 2012 16:59:06 +0100
+
+argyll (1.3.5-5) unstable; urgency=low
+
+ * Fix two bugs in ColorHugColorHug patch (Closes: #657582).
+
+ -- Christian Marillat <marillat@debian.org> Sat, 28 Jan 2012 01:42:30 +0100
+
+argyll (1.3.5-4) unstable; urgency=low
+
+ * New patch 03_add-ColorHug_sensor_driver to add support for the ColorHug
+ sensor (Closes: #655888)
+
+ -- Christian Marillat <marillat@debian.org> Tue, 17 Jan 2012 18:22:51 +0100
+
+argyll (1.3.5-3) unstable; urgency=low
+
+ * debian/rules Enable make distclean (Closes: #649728).
+
+ -- Christian Marillat <marillat@debian.org> Wed, 23 Nov 2011 15:17:42 +0100
+
+argyll (1.3.5-2) unstable; urgency=low
+
+ * Don't package icclu and iccdump binaries in argyll, files already in
+ libicc2 package.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 21 Nov 2011 08:25:40 +0100
+
+argyll (1.3.5-1) unstable; urgency=low
+
+ [ Christian Marillat ]
+ * New maintainer (Closes: #622620) Thanks, Roland!
+ * Use dh-autoreconf.
+
+ [ Dmitry Nezhevenko ]
+ * New upstream release (Closes: #647093).
+ * Switch to dpkg-source 3.0 (quilt) format.
+ * Merge debian changes from 1.3.0 (experimental) and 1.1.1 (unstable).
+ * Unsplit libicc2, built from the same source package again (since
+ upstream only ships it as part of Argyll anyway). Actually was already
+ done in experimental (Closes: #636801).
+ * Use kfreebsd-any instead of kfreebsd-(i386|amd64) to match kFreeBSD
+ (Closes: #634688).
+ * Provide dedicated libimdi0/libimdi-dev libraries (Closes: #611139).
+ * Add argyll-dbg package with debug symbols.
+
+ -- Christian Marillat <marillat@debian.org> Sun, 13 Nov 2011 15:30:42 +0100
+
+argyll (1.3.0-3) experimental; urgency=low
+
+ * Minor future-proofing in debian/rules.
+ * Also removed redundant shipping of the firmware-package-builder
+ tarball, thanks to Pascal de Bruijn for noticing.
+
+ -- Roland Mas <lolando@debian.org> Fri, 17 Sep 2010 11:05:22 +0200
+
+argyll (1.3.0-2) experimental; urgency=low
+
+ * Fixed packaging bugs introduced when un-splitting the source package.
+
+ -- Roland Mas <lolando@debian.org> Tue, 14 Sep 2010 11:29:27 +0200
+
+argyll (1.3.0-1) experimental; urgency=low
+
+ * New upstream release.
+
+ -- Roland Mas <lolando@debian.org> Wed, 08 Sep 2010 15:16:29 +0200
+
+argyll (1.2.1-1) experimental; urgency=low
+
+ * New upstream bugfix release.
+ * Please welcome Xavier Oswald as uploader.
+
+ -- Roland Mas <lolando@debian.org> Sun, 05 Sep 2010 15:50:41 +0200
+
+argyll (1.2.0-0) UNRELEASED; urgency=low
+
+ * New upstream release.
+ * Unsplit libicc2, built from the same source package again (since
+ upstream only ships it as part of Argyll anyway).
+ * Bumped Standards-Version to 3.9.1 (no changes).
+ * argyll-firmware-spyder2: Moved firmware to /usr/share/color, which is
+ freedesktop.org-compliant and (more to the point) where Argyll 1.2.0
+ looks for it.
+
+ -- Roland Mas <lolando@debian.org> Thu, 05 Aug 2010 15:33:20 +0200
+
+argyll (1.1.1-2) unstable; urgency=medium
+
+ * QA upload.
+ * Add ../libargyll.la to LDADD (Closes: #615692).
+ * Don't ship .la files (Closes: #621142).
+
+ -- Luk Claes <luk@debian.org> Sat, 11 Jun 2011 11:18:43 +0200
+
+argyll (1.1.1-1) unstable; urgency=low
+
+ * New upstream release.
+ * Switched dependency on policykit-1 to a more correct recommendation on
+ consolekit + recent udev.
+ * Updated copyright file (doc is now GFDL-1.3).
+ * Bumped Standards-Version to 3.8.4 (no changes required).
+
+ -- Roland Mas <lolando@debian.org> Wed, 24 Feb 2010 21:26:55 +0100
+
+argyll (1.1.0-5) unstable; urgency=low
+
+ * Bumped version build-dependency on libicc-dev to prevent segmentation
+ fault.
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 19:06:07 +0100
+
+argyll (1.1.0-4) unstable; urgency=low
+
+ * Adapted packaging to new udev rules, now compatible with PolicyKit-1
+ (closes: #529411). This should fix device file permissions problems,
+ too (closes: #549406). And also the "deprecated udev function"
+ warning (closes: #564269).
+ * Removed conffiles no longer shipped by the package.
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 13:47:59 +0100
+
+argyll (1.1.0-3) unstable; urgency=low
+
+ * Only depend on udev for Linux systems.
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 11:42:54 +0100
+
+argyll (1.1.0-2) unstable; urgency=low
+
+ * Fix build on FreeBSD, patch from Petr Salinger
+ <Petr.Salinger@seznam.cz> (closes: #566768).
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 10:29:33 +0100
+
+argyll (1.1.0-1) unstable; urgency=low
+
+ * New upstream release, including a patch obtained from upstream just
+ after the actual release.
+ * Also, stop using the system's libusb, which causes known problems with
+ Argyll. Now using Argyll's patched copy (privately, since the patches
+ cause problems with other software).
+
+ -- Roland Mas <lolando@debian.org> Sun, 24 Jan 2010 23:34:18 +0100
+
+argyll (1.1.0~rc4-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Ship all doc files with a wildcard rule, rather than a fixed (and
+ outdated) set.
+
+ -- Roland Mas <lolando@debian.org> Wed, 06 Jan 2010 10:33:54 +0100
+
+argyll (1.1.0~rc3-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Moved udev rules file to /lib/udev/rules.d.
+
+ -- Roland Mas <lolando@debian.org> Tue, 05 Jan 2010 14:49:38 +0100
+
+argyll (1.1.0~rc2-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Updated location of Bazaar branches in control file.
+ * The Debian-specific branch now feeds from the "midstream" branch
+ rather than the "upstream-releases" branch, to ease collaboration with
+ other distributions. This shouldn't make any difference on the
+ package contents.
+
+ -- Roland Mas <lolando@debian.org> Thu, 10 Dec 2009 17:26:04 +0100
+
+argyll (1.1.0~rc1+dfsg-1) unstable; urgency=low
+
+ * Removed non-free IETF RFC/I-D from source package, thanks to Simon
+ Josefsson (closes: #555377).
+
+ -- Roland Mas <lolando@debian.org> Sat, 14 Nov 2009 20:23:53 +0100
+
+argyll (1.1.0~rc1-3) unstable; urgency=low
+
+ * Added Build-Depends: libusbhid-dev for kFreeBSD architectures.
+
+ -- Roland Mas <lolando@debian.org> Mon, 09 Nov 2009 13:34:54 +0100
+
+argyll (1.1.0~rc1-2) unstable; urgency=low
+
+ * Fixed build on GNU/kFreeBSD ports.
+ * Applied patch from upstream that fixes an infinite loop if Xrandr is
+ enabled.
+
+ -- Roland Mas <lolando@debian.org> Mon, 09 Nov 2009 11:46:57 +0100
+
+argyll (1.1.0~rc1-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Updated debian/copyright (upstream switched to Affero GPLv3).
+ * Bumped versioned build-dependency on debhelper.
+ * Bumped standards version to 3.8.3 (no changes needed).
+
+ -- Roland Mas <lolando@debian.org> Sun, 08 Nov 2009 22:19:45 +0100
+
+argyll (1.0.4-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Roland Mas <lolando@debian.org> Fri, 03 Jul 2009 14:14:11 +0200
+
+argyll (1.0.3+dfsg1-3) unstable; urgency=low
+
+ * libicc is now a separate source+binary package, so argyll now links
+ against it.
+ * Since that new libicc is a proper new upstream snapshot, the problems
+ introduced with the local patches should be fixed (closes: #524478).
+
+ -- Roland Mas <lolando@debian.org> Tue, 02 Jun 2009 11:26:01 +0200
+
+argyll (1.0.3+dfsg1-2) unstable; urgency=low
+
+ * Adapted debian/watch file to match version mangling.
+ * Updated autotools build system to dynamically link against the
+ internal libraries and provide a libicc.so for dynamic linking.
+ * Also ship the corresponding header files.
+ * Not splitting libicc into its own binary package just yet though, I
+ want to get more testing of the dynamic linking first.
+
+ -- Roland Mas <lolando@debian.org> Thu, 14 May 2009 16:49:44 +0200
+
+argyll (1.0.3+dfsg1-1) unstable; urgency=low
+
+ * argyll-firmware-spyder2 is now generated as section non-free/graphics
+ rather than just graphics.
+ * Removed non-free RFC from source package (closes: #524972).
+
+ -- Roland Mas <lolando@debian.org> Tue, 28 Apr 2009 11:47:38 +0200
+
+argyll (1.0.3-5) unstable; urgency=low
+
+ * Documented web interface for the Bazaar repository.
+ * Added source package for the Spyder2 firmware.
+
+ -- Roland Mas <lolando@debian.org> Fri, 17 Apr 2009 23:34:40 +0200
+
+argyll (1.0.3-4) unstable; urgency=low
+
+ * Actually create /var/lib/argyll so spyd2en can store its firmware in
+ it... also remove it on purge.
+ * Also look for the Spyder2 firmware in /lib/firmware.
+ * Shortened debian/rules quite a bit thanks to Debhelper 7.
+ * Fixed build rules so testsuite passes.
+ * Bumped standards-version to 3.8.1 (no changes).
+
+ -- Roland Mas <lolando@debian.org> Thu, 16 Apr 2009 11:25:26 +0200
+
+argyll (1.0.3-3) unstable; urgency=low
+
+ * Another patch for icclib, this time from Jan Lieskovsky, fixing some
+ more vulnerabilities described in CVE-2009-0792 (closes: #523472).
+
+ -- Roland Mas <lolando@debian.org> Fri, 10 Apr 2009 17:53:55 +0200
+
+argyll (1.0.3-2) unstable; urgency=low
+
+ * Patched embedded copy of icclib to fix integer overflow and denial of
+ service vulnerabilities as described in CVE-2009-0583 and
+ CVE-2009-0584. Patch provided by Moritz Muehlenhoff and the Debian
+ security team (closes: #522448).
+
+ -- Roland Mas <lolando@debian.org> Fri, 03 Apr 2009 22:43:14 +0200
+
+argyll (1.0.3-1) unstable; urgency=low
+
+ * New upstream release.
+ * Adopted package from Christian Marillat's Debian-Multimedia
+ repository (closes: #498396). Thanks, Christian!
+ * Stopped removing some files in clean target.
+ * Switched build-system to autotools.
+ * Link to system libusb rather than locally-shipped one.
+ * Fixed watch file.
+ * Moved Spyder2 firmware to /var/lib/argyll.
+ * Added detailed debian/copyright file.
+ * Use dh_prep instead of dh_clean -k.
+ * Rename /usr/bin/foo to /usr/bin/argyll-foo, for foo in
+ {average,refine,targen,verify}, to avoid having binaries with too
+ generic names. Documented in README.Debian.
+
+ -- Roland Mas <lolando@debian.org> Thu, 19 Feb 2009 20:34:48 +0100
+
+argyll (1.0.0-0.0) unstable; urgency=low
+
+ * New upstream release.
+ * Added configuration files for udev, hal and policykit.
+
+ -- Christian Marillat <marillat@debian.org> Fri, 18 Jul 2008 08:51:45 +0200
+
+argyll (0.60-0.1) unstable; urgency=low
+
+ * Need to Build-depends on libxinerama-dev instead of x11proto-xinerama-dev.
+
+ -- Christian Marillat <marillat@debian.org> Fri, 21 Jul 2006 06:25:46 +0200
+
+argyll (0.60-0.0) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Christian Marillat <marillat@debian.org> Thu, 20 Jul 2006 10:56:43 +0200
+
+argyll (0.53.1-0.2) unstable; urgency=low
+
+ * Apply a patch from Guido to fix build under ppc.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 23 May 2006 14:40:45 +0200
+
+argyll (0.53.1-0.1) unstable; urgency=low
+
+ * Add libxxf86vm-dev and x11proto-xf86vidmode-dev in build-Depends.
+
+ -- Christian Marillat <marillat@debian.org> Fri, 12 May 2006 16:27:46 +0200
+
+argyll (0.53.1-0.0) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Christian Marillat <marillat@debian.org> Thu, 9 Feb 2006 13:56:03 +0100
+
+argyll (0.53-0.1) unstable; urgency=low
+
+ * Rename icclink in icclink-argyll.
+ * Rename sprof in sprof-argyll.
+
+ -- Christian Marillat <marillat@debian.org> Wed, 8 Feb 2006 11:42:15 +0100
+
+argyll (0.53-0.0) unstable; urgency=low
+
+ * Initial release.
+
+ -- Christian Marillat <marillat@debian.org> Sun, 5 Feb 2006 22:08:11 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..bc97099
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,91 @@
+Source: argyll
+Section: graphics
+Priority: optional
+Maintainer: Jörg Frings-Fürst <debian@jff-webhosting.net>
+Standards-Version: 3.9.6
+Build-Depends:
+ debhelper (>= 9),
+ dh-autoreconf,
+ dpkg-dev (>= 1.17.0),
+ jam,
+ libjpeg-dev,
+ libssl-dev,
+ libpng12-dev,
+ libtiff5-dev,
+ libtool,
+ libusb-dev,
+ libx11-dev,
+ libxinerama-dev,
+ libxrandr-dev,
+ libxss-dev,
+ libxxf86vm-dev,
+ x11proto-scrnsaver-dev,
+ x11proto-xf86vidmode-dev,
+ zlib1g-dev
+Homepage: http://www.argyllcms.com/
+Vcs-Git: git://anonscm.debian.org/collab-maint/argyll.git
+Vcs-Browser: http://anonscm.debian.org/cgit/collab-maint/argyll.git
+
+Package: argyll
+Architecture: linux-any
+Depends: ${misc:Depends}, ${shlibs:Depends}, argyll-ref
+Pre-Depends:
+ dpkg (>= 1.17.5)
+Recommends: libpam-systemd [linux-any], udev (>= 196) [linux-any]
+Suggests: argyll-doc, colord, gir1.2-colordgtk-1.0
+Description: Color Management System, calibrator and profiler
+ Argyll is an experimental, open source, ICC compatible color management
+ system. It supports accurate ICC profile creation for scanners, CMYK
+ printers, film recorders and calibration and profiling of displays.
+ Spectral sample data is supported, allowing a selection of illuminants
+ observer types, and paper fluorescent whitener additive compensation.
+ Profiles can also incorporate source specific gamut mappings for perceptual
+ and saturation intents. Gamut mapping and profile linking uses the CIECAM02
+ appearance model, a unique gamut mapping algorithm, and a wide selection of
+ rendering intents. It also includes code for the fastest portable 8 bit
+ raster color conversion engine available anywhere, as well as support for
+ fast, fully accurate 16 bit conversion. Device color gamuts can also be
+ viewed and compared using a VRML viewer.
+
+Package: argyll-dbg
+Section: debug
+Priority: extra
+Architecture: linux-any
+Depends: argyll (= ${binary:Version}), ${misc:Depends}
+Pre-Depends:
+ dpkg (>= 1.17.5)
+Description: debugging symbols for argyll
+ Argyll is an experimental, open source, ICC compatible color management
+ system. It supports accurate ICC profile creation for scanners, CMYK
+ printers, film recorders and calibration and profiling of displays.
+ .
+ This package contains the debugging symbols for argyll, libicc and libimdi
+ libraries
+
+Package: argyll-ref
+Architecture: all
+Depends: ${misc:Depends}
+Pre-Depends:
+ dpkg (>= 1.17.5)
+Replaces: argyll (<< 1.6.3-1)
+Breaks: argyll (<< 1.6.3-1)
+Description: Color Management System, calibrator and profiler (data files)
+ Argyll is an experimental, open source, ICC compatible color management
+ system. It supports accurate ICC profile creation for scanners, CMYK
+ printers, film recorders and calibration and profiling of displays.
+ .
+ This package contains the data files for argyll.
+
+Package: argyll-doc
+Architecture: all
+Section: doc
+Priority: extra
+Depends: ${misc:Depends}
+Pre-Depends:
+ dpkg (>= 1.17.5)
+Description: Color Management System, calibrator and profiler (documentation)
+ Argyll is an experimental, open source, ICC compatible color management
+ system. It supports accurate ICC profile creation for scanners, CMYK
+ printers, film recorders and calibration and profiling of displays.
+ .
+ This package contains the documentation for argyll.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..ae16fbc
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,965 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: ArgyllCMS
+Upstream-Contact: Graeme W. Gill <Graeme@argyllcms.com>
+Source: http://www.argyllcms.com/
+
+Files: *
+Copyright: 1995-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: AGPL-3
+
+Files: icc/*
+ cgats/*
+ jcnf/*
+ ucmm/*
+Copyright: 1995-2014 Graeme W. Gill <Graeme@argyllcms.com>
+License: Expat
+
+Files: ccast/cast_channel.proto
+Copyright: 2013 The Chromium Authors
+License: BSD-3
+
+Files: ccast/chan/protobuf-c.*
+Copyright: 2008-2014 Dave Benson and the protobuf-c authors
+License: BSD-2
+
+Files: ccast/axTLS/*.c
+ ccast/axTLS/*.h
+Copyright: 2007 Cameron Rich
+License: BSD-3
+
+Files: ccast/axTLS/os_int.h
+Copyright: 2014 Graeme W. Gill
+License: Expat
+
+Files: icc/iccV42.h
+Copyright: 1994-1998 SunSoft, Inc
+ 1994-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: Expat
+
+Files: plot/x3dom.*
+Copyright: 2009 Fraunhofer IGD, Darmstadt, Germany
+License: MIT and GPL-3+
+
+Files: yajl/*
+Copyright: 2007-2014 Lloyd Hilaiel
+License: BSD-3
+
+Files: yajl/yajl_tree.*
+Copyright: 2010-2011 Florian Forster <ff@octo.it>
+License: BSD-3
+
+Files: usb/*
+Copyright: 2012-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: Expat
+
+Files: usb/driver/*
+Copyright: 2002-2005 Stephan Meyer <ste_meyer@web.de>
+License: GPL-2 or LGPL-2
+ The library (DLL) is distributed under the terms of the GNU Lesser
+ General Public License (LGPL).
+ .
+ All other components (drivers, services, installer) are distributed
+ under the terms of the GNU General Public License (GPL).
+
+Files: usb/driver/ioctl.c
+Copyright: 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ 2010 Travis Robinson <libusbdotnet@gmail.com>
+License: GPL-2+
+
+Files: usb/driver/transfer.c
+Copyright: 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ 2010 Travis Robinson <libusbdotnet@gmail.com>
+License: GPL-3+
+
+Files: xicc/iccjpeg.*
+Copyright: 1998-2010 Marti Maria Saguer
+License: Expat
+
+Files: spectro/*
+Copyright: 1996-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: GPL-2+
+
+Files: spectro/dispcal.c
+ spectro/dispsup.c
+ spectro/dispsup.h
+ spectro/dispwin.c
+ spectro/dispwin.h
+ spectro/average.c
+ spectro/synthcal.c
+ spectro/synthread.c
+ spectro/ccxxmake.c
+ spectro/fakeread.c
+ spectro/License.txt
+ spectro/chartread.c
+ spectro/dispread.c
+ spectro/illumread.c
+Copyright: 1996-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: AGPL-3
+
+Files: spectro/colorhug.*
+Copyright: 2006-2015 Graeme W. Gill <Graeme@argyllcms.com>
+ 2011 Richard Hughes
+License: GPL-2+
+
+Files: spectro/mongoose.*
+Copyright: 2004-2012 Sergey Lyubka
+License: Expat
+
+Files: spectro/spec2cie.c
+Copyright: 2005 Gerhard Fuernkranz
+ 2006-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: GPL-2+
+
+Files: h/sort.h
+Copyright: 1996-2010 Graeme W. Gill <Graeme@argyllcms.com>
+License: GPL-2+
+
+Files: xicc/xspect.c
+Copyright: 2000-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: GPL-2+
+
+Files: doc/*
+Copyright: 1995-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: GFDL-1.3+
+
+Files: numlib/numsup.*
+Copyright: 1997-2015 Graeme W. Gill <Graeme@argyllcms.com>
+License: GPL-2+
+
+Files: rspl/rspl1.*
+Copyright: 1996-2010 Graeme W. Gill <Graeme@argyllcms.com>
+License: GPL-2+
+
+Files: xml/*
+Copyright: 2003-2011 Michael R Sweet
+License: LGPL-2+
+
+Files: xml/install-sh
+Copyright: 1991 Massachusetts Institute of Technology
+License: MIT
+
+Files: ref/*.icm
+ icc/*.icm
+Copyright: Public domain
+License: public-domain
+ Public Domain. No Warranty, Use at own risk
+
+Files: debian/*
+Copyright: 2006-2008 Christian Marillat <marillat@debian.org>
+ 2008-2010 Roland Mas <lolando@debian.org>
+ 2014-2015 Jörg Frings-Fürst <debian@jff-webhosting.net>
+License: GPL-3+
+
+License: AGPL-3
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+ .
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+ .
+ Preamble
+ .
+ The GNU Affero General Public License is a free, copyleft license for
+ software and other kinds of works, specifically designed to ensure
+ cooperation with the community in the case of network server software.
+ .
+ The licenses for most software and other practical works are designed
+ to take away your freedom to share and change the works. By contrast,
+ our General Public Licenses are intended to guarantee your freedom to
+ share and change all versions of a program--to make sure it remains free
+ software for all its users.
+ .
+ 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
+ them 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.
+ .
+ Developers that use our General Public Licenses protect your rights
+ with two steps: (1) assert copyright on the software, and (2) offer
+ you this License which gives you legal permission to copy, distribute
+ and/or modify the software.
+ .
+ A secondary benefit of defending all users' freedom is that
+ improvements made in alternate versions of the program, if they
+ receive widespread use, become available for other developers to
+ incorporate. Many developers of free software are heartened and
+ encouraged by the resulting cooperation. However, in the case of
+ software used on network servers, this result may fail to come about.
+ The GNU General Public License permits making a modified version and
+ letting the public access it on a server without ever releasing its
+ source code to the public.
+ .
+ The GNU Affero General Public License is designed specifically to
+ ensure that, in such cases, the modified source code becomes available
+ to the community. It requires the operator of a network server to
+ provide the source code of the modified version running there to the
+ users of that server. Therefore, public use of a modified version, on
+ a publicly accessible server, gives the public access to the source
+ code of the modified version.
+ .
+ An older license, called the Affero General Public License and
+ published by Affero, was designed to accomplish similar goals. This is
+ a different license, not a version of the Affero GPL, but Affero has
+ released a new version of the Affero GPL which permits relicensing under
+ this license.
+ .
+ The precise terms and conditions for copying, distribution and
+ modification follow.
+ .
+ TERMS AND CONDITIONS
+ .
+ 0. Definitions.
+ .
+ "This License" refers to version 3 of the GNU Affero General Public License.
+ .
+ "Copyright" also means copyright-like laws that apply to other kinds of
+ works, such as semiconductor masks.
+ .
+ "The Program" refers to any copyrightable work licensed under this
+ License. Each licensee is addressed as "you". "Licensees" and
+ "recipients" may be individuals or organizations.
+ .
+ To "modify" a work means to copy from or adapt all or part of the work
+ in a fashion requiring copyright permission, other than the making of an
+ exact copy. The resulting work is called a "modified version" of the
+ earlier work or a work "based on" the earlier work.
+ .
+ A "covered work" means either the unmodified Program or a work based
+ on the Program.
+ .
+ To "propagate" a work means to do anything with it that, without
+ permission, would make you directly or secondarily liable for
+ infringement under applicable copyright law, except executing it on a
+ computer or modifying a private copy. Propagation includes copying,
+ distribution (with or without modification), making available to the
+ public, and in some countries other activities as well.
+ .
+ To "convey" a work means any kind of propagation that enables other
+ parties to make or receive copies. Mere interaction with a user through
+ a computer network, with no transfer of a copy, is not conveying.
+ .
+ An interactive user interface displays "Appropriate Legal Notices"
+ to the extent that it includes a convenient and prominently visible
+ feature that (1) displays an appropriate copyright notice, and (2)
+ tells the user that there is no warranty for the work (except to the
+ extent that warranties are provided), that licensees may convey the
+ work under this License, and how to view a copy of this License. If
+ the interface presents a list of user commands or options, such as a
+ menu, a prominent item in the list meets this criterion.
+ .
+ 1. Source Code.
+ .
+ The "source code" for a work means the preferred form of the work
+ for making modifications to it. "Object code" means any non-source
+ form of a work.
+ .
+ A "Standard Interface" means an interface that either is an official
+ standard defined by a recognized standards body, or, in the case of
+ interfaces specified for a particular programming language, one that
+ is widely used among developers working in that language.
+ .
+ The "System Libraries" of an executable work include anything, other
+ than the work as a whole, that (a) is included in the normal form of
+ packaging a Major Component, but which is not part of that Major
+ Component, and (b) serves only to enable use of the work with that
+ Major Component, or to implement a Standard Interface for which an
+ implementation is available to the public in source code form. A
+ "Major Component", in this context, means a major essential component
+ (kernel, window system, and so on) of the specific operating system
+ (if any) on which the executable work runs, or a compiler used to
+ produce the work, or an object code interpreter used to run it.
+ .
+ The "Corresponding Source" for a work in object code form means all
+ the source code needed to generate, install, and (for an executable
+ work) run the object code and to modify the work, including scripts to
+ control those activities. However, it does not include the work's
+ System Libraries, or general-purpose tools or generally available free
+ programs which are used unmodified in performing those activities but
+ which are not part of the work. For example, Corresponding Source
+ includes interface definition files associated with source files for
+ the work, and the source code for shared libraries and dynamically
+ linked subprograms that the work is specifically designed to require,
+ such as by intimate data communication or control flow between those
+ subprograms and other parts of the work.
+ .
+ The Corresponding Source need not include anything that users
+ can regenerate automatically from other parts of the Corresponding
+ Source.
+ .
+ The Corresponding Source for a work in source code form is that
+ same work.
+ .
+ 2. Basic Permissions.
+ .
+ All rights granted under this License are granted for the term of
+ copyright on the Program, and are irrevocable provided the stated
+ conditions are met. This License explicitly affirms your unlimited
+ permission to run the unmodified Program. The output from running a
+ covered work is covered by this License only if the output, given its
+ content, constitutes a covered work. This License acknowledges your
+ rights of fair use or other equivalent, as provided by copyright law.
+ .
+ You may make, run and propagate covered works that you do not
+ convey, without conditions so long as your license otherwise remains
+ in force. You may convey covered works to others for the sole purpose
+ of having them make modifications exclusively for you, or provide you
+ with facilities for running those works, provided that you comply with
+ the terms of this License in conveying all material for which you do
+ not control copyright. Those thus making or running the covered works
+ for you must do so exclusively on your behalf, under your direction
+ and control, on terms that prohibit them from making any copies of
+ your copyrighted material outside their relationship with you.
+ .
+ Conveying under any other circumstances is permitted solely under
+ the conditions stated below. Sublicensing is not allowed; section 10
+ makes it unnecessary.
+ .
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+ .
+ No covered work shall be deemed part of an effective technological
+ measure under any applicable law fulfilling obligations under article
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
+ similar laws prohibiting or restricting circumvention of such
+ measures.
+ .
+ When you convey a covered work, you waive any legal power to forbid
+ circumvention of technological measures to the extent such circumvention
+ is effected by exercising rights under this License with respect to
+ the covered work, and you disclaim any intention to limit operation or
+ modification of the work as a means of enforcing, against the work's
+ users, your or third parties' legal rights to forbid circumvention of
+ technological measures.
+ .
+ 4. Conveying Verbatim Copies.
+ .
+ You may convey 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;
+ keep intact all notices stating that this License and any
+ non-permissive terms added in accord with section 7 apply to the code;
+ keep intact all notices of the absence of any warranty; and give all
+ recipients a copy of this License along with the Program.
+ .
+ You may charge any price or no price for each copy that you convey,
+ and you may offer support or warranty protection for a fee.
+ .
+ 5. Conveying Modified Source Versions.
+ .
+ You may convey a work based on the Program, or the modifications to
+ produce it from the Program, in the form of source code under the
+ terms of section 4, provided that you also meet all of these conditions:
+ .
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+ .
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+ .
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+ .
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+ .
+ A compilation of a covered work with other separate and independent
+ works, which are not by their nature extensions of the covered work,
+ and which are not combined with it such as to form a larger program,
+ in or on a volume of a storage or distribution medium, is called an
+ "aggregate" if the compilation and its resulting copyright are not
+ used to limit the access or legal rights of the compilation's users
+ beyond what the individual works permit. Inclusion of a covered work
+ in an aggregate does not cause this License to apply to the other
+ parts of the aggregate.
+ .
+ 6. Conveying Non-Source Forms.
+ .
+ You may convey a covered work in object code form under the terms
+ of sections 4 and 5, provided that you also convey the
+ machine-readable Corresponding Source under the terms of this License,
+ in one of these ways:
+ .
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+ .
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+ .
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+ .
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+ .
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+ .
+ A separable portion of the object code, whose source code is excluded
+ from the Corresponding Source as a System Library, need not be
+ included in conveying the object code work.
+ .
+ A "User Product" is either (1) a "consumer product", which means any
+ tangible personal property which is normally used for personal, family,
+ or household purposes, or (2) anything designed or sold for incorporation
+ into a dwelling. In determining whether a product is a consumer product,
+ doubtful cases shall be resolved in favor of coverage. For a particular
+ product received by a particular user, "normally used" refers to a
+ typical or common use of that class of product, regardless of the status
+ of the particular user or of the way in which the particular user
+ actually uses, or expects or is expected to use, the product. A product
+ is a consumer product regardless of whether the product has substantial
+ commercial, industrial or non-consumer uses, unless such uses represent
+ the only significant mode of use of the product.
+ .
+ "Installation Information" for a User Product means any methods,
+ procedures, authorization keys, or other information required to install
+ and execute modified versions of a covered work in that User Product from
+ a modified version of its Corresponding Source. The information must
+ suffice to ensure that the continued functioning of the modified object
+ code is in no case prevented or interfered with solely because
+ modification has been made.
+ .
+ If you convey an object code work under this section in, or with, or
+ specifically for use in, a User Product, and the conveying occurs as
+ part of a transaction in which the right of possession and use of the
+ User Product is transferred to the recipient in perpetuity or for a
+ fixed term (regardless of how the transaction is characterized), the
+ Corresponding Source conveyed under this section must be accompanied
+ by the Installation Information. But this requirement does not apply
+ if neither you nor any third party retains the ability to install
+ modified object code on the User Product (for example, the work has
+ been installed in ROM).
+ .
+ The requirement to provide Installation Information does not include a
+ requirement to continue to provide support service, warranty, or updates
+ for a work that has been modified or installed by the recipient, or for
+ the User Product in which it has been modified or installed. Access to a
+ network may be denied when the modification itself materially and
+ adversely affects the operation of the network or violates the rules and
+ protocols for communication across the network.
+ .
+ Corresponding Source conveyed, and Installation Information provided,
+ in accord with this section must be in a format that is publicly
+ documented (and with an implementation available to the public in
+ source code form), and must require no special password or key for
+ unpacking, reading or copying.
+ .
+ 7. Additional Terms.
+ .
+ "Additional permissions" are terms that supplement the terms of this
+ License by making exceptions from one or more of its conditions.
+ Additional permissions that are applicable to the entire Program shall
+ be treated as though they were included in this License, to the extent
+ that they are valid under applicable law. If additional permissions
+ apply only to part of the Program, that part may be used separately
+ under those permissions, but the entire Program remains governed by
+ this License without regard to the additional permissions.
+ .
+ When you convey a copy of a covered work, you may at your option
+ remove any additional permissions from that copy, or from any part of
+ it. (Additional permissions may be written to require their own
+ removal in certain cases when you modify the work.) You may place
+ additional permissions on material, added by you to a covered work,
+ for which you have or can give appropriate copyright permission.
+ .
+ Notwithstanding any other provision of this License, for material you
+ add to a covered work, you may (if authorized by the copyright holders of
+ that material) supplement the terms of this License with terms:
+ .
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+ .
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+ .
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+ .
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+ .
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+ .
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+ .
+ All other non-permissive additional terms are considered "further
+ restrictions" within the meaning of section 10. If the Program as you
+ received it, or any part of it, contains a notice stating that it is
+ governed by this License along with a term that is a further
+ restriction, you may remove that term. If a license document contains
+ a further restriction but permits relicensing or conveying under this
+ License, you may add to a covered work material governed by the terms
+ of that license document, provided that the further restriction does
+ not survive such relicensing or conveying.
+ .
+ If you add terms to a covered work in accord with this section, you
+ must place, in the relevant source files, a statement of the
+ additional terms that apply to those files, or a notice indicating
+ where to find the applicable terms.
+ .
+ Additional terms, permissive or non-permissive, may be stated in the
+ form of a separately written license, or stated as exceptions;
+ the above requirements apply either way.
+ .
+ 8. Termination.
+ .
+ You may not propagate or modify a covered work except as expressly
+ provided under this License. Any attempt otherwise to propagate or
+ modify it is void, and will automatically terminate your rights under
+ this License (including any patent licenses granted under the third
+ paragraph of section 11).
+ .
+ However, if you cease all violation of this License, then your
+ license from a particular copyright holder is reinstated (a)
+ provisionally, unless and until the copyright holder explicitly and
+ finally terminates your license, and (b) permanently, if the copyright
+ holder fails to notify you of the violation by some reasonable means
+ prior to 60 days after the cessation.
+ .
+ Moreover, your license from a particular copyright holder is
+ reinstated permanently if the copyright holder notifies you of the
+ violation by some reasonable means, this is the first time you have
+ received notice of violation of this License (for any work) from that
+ copyright holder, and you cure the violation prior to 30 days after
+ your receipt of the notice.
+ .
+ Termination of your rights under this section does not terminate the
+ licenses of parties who have received copies or rights from you under
+ this License. If your rights have been terminated and not permanently
+ reinstated, you do not qualify to receive new licenses for the same
+ material under section 10.
+ .
+ 9. Acceptance Not Required for Having Copies.
+ .
+ You are not required to accept this License in order to receive or
+ run a copy of the Program. Ancillary propagation of a covered work
+ occurring solely as a consequence of using peer-to-peer transmission
+ to receive a copy likewise does not require acceptance. However,
+ nothing other than this License grants you permission to propagate or
+ modify any covered work. These actions infringe copyright if you do
+ not accept this License. Therefore, by modifying or propagating a
+ covered work, you indicate your acceptance of this License to do so.
+ .
+ 10. Automatic Licensing of Downstream Recipients.
+ .
+ Each time you convey a covered work, the recipient automatically
+ receives a license from the original licensors, to run, modify and
+ propagate that work, subject to this License. You are not responsible
+ for enforcing compliance by third parties with this License.
+ .
+ An "entity transaction" is a transaction transferring control of an
+ organization, or substantially all assets of one, or subdividing an
+ organization, or merging organizations. If propagation of a covered
+ work results from an entity transaction, each party to that
+ transaction who receives a copy of the work also receives whatever
+ licenses to the work the party's predecessor in interest had or could
+ give under the previous paragraph, plus a right to possession of the
+ Corresponding Source of the work from the predecessor in interest, if
+ the predecessor has it or can get it with reasonable efforts.
+ .
+ You may not impose any further restrictions on the exercise of the
+ rights granted or affirmed under this License. For example, you may
+ not impose a license fee, royalty, or other charge for exercise of
+ rights granted under this License, and you may not initiate litigation
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ any patent claim is infringed by making, using, selling, offering for
+ sale, or importing the Program or any portion of it.
+ .
+ 11. Patents.
+ .
+ A "contributor" is a copyright holder who authorizes use under this
+ License of the Program or a work on which the Program is based. The
+ work thus licensed is called the contributor's "contributor version".
+ .
+ A contributor's "essential patent claims" are all patent claims
+ owned or controlled by the contributor, whether already acquired or
+ hereafter acquired, that would be infringed by some manner, permitted
+ by this License, of making, using, or selling its contributor version,
+ but do not include claims that would be infringed only as a
+ consequence of further modification of the contributor version. For
+ purposes of this definition, "control" includes the right to grant
+ patent sublicenses in a manner consistent with the requirements of
+ this License.
+ .
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+ patent license under the contributor's essential patent claims, to
+ make, use, sell, offer for sale, import and otherwise run, modify and
+ propagate the contents of its contributor version.
+ .
+ In the following three paragraphs, a "patent license" is any express
+ agreement or commitment, however denominated, not to enforce a patent
+ (such as an express permission to practice a patent or covenant not to
+ sue for patent infringement). To "grant" such a patent license to a
+ party means to make such an agreement or commitment not to enforce a
+ patent against the party.
+ .
+ If you convey a covered work, knowingly relying on a patent license,
+ and the Corresponding Source of the work is not available for anyone
+ to copy, free of charge and under the terms of this License, through a
+ publicly available network server or other readily accessible means,
+ then you must either (1) cause the Corresponding Source to be so
+ available, or (2) arrange to deprive yourself of the benefit of the
+ patent license for this particular work, or (3) arrange, in a manner
+ consistent with the requirements of this License, to extend the patent
+ license to downstream recipients. "Knowingly relying" means you have
+ actual knowledge that, but for the patent license, your conveying the
+ covered work in a country, or your recipient's use of the covered work
+ in a country, would infringe one or more identifiable patents in that
+ country that you have reason to believe are valid.
+ .
+ If, pursuant to or in connection with a single transaction or
+ arrangement, you convey, or propagate by procuring conveyance of, a
+ covered work, and grant a patent license to some of the parties
+ receiving the covered work authorizing them to use, propagate, modify
+ or convey a specific copy of the covered work, then the patent license
+ you grant is automatically extended to all recipients of the covered
+ work and works based on it.
+ .
+ A patent license is "discriminatory" if it does not include within
+ the scope of its coverage, prohibits the exercise of, or is
+ conditioned on the non-exercise of one or more of the rights that are
+ specifically granted under this License. You may not convey a covered
+ work if you are a party to an arrangement with a third party that is
+ in the business of distributing software, under which you make payment
+ to the third party based on the extent of your activity of conveying
+ the work, and under which the third party grants, to any of the
+ parties who would receive the covered work from you, a discriminatory
+ patent license (a) in connection with copies of the covered work
+ conveyed by you (or copies made from those copies), or (b) primarily
+ for and in connection with specific products or compilations that
+ contain the covered work, unless you entered into that arrangement,
+ or that patent license was granted, prior to 28 March 2007.
+ .
+ Nothing in this License shall be construed as excluding or limiting
+ any implied license or other defenses to infringement that may
+ otherwise be available to you under applicable patent law.
+ .
+ 12. No Surrender of Others' Freedom.
+ .
+ If 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 convey a
+ covered work so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you may
+ not convey it at all. For example, if you agree to terms that obligate you
+ to collect a royalty for further conveying from those to whom you convey
+ the Program, the only way you could satisfy both those terms and this
+ License would be to refrain entirely from conveying the Program.
+ .
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+ .
+ Notwithstanding any other provision of this License, if you modify the
+ Program, your modified version must prominently offer all users
+ interacting with it remotely through a computer network (if your version
+ supports such interaction) an opportunity to receive the Corresponding
+ Source of your version by providing access to the Corresponding Source
+ from a network server at no charge, through some standard or customary
+ means of facilitating copying of software. This Corresponding Source
+ shall include the Corresponding Source for any work covered by version 3
+ of the GNU General Public License that is incorporated pursuant to the
+ following paragraph.
+ .
+ Notwithstanding any other provision of this License, you have
+ permission to link or combine any covered work with a work licensed
+ under version 3 of the GNU General Public License into a single
+ combined work, and to convey the resulting work. The terms of this
+ License will continue to apply to the part which is the covered work,
+ but the work with which it is combined will remain governed by version
+ 3 of the GNU General Public License.
+ .
+ 14. Revised Versions of this License.
+ .
+ The Free Software Foundation may publish revised and/or new versions of
+ the GNU Affero 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 that a certain numbered version of the GNU Affero General
+ Public License "or any later version" applies to it, you have the
+ option of following the terms and conditions either of that numbered
+ version or of any later version published by the Free Software
+ Foundation. If the Program does not specify a version number of the
+ GNU Affero General Public License, you may choose any version ever published
+ by the Free Software Foundation.
+ .
+ If the Program specifies that a proxy can decide which future
+ versions of the GNU Affero General Public License can be used, that proxy's
+ public statement of acceptance of a version permanently authorizes you
+ to choose that version for the Program.
+ .
+ Later license versions may give you additional or different
+ permissions. However, no additional obligations are imposed on any
+ author or copyright holder as a result of your choosing to follow a
+ later version.
+ .
+ 15. Disclaimer of Warranty.
+ .
+ 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.
+ .
+ 16. Limitation of Liability.
+ .
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+ 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.
+ .
+ 17. Interpretation of Sections 15 and 16.
+ .
+ If the disclaimer of warranty and limitation of liability provided
+ above cannot be given local legal effect according to their terms,
+ reviewing courts shall apply local law that most closely approximates
+ an absolute waiver of all civil liability in connection with the
+ Program, unless a warranty or assumption of liability accompanies a
+ copy of the Program in return for a fee.
+ .
+ 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
+ state 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 Affero General Public License as published by
+ the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+ .
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ .
+ Also add information on how to contact you by electronic and paper mail.
+ .
+ If your software can interact with users remotely through a computer
+ network, you should also make sure that it provides a way for users to
+ get its source. For example, if your program is a web application, its
+ interface could display a "Source" link that leads users to an archive
+ of the code. There are many ways you could offer source, and different
+ solutions will be better for different programs; see section 13 for the
+ specific requirements.
+ .
+ You should also get your employer (if you work as a programmer) or school,
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
+ For more information on this, and how to apply and follow the GNU AGPL, see
+ <http://www.gnu.org/licenses/>.
+
+License: BSD-2
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ .
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ .
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: BSD-3
+ All rights reserved.
+ .
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ .
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ .
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ .
+ 3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+License: Expat
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+License: GFDL-1.3+
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.3
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ .
+ On Debian systems, the complete text of the GNU Free Documentation License
+ version 1.3 can be found in "/usr/share/common-licenses/GFDL-1.3".
+
+License: GPL-2+
+ 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, see <http://www.gnu.org/licenses/>.
+ .
+ The complete text of the GNU General Public License
+ can be found in /usr/share/common-licenses/GPL-2 file.
+
+License: GPL-3+
+ This package 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 3 of the License, or
+ (at your option) any later version.
+ .
+ This package 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, see <http://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
+
+License: LGPL-2+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+ .
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+ .
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU Library General Public License
+ version 2 can be found in "/usr/share/common-licenses/LGPL-2".
+
+License: MIT
+ All rights reserved. No part of this source code may be reproduced,
+ stored in a retrieval system, or transmitted, in any form or by any
+ means, electronic, mechanical, photocopying, recording or otherwise,
+ except as stated in the end-user licence agreement, without the prior
+ permission of the copyright owners.
+ .
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of OSF, UI or X/Open not be used in
+ advertising or publicity pertaining to distribution of the software
+ without specific, written prior permission. OSF, UI and X/Open make
+ no representations about the suitability of this software for any purpose.
+ It is provided "as is" without express or implied warranty.
+ .
+ OSF, UI and X/Open DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ EVENT SHALL OSF, UI or X/Open BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ PERFORMANCE OF THIS SOFTWARE.
diff --git a/debian/icc-utils.postinst b/debian/icc-utils.postinst
new file mode 100644
index 0000000..42dfee1
--- /dev/null
+++ b/debian/icc-utils.postinst
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <postinst> `abort-remove'
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+# source debconf library
+#. /usr/share/debconf/confmodule
+
+
+case "$1" in
+
+ configure|abort-upgrade|abort-remove|abort-deconfigure)
+ # Replace documentation directory symlink
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/icc-utils /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+
+esac
+
+#DEBHELPER#
+
+
+exit 0
diff --git a/debian/icc-utils.postrm b/debian/icc-utils.postrm
new file mode 100644
index 0000000..eb12775
--- /dev/null
+++ b/debian/icc-utils.postrm
@@ -0,0 +1,33 @@
+#! /bin/sh
+# postrm script for icc-utils
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
+# for details, see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/icc-utils /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 0
+
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
diff --git a/debian/icc-utils.preinst b/debian/icc-utils.preinst
new file mode 100644
index 0000000..98e4723
--- /dev/null
+++ b/debian/icc-utils.preinst
@@ -0,0 +1,32 @@
+#!/bin/sh
+# preinst script for icc-utils
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <new-preinst> `install'
+# * <new-preinst> `install' <old-version>
+# * <new-preinst> `upgrade' <old-version>
+# * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+ install|upgrade|abort-upgrade)
+ dpkg-maintscript-helper symlink_to_dir /usr/share/doc/icc-utils /usr/share/doc/argyll-doc 1.6.3-2~ -- "$@"
+ ;;
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/man/applycal.1 b/debian/man/applycal.1
new file mode 100644
index 0000000..eb2f902
--- /dev/null
+++ b/debian/man/applycal.1
@@ -0,0 +1,30 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH APPLY "1" "September 2014" "applycal" "User Commands"
+.SH NAME
+Apply \- Apply device calibration to an ICC profile.
+.SH DESCRIPTION
+Apply device calibration to an ICC profile
+.SH SYNOPSIS
+.B applycal
+.RB [\-options] [calfile.cal] inprof.icc [outprof.icc]
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-a\fR
+Apply or re\-apply calibration (default)
+.TP
+\fB\-u\fR
+Remove calibration
+.TP
+\fB\-c\fR
+Check calibration
+.TP
+calfile.cal
+Calibration file to apply
+.TP
+inprof.icc
+ICC profile to read
+.TP
+outprof.icc
+modified ICC profile to write \ No newline at end of file
diff --git a/debian/man/average.1 b/debian/man/average.1
new file mode 100644
index 0000000..ae80f1f
--- /dev/null
+++ b/debian/man/average.1
@@ -0,0 +1,29 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH AVERAGE "1" "September 2014" "average" "User Commands"
+.SH NAME
+Average \- Average or merge values in .ti3 like files.
+.SH DESCRIPTION
+Average or merge values in .ti3 like files
+.IP
+Diagnostic: Too few arguments (1, minimum is 2)
+.SH SYNOPSIS
+.B average
+.RB [\-options]\ \input1.ti3\ \input2.ti3 ... output.ti3
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-m\fR
+Merge rather than average
+.TP
+input1.ti3
+First input file
+.TP
+input2.ti3
+Second input file
+.TP
+\&...
+etc.
+.TP
+output.ti3
+Resulting averaged or merged output file
diff --git a/debian/man/cb2ti3.1 b/debian/man/cb2ti3.1
new file mode 100644
index 0000000..ddf3a9d
--- /dev/null
+++ b/debian/man/cb2ti3.1
@@ -0,0 +1,21 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CONVERT "1" "September 2014" "cb2ti3" "User Commands"
+.SH NAME
+Convert \- Convert Colorblind raw device profile data to Argyll data.
+.SH DESCRIPTION
+Convert Colorblind raw device profile data to Argyll data
+.SH SYNOPSIS
+.B cb2ti3
+.RB [\-v] [\-l limit] infile outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-l\fR limit
+Set inklimit in .ti3 file
+.TP
+infile
+Base name for input.CMY and input.nCIE file
+.TP
+outfile
+Base name for output.ti3 file \ No newline at end of file
diff --git a/debian/man/cctiff.1 b/debian/man/cctiff.1
new file mode 100644
index 0000000..cb23e31
--- /dev/null
+++ b/debian/man/cctiff.1
@@ -0,0 +1,73 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH COLOR "1" "September 2014" "cctiff" "User Commands"
+.SH NAME
+Color \- Color Correct a TIFF file using any sequence of ICC profiles or Calibrations.
+.SH DESCRIPTION
+Color Correct a TIFF or JPEG file using any sequence of ICC profiles or Calibrations
+.SH SYNOPSIS
+.B cctiff
+.RB [\-options]\ { [\-i intent]\ profile.icc\ |\ calbrtn.cal\ ...}\ infile.(tif|jpg)\ outfile.(tif|jpg)
+.TP
+\fB\-v\fR
+Verbose.
+.TP
+\fB\-c\fR
+Combine linearisation curves into one transform.
+.TP
+\fB\-p\fR
+Use slow precise correction.
+.TP
+\fB\-k\fR
+Check fast result against precise, and report.
+.TP
+\fB\-r\fR n
+Override the default CLUT resolution
+.TP
+\fB\-t\fR n
+Choose output encoding from 1..n
+.TP
+\fB\-f\fR [T|J]
+Set output format to Tiff or Jpeg (Default is same as input)
+.TP
+\fB\-q\fR quality
+Set JPEG quality 1..100 (Default 80)
+.TP
+\fB\-a\fR
+Read and Write planes > 4 as alpha planes
+.TP
+\fB\-I\fR
+Ignore any file or profile colorspace mismatches
+.TP
+\fB\-D\fR
+Don't append or set the output TIFF or JPEG description
+.TP
+\fB\-e\fR profile.[icc | tiff | jpg]
+Optionally embed a profile in the destination TIFF or JPEG file.
+.IP
+Then for each profile in sequence:
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute colorimetric
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+profile.[icc | tiff]
+Device, Link or Abstract profile
+.IP
+( May be embedded profile in TIFF/JPEG file)
+.IP
+or each calibration file in sequence:
+.TP
+\fB\-d\fR dir
+f = forward cal. (default), b = backwards cal.
+.TP
+calbrtn.cal
+Device calibration file.
+.TP
+infile.tif/jpg
+Input TIFF/JPEG file in appropriate color space
+.IP
+outfile.tif/jpg Output TIFF/JPEG file
diff --git a/debian/man/ccxxmake.1 b/debian/man/ccxxmake.1
new file mode 100644
index 0000000..337db92
--- /dev/null
+++ b/debian/man/ccxxmake.1
@@ -0,0 +1,91 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "ccmxmake" "User Commands"
+.SH NAME
+Create \- Create CCMX or CCSS.
+.SH DESCRIPTION
+Create CCMX or CCSS
+.SH SYNOPSIS
+.B ccmxmake
+.RB [\-options]\ output.ccmx
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-S\fR
+Create CCSS rather than CCMX
+.HP
+\fB\-f\fR file1.ti3[,file2.ti3] Create from one or two .ti3 files rather than measure.
+.TP
+\fB\-display\fR displayname
+Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 name = ':0.0'
+1 = 'Screen 1, Output DVI\-I\-1 at 0, 0, width 1920, height 1080'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for CCMX spectrometer data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-s\fR steps
+Override default patch sequence combination steps (default 1)
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+\fB\-E\fR desciption
+Override the default overall description
+.TP
+\fB\-I\fR displayname
+Set display make and model description
+.TP
+\fB\-T\fR displaytech
+Set display technology description (ie. CRT, LCD etc.)
+.TP
+\fB\-U\fR c
+Set UI selection character(s)
+.TP
+\fB\-Y\fR r|n
+Set or override refresh/non\-refresh display type
+.TP
+\fB\-Y\fR R:rate
+Override measured refresh rate with rate Hz
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.IP
+correction.ccmx | calibration.ccss
+.IP
+File to save result to
diff --git a/debian/man/chartread.1 b/debian/man/chartread.1
new file mode 100644
index 0000000..1d8285e
--- /dev/null
+++ b/debian/man/chartread.1
@@ -0,0 +1,96 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH READ "1" "September 2014" "chartread" "User Commands"
+.SH NAME
+Read \- Read Target Test Chart.
+.SH DESCRIPTION
+Read Target Test Chart
+.SH SYNOPSIS
+.B chartread
+.RB [\-options]\ outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-t\fR
+Use transmission measurement mode
+.TP
+\fB\-d\fR
+Use display measurement mode (white Y relative results)
+.TP
+\fB\-e\fR
+Emissive for transparency on a light box
+.TP
+\fB\-p\fR
+Measure patch by patch rather than strip
+.TP
+\fB\-x\fR [lx]
+Take external values, either L*a*b* (\fB\-xl\fR) or XYZ (\fB\-xx\fR).
+.TP
+\fB\-n\fR
+Don't save spectral information (default saves spectral)
+.TP
+\fB\-l\fR
+Save CIE as D50 L*a*b* rather than XYZ
+.TP
+\fB\-L\fR
+Save CIE as D50 L*a*b* as well as XYZ
+.TP
+\fB\-r\fR
+Resume reading partly read chart
+.TP
+\fB\-I\fR file.cal
+Override calibration info from .ti2 in resulting .ti3
+.TP
+\fB\-F\fR filter
+Set filter configuration (if aplicable):
+.TP
+n
+None
+.TP
+p
+Polarising filter
+.TP
+6
+D65
+.TP
+u
+U.V. Cut
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-B\fR
+Disable auto bi\-directional strip recognition
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for CCSS instrument:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-T\fR ratio
+Modify strip patch consistency tolerance by ratio
+.TP
+\fB\-S\fR
+Suppress wrong strip & unexpected value warnings
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+outfile
+Base name for input[ti2]/output[ti3] file
diff --git a/debian/man/collink.1 b/debian/man/collink.1
new file mode 100644
index 0000000..35d6c02
--- /dev/null
+++ b/debian/man/collink.1
@@ -0,0 +1,241 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH LINK "1" "September 2014" "collink" "User Commands"
+.SH NAME
+Link \- Link ICC profiles.
+.SH DESCRIPTION
+Link ICC profiles
+.SH SYNOPSIS
+.B collink
+.RB [options]\ srcprofile\ dstprofile\ linkedprofile
+.TP
+\fB\-v\fR Verbose
+.HP
+\fB\-A\fR manufacturer Manufacturer description string
+.TP
+\fB\-M\fR model
+Model description string
+.TP
+\fB\-D\fR description
+Profile Description string (Default "inoutfile")
+.TP
+\fB\-C\fR copyright
+Copyright string
+.TP
+\fB\-V\fR
+Verify existing profile, rather than link
+.TP
+\fB\-q\fR lmhu
+Quality \- Low, Medium (def), High, Ultra
+.TP
+\fB\-r\fR res
+Override clut res. set by \fB\-q\fR
+.TP
+\fB\-n\fR
+Don't preserve device linearization curves in result
+.TP
+\fB\-f\fR
+Special :\- Force neutral colors to be K only output
+.TP
+\fB\-fk\fR
+Special :\- Force K only neutral colors to be K only output
+.TP
+\fB\-F\fR
+Special :\- Force all colors to be K only output
+.TP
+\fB\-fcmy\fR
+Special :\- Force 100% C,M or Y only to stay pure
+.TP
+\fB\-p\fR absprof
+Include abstract profile in link
+.TP
+\fB\-a\fR file.cal
+Apply calibration curves to link output and append linear
+.TP
+\fB\-H\fR file.cal
+Append calibration curves to 3dlut
+.TP
+\fB\-s\fR
+Simple Mode (default)
+.TP
+\fB\-g\fR [src.gam]
+Gamut Mapping Mode [optional source image gamut]
+.TP
+\fB\-G\fR [src.gam]
+Gamut Mapping Mode using inverse outprofile A2B
+.IP
+Simple Mode Options:
+\fB\-i\fR in_intent p = perceptual, r = relative colorimetric,
+.IP
+s = saturation, a = absolute colorimetric
+.TP
+\fB\-o\fR out_intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute colorimetric
+.TP
+Gamut Mapping
+Mode Options:
+.TP
+\fB\-i\fR intent
+set linking intent from the following choice:
+.IP
+a \- Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]
+.IP
+aw \- Absolute Colorimetric (in Jab) with scaling to fit white point
+aa \- Absolute Appearance
+.IP
+r \- White Point Matched Appearance [ICC Relative Colorimetric]
+.IP
+la \- Luminance axis matched Appearance
+.IP
+p \- Perceptual (Preferred) (Default) [ICC Perceptual]
+.IP
+pa \- Perceptual Apperance
+ms \- Saturation
+.IP
+s \- Enhanced Saturation [ICC Saturation]
+.IP
+al \- Absolute Colorimetric (Lab)
+rl \- White Point Matched Colorimetric (Lab)
+.TP
+\fB\-w\fR [J,a,b]
+Use forced whitepoint hack [optional target point]
+.TP
+\fB\-c\fR viewcond
+set source viewing conditions for CIECAM02,
+either an enumerated choice, or a parameter
+.TP
+\fB\-d\fR viewcond
+set destination viewing conditions for CIECAM02,
+either an enumerated choice, or parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+tv \- Television/Film Studio
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:imagewhite
+Image white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 0)
+.TP
+g:glare
+Flare light % of ambient (default 1)
+.TP
+g:X:Y:Z
+Flare color as XYZ (default media white, Abs: D50)
+.TP
+g:x:y
+Flare color as x, y
+.TP
+\fB\-t\fR tlimit
+set source total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-T\fR klimit
+set source black ink limit, 0 \- 100% (estimate by default)
+.IP
+Inverse outprofile A2B Options:
+\fB\-k\fR tezhxr CMYK Black generation
+.IP
+t = transfer K from source to destination, e = retain K of destination B2A table
+z = zero K, h = 0.5 K, x = maximum K, r = ramp K (default)
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+p = black target generation curve parameters
+.HP
+\fB\-k\fR q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2
+.IP
+q = transfer source K to dual curve limits
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set destination total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set destination black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-3\fR flag
+Create "3DLut" output file as well as devlink
+.TP
+e
+eeColor .txt file
+.TP
+m
+MadVR .3dlut file
+.TP
+\fB\-I\fR b
+Apply BT.1886\-like mapping with effective gamma 2.2 to input
+.TP
+\fB\-I\fR b:g.g
+Apply BT.1886\-like mapping with effective gamma g.g to input
+.TP
+\fB\-I\fR B
+Apply BT.1886 mapping with technical gamma 2.4 to input
+.TP
+\fB\-I\fR B:g.g
+Apply BT.1886 mapping with technical gamma g.g to input
+.TP
+\fB\-e\fR flag
+Video encode input as:
+.TP
+\fB\-E\fR flag
+Video encode output as:
+.TP
+n
+normal 0..1 full range RGB levels (default)
+.TP
+t
+(16\-235)/255 "TV" RGB levels
+.TP
+6
+Rec601 YCbCr SD (16\-235,240)/255 "TV" levels
+.TP
+7
+Rec709 1125/60Hz YCbCr HD (16\-235,240)/255 "TV" levels
+.TP
+5
+Rec709 1250/50Hz YCbCr HD (16\-235,240)/255 "TV" levels
+.TP
+2
+Rec2020 YCbCr UHD (16\-235,240)/255 "TV" levels
+.TP
+C
+Rec2020 Constant Luminance YCbCr UHD (16\-235,240)/255 "TV" levels
+.TP
+x
+xvYCC Rec601 YCbCr Rec709 Prims. SD (16\-235,240)/255 "TV" levels
+.TP
+X
+xvYCC Rec709 YCbCr Rec709 Prims. HD (16\-235,240)/255 "TV" levels
+.TP
+\fB\-P\fR
+Create gamut gammap.wrl diagostic
diff --git a/debian/man/colprof.1 b/debian/man/colprof.1
new file mode 100644
index 0000000..cf8b9b1
--- /dev/null
+++ b/debian/man/colprof.1
@@ -0,0 +1,186 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "colprof" "User Commands"
+.SH NAME
+Create \- Create ICC profile.
+.SH DESCRIPTION
+Create ICC profile
+.SH SYNOPSIS
+.B colprof
+.RB [\-options]\ inoutfile
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-A\fR manufacturer Manufacturer description string
+.TP
+\fB\-M\fR model
+Model description string
+.TP
+\fB\-D\fR description
+Profile Description string (Default "inoutfile")
+.TP
+\fB\-C\fR copyright
+Copyright string
+.TP
+\fB\-Z\fR tmnb
+Attributes: Transparency, Matte, Negative, BlackAndWhite
+.TP
+\fB\-Z\fR prsa
+Default intent: Perceptual, Rel. Colorimetric, Saturation, Abs. Colorimetric
+.TP
+\fB\-q\fR lmhu
+Quality \- Low, Medium (def), High, Ultra
+.TP
+\fB\-b\fR [lmhun]
+Low quality B2A table \- or specific B2A quality or none for input device
+.TP
+\fB\-ni\fR
+Don't create input (Device) shaper curves
+.TP
+\fB\-np\fR
+Don't create input (Device) grid position curves
+.TP
+\fB\-no\fR
+Don't create output (PCS) shaper curves
+.TP
+\fB\-nc\fR
+Don't put the input .ti3 data in the profile
+.TP
+\fB\-k\fR zhxr
+Black value target: z = zero K,
+h = 0.5 K, x = max K, r = ramp K (def.)
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+override total ink limit, 0 \- 400% (default from .ti3)
+.TP
+\fB\-L\fR klimit
+override black ink limit, 0 \- 100% (default from .ti3)
+.TP
+\fB\-a\fR lxXgsmGS
+Algorithm type override
+l = Lab cLUT (def.), x = XYZ cLUT, X = display XYZ cLUT + matrix
+g = gamma+matrix, s = shaper+matrix, m = matrix only,
+G = single gamma+matrix, S = single shaper+matrix
+.TP
+\fB\-u\fR
+If input profile, auto scale WP to allow extrapolation
+.TP
+\fB\-uc\fR
+If input profile, clip cLUT values above WP
+.TP
+\fB\-U\fR scale
+If input profile, scale media white point by scale
+.TP
+\fB\-R\fR
+Restrict white <= 1.0, black and primaries to be +ve
+.TP
+\fB\-V\fR demphasis
+Degree of dark region cLUT grid emphasis 1.0\-4.0 (default 1.00 = none)
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-r\fR avgdev
+Average deviation of device+instrument readings as a percentage (default 0.50%)
+.TP
+\fB\-s\fR src.icc
+Apply gamut mapping to output profile perceptual B2A table for given source space
+.TP
+\fB\-S\fR src.icc
+Apply gamut mapping to output profile perceptual and saturation B2A table
+.TP
+\fB\-nP\fR
+Use colormetric source gamut to make output profile perceptual table
+.TP
+\fB\-nS\fR
+Use colormetric source gamut to make output profile saturation table
+.TP
+\fB\-g\fR src.gam
+Use source image gamut as well for output profile gamut mapping
+.TP
+\fB\-p\fR absprof,...
+Incorporate abstract profile(s) into output tables
+.TP
+\fB\-t\fR intent
+Override gamut mapping intent for output profile perceptual table:
+.TP
+\fB\-T\fR intent
+Override gamut mapping intent for output profile saturation table:
+.IP
+a \- Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]
+.IP
+aw \- Absolute Colorimetric (in Jab) with scaling to fit white point
+aa \- Absolute Appearance
+.IP
+r \- White Point Matched Appearance [ICC Relative Colorimetric]
+.IP
+la \- Luminance axis matched Appearance
+.IP
+p \- Perceptual (Preferred) (Default) [ICC Perceptual]
+.IP
+pa \- Perceptual Apperance
+ms \- Saturation
+.IP
+s \- Enhanced Saturation [ICC Saturation]
+.IP
+al \- Absolute Colorimetric (Lab)
+rl \- White Point Matched Colorimetric (Lab)
+.TP
+\fB\-c\fR viewcond
+set input viewing conditions for output profile CIECAM02 gamut mapping,
+.IP
+either an enumerated choice, or a parameter
+.TP
+\fB\-d\fR viewcond
+set output viewing conditions for output profile CIECAM02 gamut mapping
+.IP
+either an enumerated choice, or a parameter
+Also sets out of gamut clipping CAM space.
+either an enumerated choice, or a series of parameters:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+tv \- Television/Film Studio
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+\fB\-P\fR
+Create gamut gammap_p.wrl and gammap_s.wrl diagostics
+.TP
+\fB\-O\fR outputfile
+Override the default output filename.
+.TP
+inoutfile
+Base name for input.ti3/output.icc file
diff --git a/debian/man/colverify.1 b/debian/man/colverify.1
new file mode 100644
index 0000000..392d8f0
--- /dev/null
+++ b/debian/man/colverify.1
@@ -0,0 +1,68 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH VERIFY "1" "September 2014" "verfiy" "User Commands"
+.SH NAME
+Verify \- Verify CIE values.
+.SH DESCRIPTION
+Verify CIE values
+.SH SYNOPSIS
+.B verify
+.RB [\-options]\ target.ti3\ measured.ti3
+.TP
+\fB\-v\fR [n]
+Verbose mode, n >= 2 print each value
+.TP
+\fB\-n\fR
+Normalise each files reading to its white Y
+.TP
+\fB\-N\fR
+Normalise each files reading to its white XYZ
+.TP
+\fB\-m\fR
+Normalise each files reading to its white X+Y+Z
+.TP
+\fB\-D\fR
+Use D50 100.0 as L*a*b* white reference
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-s\fR
+Sort patch values by error
+.TP
+\fB\-w\fR
+create VRML vector visualisation (measured.wrl)
+.TP
+\fB\-W\fR
+create VRML marker visualisation (measured.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-L\fR profile.icc
+Skip any first file out of profile gamut patches
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix to second file
+.TP
+target.ti3
+Target (reference) PCS or spectral values.
+.TP
+measured.ti3
+Measured (actual) PCS or spectral values
diff --git a/debian/man/dispcal.1 b/debian/man/dispcal.1
new file mode 100644
index 0000000..20e9442
--- /dev/null
+++ b/debian/man/dispcal.1
@@ -0,0 +1,156 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CALIBRATE "1" "September 2014" "dispcal" "User Commands"
+.SH NAME
+Calibrate \- Calibrate a Display.
+.SH DESCRIPTION
+Calibrate a Display
+.SH SYNOPSIS
+.B dispcal
+.RB [options]\ outfile
+.TP
+\fB\-v\fR [n]
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 = 'Screen 1, Output DVI\-I\-1 at 0, 0, width 1920, height 1080'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-r\fR
+Report on the calibrated display then exit
+.TP
+\fB\-R\fR
+Report on the uncalibrated display then exit
+.TP
+\fB\-m\fR
+Skip adjustment of the monitor controls
+.TP
+\fB\-o\fR [profile.icc]
+Create fast matrix/shaper profile [different filename to outfile.icc]
+.TP
+\fB\-O\fR "description"
+Fast ICC Profile Description string (Default "outfile")
+.TP
+\fB\-u\fR
+Update previous calibration and (if \fB\-o\fR used) ICC profile VideoLUTs
+.TP
+\fB\-q\fR [vlmh]
+Quality \- Very Low, Low, Medium (def), High
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-t\fR [temp]
+White Daylight locus target, optional target temperaturee in deg. K (deflt.)
+.TP
+\fB\-T\fR [temp]
+White Black Body locus target, optional target temperaturee in deg. K
+.TP
+\fB\-w\fR x,y
+Set the target white point as chromaticity coordinates
+.TP
+\fB\-b\fR bright
+Set the target white brightness in cd/m^2
+.TP
+\fB\-g\fR gamma
+Set the target response curve advertised gamma (Def. 2.4)
+Use "\-gl" for L*a*b* curve
+Use "\-gs" for sRGB curve
+Use "\-g709" for REC 709 curve (should use \fB\-a\fR as well!)
+Use "\-g240" for SMPTE 240M curve (should use \fB\-a\fR as well!)
+Use "\-G2.4 \fB\-f0\fR" for BT.1886
+.TP
+\fB\-G\fR gamma
+Set the target response curve actual technical gamma
+.TP
+\fB\-f\fR [degree]
+Amount of black level accounted for with output offset (default all output offset)
+.TP
+\fB\-a\fR ambient
+Use viewing condition adjustment for ambient in Lux
+.TP
+\fB\-k\fR factor
+Amount to correct black hue, 0 = none, 1 = full, Default = Automatic
+.TP
+\fB\-A\fR rate
+Rate of blending from neutral to black point. Default 4.0
+.TP
+\fB\-B\fR blkbright
+Set the target black brightness in cd/m^2
+.TP
+\fB\-e\fR [n]
+Run n verify passes on final curves
+.TP
+\fB\-z\fR
+Run only verify pass on installed calibration curves
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-E\fR
+Encode the test values for video range 16..235/255
+.TP
+\fB\-J\fR
+Run instrument calibration first (used rarely)
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectrometer or CCSS colorimeter data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c
+.TP
+\fB\-I\fR b|w
+Drift compensation, Black: \fB\-Ib\fR, White: \fB\-Iw\fR, Both: \fB\-Ibw\fR
+.TP
+\fB\-Y\fR R:rate
+Override measured refresh rate with rate Hz
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-Y\fR p
+Don't wait for the instrument to be placed on the display
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-M\fR "command"
+Invoke shell "command" each time a color is measured
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+inoutfile
+Base name for created or updated .cal and .icc output files
diff --git a/debian/man/dispread.1 b/debian/man/dispread.1
new file mode 100644
index 0000000..a19b8c7
--- /dev/null
+++ b/debian/man/dispread.1
@@ -0,0 +1,103 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH READ "1" "September 2014" "dispread" "User Commands"
+.SH NAME
+Read \- Read a Display.
+.SH DESCRIPTION
+Read a Display
+.SH SYNOPSIS
+.B dispread
+.RB [options]\ outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 = 'Screen 1, Output DVI\-I\-1 at 0, 0, width 1920, height 1080'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-k\fR file.cal
+Load calibration file into display while reading
+.TP
+\fB\-K\fR file.cal
+Apply calibration file to test values while reading
+.TP
+\fB\-s\fR
+Save spectral information (default don't save)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-E\fR
+Encode the test values for video range 16..235/255
+.TP
+\fB\-J\fR
+Run instrument calibration first (used rarely)
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-w\fR
+Disable normalisation of white to Y = 100
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectrometer or CCSS colorimeter data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c
+.TP
+\fB\-I\fR b|w
+Drift compensation, Black: \fB\-Ib\fR, White: \fB\-Iw\fR, Both: \fB\-Ibw\fR
+.TP
+\fB\-Y\fR R:rate
+Override measured refresh rate with rate Hz
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-Y\fR p
+Don't wait for the instrument to be placed on the display
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-M\fR "command"
+Invoke shell "command" each time a color is measured
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+outfile
+Base name for input[ti1]/output[ti3] file
diff --git a/debian/man/dispwin.1 b/debian/man/dispwin.1
new file mode 100644
index 0000000..c4c7594
--- /dev/null
+++ b/debian/man/dispwin.1
@@ -0,0 +1,81 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH TEST "1" "September 2014" "dispwin" "User Commands"
+.SH NAME
+Test \- Test display patch window, Set Video LUTs, Install profiles.
+.SH DESCRIPTION
+Test display patch window, Set Video LUTs, Install profiles
+.SH SYNOPSIS
+.B dispwin
+.RB [options]\ [calfile]
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for Video LUT access
+.IP
+1 = 'Screen 1, Output DVI\-I\-1 at 0, 0, width 1920, height 1080'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-i\fR
+Run forever with random values
+.TP
+\fB\-G\fR filename
+Display RGB colors from CGATS file
+.TP
+\fB\-C\fR r.rr,g.gg,b.bb
+Add this RGB color to list to be displayed
+.TP
+\fB\-m\fR
+Manually cycle through values
+.TP
+\fB\-f\fR
+Test grey ramp fade
+.TP
+\fB\-r\fR
+Test just Video LUT loading & Beeps
+.TP
+\fB\-n\fR
+Test native output (rather than through Video LUT and C.M.)
+.TP
+\fB\-s\fR filename
+Save the currently loaded Video LUT to 'filename'
+.TP
+\fB\-c\fR
+Load a linear display calibration
+.TP
+\fB\-V\fR
+Verify that calfile/profile cal. is currently loaded in LUT
+.TP
+\fB\-I\fR
+Install profile for display and use it's calibration
+.TP
+\fB\-U\fR
+Un\-install profile for display
+.TP
+\fB\-S\fR d
+Specify the install/uninstall scope for OS X [nlu] or X11/Vista [lu]
+d is one of: n = network, l = local system, u = user (default)
+.TP
+\fB\-L\fR
+Load installed profiles cal. into Video LUT
+.TP
+\fB\-X\fR
+Run in daemon loader mode for given X11 server
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+calfile
+Load calibration (.cal or .icc) into Video LUT
diff --git a/debian/man/extracticc.1 b/debian/man/extracticc.1
new file mode 100644
index 0000000..9d5adad
--- /dev/null
+++ b/debian/man/extracticc.1
@@ -0,0 +1,12 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH EXTRACT "1" "September 2014" "extracticc" "User Commands"
+.SH NAME
+Extract \- Extract an ICC profile from a TIFF file.
+.SH DESCRIPTION
+Extract an ICC profile from a TIFF or JPEG file
+.SH SYNOPSIS
+.B extracticc
+.RB [\-v]\ infile.(tif|jpg)\ outfile.icc
+.TP
+\fB\-v\fR
+Verbose
diff --git a/debian/man/extractttag.1 b/debian/man/extractttag.1
new file mode 100644
index 0000000..eac947a
--- /dev/null
+++ b/debian/man/extractttag.1
@@ -0,0 +1,18 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH EXTRACT "1" "September 2014" "extractttag" "User Commands"
+.SH NAME
+Extract \- Extract a text tag from an ICC profile.
+.SH DESCRIPTION
+Extract a text tag from an ICC profile
+.SH SYNOPSIS
+.B extractttag
+.RB [\-v]\ infile.icc\ outfile
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-t\fR tag
+Extract this tag rather than default 'targ'
+.TP
+\fB\-c\fR
+Extract calibration file from 'targ' tag
diff --git a/debian/man/fakeCMY.1 b/debian/man/fakeCMY.1
new file mode 100644
index 0000000..6509ad6
--- /dev/null
+++ b/debian/man/fakeCMY.1
@@ -0,0 +1,21 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "fakeCMY" "User Commands"
+.SH NAME
+Create \- Create a fake CMY data file from a CMYK profile.
+.SH DESCRIPTION
+Create a fake CMY data file from a CMYK profile
+.SH SYNOPSIS
+.B fakeCMY
+.RB [option]\ profile.icm\ fake.ti3
+.TP
+\fB\-v\fR
+verbose
+.TP
+\fB\-r\fR res
+set surface point resolution (default 3)
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
diff --git a/debian/man/fakeread.1 b/debian/man/fakeread.1
new file mode 100644
index 0000000..1af12e0
--- /dev/null
+++ b/debian/man/fakeread.1
@@ -0,0 +1,90 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH FAKE "1" "September 2014" "fakeread" "User Commands"
+.SH NAME
+Fake \- Fake test chart reader - lookup values in ICC/MPP profile.
+.SH DESCRIPTION
+Fake test chart reader \- lookup values in ICC/MPP profile
+.SH SYNOPSIS
+.B fakeread
+.RB [\-options]\ profile.[icc|mpp|ti3]\ outfile
+.TP
+\fB\-v\fR [n]
+Verbose mode [level]
+.TP
+\fB\-e\fR flag
+Video encode device input to sepration as:
+.TP
+n
+normal 0..1 full range RGB levels (default)
+.TP
+t
+(16\-235)/255 "TV" RGB levels
+.TP
+6
+Rec601 YCbCr SD (16\-235,240)/255 "TV" levels
+.TP
+7
+Rec709 1125/60Hz YCbCr HD (16\-235,240)/255 "TV" levels
+.TP
+5
+Rec709 1250/50Hz YCbCr HD (16\-235,240)/255 "TV" levels
+.TP
+2
+Rec2020 YCbCr UHD (16\-235,240)/255 "TV" levels
+.TP
+C
+Rec2020 Constant Luminance YCbCr UHD (16\-235,240)/255 "TV" levels
+.HP
+\fB\-p\fR separation.icc Use device link separation profile on input
+.TP
+\fB\-E\fR flag
+Video decode separation device output. See \fB\-e\fR above
+.TP
+\fB\-k\fR file.cal
+Apply calibration (include in .ti3 output)
+.TP
+\fB\-i\fR file.cal
+Include calibration in .ti3 output, but don't apply it
+.TP
+\fB\-K\fR file.cal
+Apply inverse calibration
+.TP
+\fB\-r\fR level
+Add average random deviation of <level>% to device values (after sep. & cal.)
+.TP
+\fB\-0\fR pow
+Apply power to device chanel 0\-9
+.TP
+\fB\-b\fR output.icc
+Apply BT.1886\-like mapping with effective gamma 2.2
+.HP
+\fB\-b\fR g.g:output.icc Apply BT.1886\-like mapping with effective gamma g.g
+.TP
+\fB\-B\fR output.icc
+Apply BT.1886 mapping with technical gamma 2.4
+.HP
+\fB\-B\fR g.g:output.icc Apply BT.1886 mapping with technical gamma g.g
+.TP
+\fB\-I\fR intent
+r = relative colorimetric, a = absolute (default)
+.TP
+\fB\-A\fR L,a,b
+Scale black point to target Lab value
+.TP
+\fB\-l\fR
+Output Lab rather than XYZ
+.TP
+\fB\-s\fR
+Lookup MPP spectral values
+.TP
+\fB\-R\fR level
+Add average random deviation of <level>% to output PCS values
+.TP
+\fB\-u\fR
+Make random deviations have uniform distributions rather than normal
+.TP
+\fB\-S\fR seed
+Set random seed
+.IP
+profile.[icc|mpp|ti3] ICC, MPP profile or TI3 to use
+outfile Base name for input[ti1]/output[ti3] file
diff --git a/debian/man/greytiff.1 b/debian/man/greytiff.1
new file mode 100644
index 0000000..f1b71d6
--- /dev/null
+++ b/debian/man/greytiff.1
@@ -0,0 +1,18 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CONVERT "1" "September 2014" "greytiff" "User Commands"
+.SH NAME
+Convert \- Convert a TIFF file to monochrome using an ICC device profile.
+.SH DESCRIPTION
+Convert a TIFF file to monochrome using an ICC device profile
+.SH SYNOPSIS
+.B greytiff
+.RB [\-v\ level]\ profile.icm\ infile.tif\ outfile.tif
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-p\fR
+Use slow precise correction
+.TP
+\fB\-j\fR
+Use CIECAM02
diff --git a/debian/man/iccdump.1 b/debian/man/iccdump.1
new file mode 100644
index 0000000..e508f13
--- /dev/null
+++ b/debian/man/iccdump.1
@@ -0,0 +1,21 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH DUMP "1" "September 2014" "iccdump" "User Commands"
+.SH NAME
+Dump \- Dump an ICC file in human readable form.
+.SH DESCRIPTION
+Dump an ICC file in human readable form
+.SH SYNOPSIS
+.B iccdump
+.RB [\-v\ level]\ [\-t\ tagname]\ [\-s]\ infile
+.TP
+\fB\-v\fR level
+Verbose level 1\-3 (default 2)
+.TP
+\fB\-t\fR tag
+Dump this tag only (can be used multiple times)
+.TP
+\fB\-s\fR
+Search for embedded profile
+.TP
+\fB\-i\fR
+Check V4 ID value
diff --git a/debian/man/iccgamut.1 b/debian/man/iccgamut.1
new file mode 100644
index 0000000..2aa40ff
--- /dev/null
+++ b/debian/man/iccgamut.1
@@ -0,0 +1,97 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "iccgamut" "User Commands"
+.SH NAME
+Create \- Create Lab/Jab gamut plot.
+.SH DESCRIPTION
+Create Lab/Jab gamut plot
+.SH SYNOPSIS
+.B iccgamut
+.RB [options]\ profile
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-d\fR sres
+Surface resolution details 1.0 \- 50.0
+.TP
+\fB\-w\fR
+emit VRML .wrl file as well as CGATS .gam file
+.TP
+\fB\-n\fR
+Don't add VRML axes or white/black point
+.TP
+\fB\-k\fR
+Add VRML markers for prim. & sec. "cusp" points
+.TP
+\fB\-f\fR function
+f = forward*, b = backwards
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute (default), d = profile default
+.TP
+\fB\-p\fR oride
+l = Lab_PCS (default), j = CIECAM02 Appearance Jab
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-c\fR viewcond
+set viewing conditions for CIECAM02,
+either an enumerated choice, or a series of parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+tv \- Television/Film Studio
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:imagewhite
+Image white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 0)
+.TP
+g:glare
+Flare light % of ambient (default 1)
+.TP
+g:X:Y:Z
+Flare color as XYZ (default media white, Abs: D50)
+.TP
+g:x:y
+Flare color as x, y
+.TP
+\fB\-s\fR
+Create special cube surface topology plot
diff --git a/debian/man/icclu.1 b/debian/man/icclu.1
new file mode 100644
index 0000000..5cccdde
--- /dev/null
+++ b/debian/man/icclu.1
@@ -0,0 +1,34 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH TRANSLATE "1" "September 2014" "icclu" "User Commands"
+.SH NAME
+Translate \- Translate colors through an ICC profile.
+.SH DESCRIPTION
+Translate colors through an ICC profile
+.SH SYNOPSIS
+.B icclu
+.RB [\-v\ level]\ [\-f\ func]\ [\-i\ intent]\ [\-o\ order]\ profile
+.TP
+\fB\-v\fR level
+Verbosity level 0 \- 2 (default = 1)
+.TP
+\fB\-f\fR function
+f = forward, b = backwards, g = gamut, p = preview
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, l = Lab_PCS, y = Yxy,
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-s\fR scale
+Scale device range 0.0 \- scale rather than 0.0 \- 1.0
+.IP
+The colors to be translated should be fed into standard input,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
diff --git a/debian/man/illumread.1 b/debian/man/illumread.1
new file mode 100644
index 0000000..aaec8c3
--- /dev/null
+++ b/debian/man/illumread.1
@@ -0,0 +1,41 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH MEASURE "1" "September 2014" "illumread" "User Commands"
+.SH NAME
+Measure \- Measure an illuminant.
+.SH DESCRIPTION
+Measure an illuminant
+.SH SYNOPSIS
+.B illumread
+.RB [\-options]\ output.sp
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-S\fR
+Plot spectrum for each reading
+.TP
+\fB\-c\fR listno
+Choose instrument from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-Y\fR r
+Set refresh measurement mode
+.TP
+\fB\-Y\fR R:rate
+Override measured refresh rate with rate Hz
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+illuminant.sp
+File to save measurement to
diff --git a/debian/man/invprofcheck.1 b/debian/man/invprofcheck.1
new file mode 100644
index 0000000..60d897b
--- /dev/null
+++ b/debian/man/invprofcheck.1
@@ -0,0 +1,45 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CHECK "1" "September 2014" "invprofcheck" "User Commands"
+.SH NAME
+Check \- Check fwd to bwd relative transfer of an ICC file.
+.SH DESCRIPTION
+Check fwd to bwd relative transfer of an ICC file
+.SH SYNOPSIS
+.B invprofcheck
+.RB [\-]\ profile.icm
+.TP
+\fB\-v\fR [level]
+verbosity level (default 1), 2 to print each DE
+.TP
+\fB\-l\fR limit
+set total ink limit (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black channel ink limit (estimate by default)
+.TP
+\fB\-h\fR
+high res test (27)
+.TP
+\fB\-u\fR
+Ultra high res test (61)
+.TP
+\fB\-R\fR res
+Specific grid resolution
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-w\fR
+create VRML visualisation (profile.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-e\fR
+Color vectors according to delta E
+.TP
+profile.icm
+Profile to check
diff --git a/debian/man/kodak2ti3.1 b/debian/man/kodak2ti3.1
new file mode 100644
index 0000000..45abd06
--- /dev/null
+++ b/debian/man/kodak2ti3.1
@@ -0,0 +1,24 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CONVERT "1" "September 2014" "kodak2ti3" "User Commands"
+.SH NAME
+Convert \- Convert Kodak raw printer profile data to Argyll print data.
+.SH DESCRIPTION
+Convert Kodak raw printer profile data to Argyll print data
+.SH SYNOPSIS
+.B kodak2ti3
+.RB [\-v]\ [\-l\ limit]\ infile\ outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-l\fR limit
+set ink limit, 0 \- 400%
+.TP
+\fB\-r\fR filename
+Use an alternate 928 patch reference file
+.TP
+infile
+Base name for input.pat file
+.TP
+outfile
+Base name for output.ti3 file
diff --git a/debian/man/ls2ti3.1 b/debian/man/ls2ti3.1
new file mode 100644
index 0000000..d7c7315
--- /dev/null
+++ b/debian/man/ls2ti3.1
@@ -0,0 +1,13 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.6.
+.TH CONVERT "1" "May 2015" "Convert LightSpace raw RGB device profile data to Argyll CGATS data, Version 1.7.0" "User Commands"
+.SH NAME
+Convert \- Convert LightSpace raw RGB device profile data to Argyll CGATS data
+.SH DESCRIPTION
+Convert LightSpace raw RGB device profile data to Argyll CGATS data, Version 1.7.0
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.TP
+infile
+Input LightSpace .bcs file
+.TP
+outbasename
+Output file basename for .ti3
diff --git a/debian/man/mppcheck.1 b/debian/man/mppcheck.1
new file mode 100644
index 0000000..1cd6b16
--- /dev/null
+++ b/debian/man/mppcheck.1
@@ -0,0 +1,29 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CHECK "1" "September 2014" "mppcheck" "User Commands"
+.SH NAME
+Check \- Check Model Printer Profile.
+.SH DESCRIPTION
+Check Model Printer Profile
+.SH SYNOPSIS
+.B mppcheck
+.RB [\-v]\ [\-c]\ [\-s]\ [\-y]\ values.ti3\ profile.mpp
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-s\fR
+Check spectral model too
+.TP
+\fB\-y\fR
+Detail each value
+.TP
+values.ti3
+Test values to check against
+.IP
+profile.mpp Profile to check
diff --git a/debian/man/mpplu.1 b/debian/man/mpplu.1
new file mode 100644
index 0000000..5651f26
--- /dev/null
+++ b/debian/man/mpplu.1
@@ -0,0 +1,57 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH TRANSLATE "1" "September 2014" "" "User Commands"
+.SH NAME
+Translate \- Translate colors through an MPP profile.
+.SH DESCRIPTION
+Translate colors through an MPP profile
+.SH SYNOPSIS
+.B mpplu
+.RB [\-v]\ [\-f\ func]\ [\-i\ intent]\ [\-o\ order]\ profile
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-f\fR function
+f = forward, b = backwards
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, l = Lab_PCS, y = Yxy, s = spectral,
+.TP
+\fB\-l\fR limit
+override default ink limit, 1 \- N00%
+.TP
+\fB\-i\fR illum
+Choose illuminant for print/transparency spectral data:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-u\fR
+Use Fluorescent Whitening Agent compensation
+.TP
+\fB\-g\fR
+Create gamut output
+.TP
+\fB\-w\fR
+Create gamut VRML as well
+.TP
+\fB\-n\fR
+Don't add VRML axes
+.TP
+\fB\-a\fR n
+Gamut transparency level
+.TP
+\fB\-d\fR n
+Gamut surface detail level
+.TP
+\fB\-t\fR num
+Invoke debugging test code "num" 1..n
+1 \- check partial derivative for device input
+2 \- create overlap diagnostic VRML gamut surface
+.IP
+The colors to be translated should be fed into stdin,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
diff --git a/debian/man/mppprof.1 b/debian/man/mppprof.1
new file mode 100644
index 0000000..13a18ef
--- /dev/null
+++ b/debian/man/mppprof.1
@@ -0,0 +1,30 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "mppprof" "User Commands"
+.SH NAME
+Create \- Create Model Printer Profile.
+.SH DESCRIPTION
+Create Model Printer Profile
+.SH SYNOPSIS
+.B mppprof
+.RB [options]\ outfile
+.HP
+\fB\-v\fR [level] Verbose mode
+.HP
+\fB\-q\fR [lmhus] Quality \- Low, Medium (def), High, Ultra, Simple
+.TP
+\fB\-l\fR limit
+override default ink limit, 1 \- n00%
+.TP
+\fB\-s\fR
+Generate spectral model too
+.TP
+\fB\-m\fR
+Generate ink mixing model
+.HP
+\fB\-y\fR [level] Verify profile, 2 = read/write verify
+.TP
+\fB\-L\fR
+Output Lab values
+.TP
+outfile
+Base name for input.ti3/output.mpp file
diff --git a/debian/man/oeminst.1 b/debian/man/oeminst.1
new file mode 100644
index 0000000..ea56505
--- /dev/null
+++ b/debian/man/oeminst.1
@@ -0,0 +1,28 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH INSTALL "1" "September 2014" "oeminst" "User Commands"
+.SH NAME
+Install \- List information about the FILEs.
+.SH DESCRIPTION
+Install OEM data files
+.SH SYNOPSIS
+.B oeminst
+.RB [\-options]\ [infile(s)]
+.TP
+\fB\-v\fR [level]
+Verbose
+.TP
+\fB\-n\fR
+Don't install, show where files would be installed
+.TP
+\fB\-c\fR
+Don't install, save files to current directory
+.TP
+\fB\-S\fR d
+Specify the install scope u = user (def.), l = local system]
+.TP
+infile
+setup.exe CD install file(s) or .dll(s) containing install files
+.TP
+infile.[edr|ccss|ccmx]
+EDR file(s) to translate and install or CCSS or CCMX files to install
+If no file is provided, oeminst will look for the install CD.
diff --git a/debian/man/printcal.1 b/debian/man/printcal.1
new file mode 100644
index 0000000..38038d6
--- /dev/null
+++ b/debian/man/printcal.1
@@ -0,0 +1,77 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "printcal" "User Commands"
+.SH NAME
+Create \- Create printer calibration.
+.SH DESCRIPTION
+Create printer calibration
+.SH SYNOPSIS
+.B printcal
+.RB [\-options]\ [prevcal]\ inoutfile
+.TP
+\fB\-v\fR verbosity
+Verbose mode
+.TP
+\fB\-p\fR
+Plot graphs.
+.TP
+\fB\-i\fR
+Initial calibration, set targets, create .cal
+.TP
+\fB\-r\fR
+Re\-calibrate against previous .cal and create new .cal
+.TP
+\fB\-e\fR
+Verify against previous .cal
+.TP
+\fB\-I\fR
+Create imitation target from .ti3 and null calibration
+.TP
+\fB\-d\fR
+Go through the motions but don't write any files
+.TP
+\fB\-s\fR smoothing
+Extra curve smoothing (default 1.0)
+.HP
+\fB\-A\fR manufacturer Set the manufacturer description string
+.TP
+\fB\-M\fR model
+Set the model description string
+.TP
+\fB\-D\fR description
+Set the profile Description string
+.TP
+\fB\-C\fR copyright
+Set the copyright string
+.TP
+\fB\-x\fR# percent
+Set initial maximum device % target (override auto)
+.TP
+\fB\-m\fR# percent
+Set initial dev target to % of auto maximum
+.TP
+\fB\-n\fR# deltaE
+Set initial white minimum deltaE target
+.TP
+\fB\-t\fR# percent
+Set initial 50% transfer curve percentage target
+.TP
+# = c, r, 0
+First channel
+.TP
+m, g, 1
+Second channel
+.TP
+y, b, 2
+Third channel
+.TP
+k,
+3 Fourth channel, etc.
+.TP
+\fB\-a\fR
+Create an Adobe Photoshop .AMP file as well as a .cal
+.TP
+prevcal
+Base name of previous .cal file for recal or verify.
+.TP
+inoutname
+Base name of input .ti3 file, output .cal file
diff --git a/debian/man/printtarg.1 b/debian/man/printtarg.1
new file mode 100644
index 0000000..59ad2ba
--- /dev/null
+++ b/debian/man/printtarg.1
@@ -0,0 +1,125 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH GENERATE "1" "September 2014" "printarg" "User Commands"
+.SH NAME
+Generate \- Generate Target PostScrip file.
+.SH DESCRIPTION
+Generate Target PostScrip file
+.SH SYNOPSIS
+.B printtarg
+.RB [\-v]\ [\-i\ instr]\ [\-r]\ [\-s]\ [\-p\ size]\ basename
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-i\fR 20 | 22 | 41 | 51 | SS | i1 | CM Select target instrument (default DTP41)
+.IP
+20 = DTP20, 22 = DTP22, 41 = DTP41, 51 = DTP51,
+SS = SpectroScan, i1 = i1Pro, CM = ColorMunki
+.TP
+\fB\-h\fR
+Use hexagon patches for SS, double density for CM
+.TP
+\fB\-a\fR scale
+Scale patch size and spacers by factor (e.g. 0.857 or 1.5 etc.)
+.TP
+\fB\-A\fR scale
+Scale spacers by additional factor (e.g. 0.857 or 1.5 etc.)
+.TP
+\fB\-r\fR
+Don't randomize patch location
+.TP
+\fB\-s\fR
+Create a scan image recognition (.cht) file
+.TP
+\fB\-S\fR
+Same as \fB\-s\fR, but don't generate wide orientation strip.
+.TP
+\fB\-c\fR
+Force colored spacers
+.TP
+\fB\-b\fR
+Force B&W spacers
+.TP
+\fB\-n\fR
+Force no spacers
+.TP
+\fB\-f\fR
+Create PostScript DeviceN Color fallback
+.TP
+\fB\-w\fR g|r|s|n
+White colorspace encoding DeviceGray (def), DeviceRGB, Separation or DeviceN
+.TP
+\fB\-k\fR g|c|s|n
+Black colorspace encoding DeviceGray (def), DeviceCMYK, Separation or DeviceN
+.TP
+\fB\-o\fR k|r|n
+CMY colorspace encoding DefiveCMYK (def), inverted DeviceRGB or DeviceN
+.TP
+\fB\-e\fR
+Output EPS compatible file
+.TP
+\fB\-t\fR [res]
+Output 8 bit TIFF raster file, optional res DPI (default 100)
+.TP
+\fB\-T\fR [res]
+Output 16 bit TIFF raster file, optional res DPI (default 100)
+.TP
+\fB\-C\fR
+Don't use TIFF compression
+.TP
+\fB\-N\fR
+Use TIFF alpha N channels more than 4
+.TP
+\fB\-D\fR
+Dither 8 bit TIFF values down from 16 bit
+.TP
+\fB\-Q\fR nbits
+Quantize test values to fit in nbits
+.TP
+\fB\-R\fR rsnum
+Use given random start number
+.TP
+\fB\-K\fR file.cal
+Apply printer calibration to patch values and include in .ti2
+.TP
+\fB\-I\fR file.cal
+Include calibration in .ti2 (but don't apply it)
+.TP
+\fB\-x\fR pattern
+Use given strip indexing pattern (Default = "A\-Z, A\-Z")
+.TP
+\fB\-y\fR pattern
+Use given patch indexing pattern (Default = "0\-9,@\-9,@\-9;1\-999")
+.TP
+\fB\-m\fR margin
+Set a page margin in mm (default 6.0 mm)
+.TP
+\fB\-M\fR margin
+Set a page margin in mm and include it in TIFF
+.TP
+\fB\-P\fR
+Don't limit strip length
+.TP
+\fB\-L\fR
+Suppress any left paper clip border
+.TP
+\fB\-U\fR
+Suppress CUPS cupsJobTicket: cups\-disable\-cmm in PS & EPS files
+.TP
+\fB\-p\fR size
+Select page size from:
+A4 [210.0 x 297.0 mm]
+A4R [297.0 x 210.0 mm]
+A3 [297.0 x 420.0 mm] (default)
+A2 [420.0 x 594.0 mm]
+Letter [215.9 x 279.4 mm]
+LetterR [279.4 x 215.9 mm]
+Legal [215.9 x 355.6 mm]
+4x6 [101.6 x 152.4 mm]
+11x17 [279.4 x 431.8 mm]
+.TP
+\fB\-p\fR WWWxHHH
+Custom size, WWW mm wide by HHH mm high
+.TP
+basname
+Base name for input(.ti1), output(.ti2) and output(.ps/.eps/.tif)
diff --git a/debian/man/profcheck.1 b/debian/man/profcheck.1
new file mode 100644
index 0000000..683786a
--- /dev/null
+++ b/debian/man/profcheck.1
@@ -0,0 +1,61 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CHECK "1" "September 2014" "profcheck" "User Commands"
+.SH NAME
+Check \- Check accuracy of ICC profile.
+.SH DESCRIPTION
+Check accuracy of ICC profile, Version 1.6.3
+.SH SYNOPSIS
+.B profcheck
+.RB [\-options]\ data.ti3\ iccprofile.icm
+.TP
+\fB\-v\fR [level]
+Verbosity level (default 1), 2 to print each DE
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-w\fR
+create VRML visualisation (iccprofile.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-m\fR
+Make VRML lines a minimum of 0.5
+.TP
+\fB\-e\fR
+Color vectors according to delta E
+.HP
+\fB\-d\fR devval1,deval2,devvalN
+.IP
+Specify a device value to sort against
+.TP
+\fB\-p\fR
+Sort device value by PCS (Lab) target
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-I\fR intent
+r = relative colorimetric, a = absolute (default)
+.TP
+data.ti3
+Test data file
+.TP
+iccprofile.icm
+Profile to check against
diff --git a/debian/man/refine.1 b/debian/man/refine.1
new file mode 100644
index 0000000..8c05df5
--- /dev/null
+++ b/debian/man/refine.1
@@ -0,0 +1,57 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "refine" "User Commands"
+.SH NAME
+Create \- Create abstract correction profile given table of absolute CIE correction values.
+.SH DESCRIPTION
+Create abstract correction profile given table of absolute CIE correction values, Version 1.6.3
+.SH SYNOPSIS
+.B refine
+.RB [\-options]\ cietarget\ ciecurrent\ [outdevicc]\ [inabs]\ outabs
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-c\fR
+Create initial abstract correction profile
+.TP
+\fB\-g\fR
+Don't impose output device gamut limit
+.TP
+\fB\-r\fR res
+Set abstract profile clut resolution (default 33)
+.TP
+\fB\-d\fR factor
+Override default damping factor (default 0.950000, then 0.700000)
+.TP
+\fB\-R\fR
+Aim for white point relative match rather than absolute
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+cietarget
+Target CIE or spectral values, CGATS file (e.g. .ti3)
+.TP
+ciecurrent
+Actual CIE or spectral values, CGATS file (e.g. .ti3)
+.TP
+[outdevicc]
+Output device ICC profile to set gamut limit (not used if \fB\-g\fR)
+.TP
+[inabs]
+Previous abstract correction ICC profile (not used if \fB\-c\fR)
+.TP
+outabs
+Created/refined abstract correction ICC profile
diff --git a/debian/man/revfix.1 b/debian/man/revfix.1
new file mode 100644
index 0000000..b6cc94c
--- /dev/null
+++ b/debian/man/revfix.1
@@ -0,0 +1,49 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH INVERT "1" "September 2014" "revfix" "User Commands"
+.SH NAME
+Invert \- Invert AtoB1 to make BtoA1 for CMYK profiles.
+.SH DESCRIPTION
+Invert AtoB1 to make BtoA1 for CMYK profiles, Version 1.6.3
+.SH SYNOPSIS
+.B revfix
+.RB [\-options]\ iccin\ iccout
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-0\fR
+Process perceptual
+.TP
+\fB\-1\fR
+Process absolute/relative colorimetric
+.TP
+\fB\-2\fR
+Process saturation
+.TP
+\fB\-r\fR res
+Override BtoA1 Clut res
+.TP
+\fB\-k\fR [ezhxr]
+e = same K as existing BtoA table (def)
+z = zero, h = 0.5 K, x = max K, r = ramp K
+.HP
+\fB\-k\fR p stle stpo enle enpo shape
+.IP
+p = curve parameters
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-p\fR absprof
+Include abstract profile in output tables
diff --git a/debian/man/scanin.1 b/debian/man/scanin.1
new file mode 100644
index 0000000..e1d0656
--- /dev/null
+++ b/debian/man/scanin.1
@@ -0,0 +1,114 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH SCANIN, "1" "September 2014" "scanin" "User Commands"
+.SH NAME
+Scanin, \- Scanin.
+.SH DESCRIPTION
+Scanin, Version 1.6.3
+.SH SYNOPSIS
+.B scanin
+.RB [options]\ input.tif\ recogin.cht\ valin.cie\ [diag.tif]
+.IP
+:\- inputs 'input.tif' and outputs scanner 'input.ti3', or
+.PP
+.B scanin
+.RB \fB\-g\fR\ [options]\ input.tif\ recogout.cht\ [diag.tif]
+.IP
+:\- outputs file 'recogout.cht', or
+.PP
+.B scanin
+.RB \fB\-o\fR\ [options]\ input.tif\ recogin.cht\ [diag.tif]
+.IP
+:\- outputs file 'input.val', or
+.PP
+.B scanin
+.RB \fB\-c\fR\ [options]\ input.tif\ recogin.cht\ scanprofile.[icc|mpp]\ pbase\ [diag.tif]
+.IP
+:\- inputs pbase.ti2 and outputs printer pbase.ti3, or
+.PP
+.B scanin
+.RB \fB\-r\fR\ [options]\ input.tif\ recogin.cht\ pbase\ [diag.tif]
+.IP
+:\- inputs pbase.ti2+.ti3 and outputs pbase.ti3
+.TP
+\fB\-g\fR
+Generate a chart reference (.cht) file
+.TP
+\fB\-o\fR
+Output patch values in .val file
+.TP
+\fB\-c\fR
+Use image to measure color to convert printer pbase .ti2 to .ti3
+.TP
+\fB\-ca\fR
+Same as \fB\-c\fR, but accumulates more values to pbase .ti3
+from subsequent pages
+.TP
+\fB\-r\fR
+Replace device values in pbase .ti2/.ti3
+Default is to create a scanner .ti3 file
+.TP
+\fB\-F\fR x1,y1,x2,y2,x3,y3,x4,y4
+Don't auto recognize, locate using four fiducual marks
+.TP
+\fB\-p\fR
+Compensate for perspective distortion
+.TP
+\fB\-a\fR
+Recognise chart in normal orientation only (\fB\-A\fR fallback as is)
+Default is to recognise all possible chart angles
+.TP
+\fB\-m\fR
+Return true mean (default is robust mean)
+.TP
+\fB\-G\fR gamma
+Approximate gamma encoding of image
+.TP
+\fB\-v\fR [n]
+Verbosity level 0\-9
+.TP
+\fB\-d\fR [ihvglLIcrsonap]
+Generate diagnostic output (try \fB\-dipn\fR)
+.TP
+i
+diag \- B&W of input image
+.TP
+h
+diag \- Horizontal edge/tick detection
+.TP
+v
+diag \- Vertical edge/tick detection
+.TP
+g
+diag \- Groups detected
+.TP
+l
+diag \- Lines detected
+.TP
+L
+diag \- All lines detected
+.TP
+I
+diag \- lines used to improve fit
+.TP
+c
+diag \- lines perspective corrected
+.TP
+r
+diag \- lines rotated
+.TP
+s
+diag \- diagnostic sample boxes rotated
+.TP
+o
+diag \- sample box outlines
+.TP
+n
+diag \- sample box names
+.TP
+a
+diag \- sample box areas
+.TP
+p
+diag \- pixel areas sampled
+.HP
+\fB\-O\fR outputfile Override the default output filename & extension.
diff --git a/debian/man/spec2cie.1 b/debian/man/spec2cie.1
new file mode 100644
index 0000000..79f23b7
--- /dev/null
+++ b/debian/man/spec2cie.1
@@ -0,0 +1,47 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CONVERT "1" "September 2014" "spec2cie" "User Commands"
+.SH NAME
+Convert \- Convert spectral .ti3 file.
+.SH SYNOPSIS
+.B spec2cie
+[\fIoptions\fR] \fIinput.ti3 output.ti3\fR
+.SH DESCRIPTION
+Convert spectral .ti3 file, Version 1.6.3
+.SH SYNOPSIS
+.B spec2cie
+.RB [options]\ input.ti3\ output.ti3
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-I\fR illum
+Override actual instrument illuminant in .ti3 file:
+.IP
+A, C, D50, D50M2, D65, F5, F8, F10 or file.sp
+(only used in conjunction with \fB\-f\fR)
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-n\fR
+Don't output spectral values
+.TP
+\fB\-p\fR
+Plot each values spectrum
+.TP
+input.ti3
+Measurement file
+.TP
+output.ti3
+Converted measurement file
diff --git a/debian/man/specplot.1 b/debian/man/specplot.1
new file mode 100644
index 0000000..d4426f3
--- /dev/null
+++ b/debian/man/specplot.1
@@ -0,0 +1,28 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH PLOT "1" "September 2014" "specplot" "User Commands"
+.SH NAME
+Plot \- Plot spectrum and calculate CCT and VCT.
+.SH DESCRIPTION
+Plot spectrum and calculate CCT and VCT
+.SH SYNOPSIS
+.B specplot
+.RB [infile.sp]
+.TP
+\fB\-v\fR
+verbose
+.TP
+\fB\-c\fR
+combine multiple files into one plot
+.TP
+\fB\-z\fR
+don't make range cover zero
+.TP
+\fB\-u\fR level
+plot effect of adding estimated UV level
+.TP
+\fB\-U\fR
+plot effect of adding range of estimated UV level
+.TP
+[infile.sp ...]
+spectrum files to plot
+default is all built in illuminants
diff --git a/debian/man/splitti3.1 b/debian/man/splitti3.1
new file mode 100644
index 0000000..4be8b4e
--- /dev/null
+++ b/debian/man/splitti3.1
@@ -0,0 +1,33 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH SPLIT "1" "September 2014" "splitcgats" "User Commands"
+.SH NAME
+Split \- Split a .ti3 into two.
+.SH DESCRIPTION
+Split a .ti3 into two, Version 1.6.3
+.SH SYNOPSIS
+.B splitcgats
+.RB [\-options]\ input.ti3\ output1.ti3\ output2.ti3
+.TP
+\fB\-v\fR
+Verbose \- print each patch value
+.TP
+\fB\-n\fR no
+Put no sets in first file, and balance in second file.
+.TP
+\fB\-p\fR percent
+Put percent% sets in first file, and balance in second file. (def. 50%)
+.TP
+\fB\-w\fR
+Put white patches in both files.
+.TP
+\fB\-r\fR seed
+Use given random seed.
+.TP
+input.ti3
+File to be split up.
+.TP
+output1.ti3
+First output file
+.TP
+output2.ti3
+Second output file
diff --git a/debian/man/spotread.1 b/debian/man/spotread.1
new file mode 100644
index 0000000..050f708
--- /dev/null
+++ b/debian/man/spotread.1
@@ -0,0 +1,123 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH MEASURE "1" "September 2014" "spotread" "User Commands"
+.SH NAME
+Measure \- Read Print Spot values.
+.SH DESCRIPTION
+Measure spot values, Version 1.6.3
+.SH SYNOPSIS
+.B spotread
+.RB [\-options]\ [logfile]
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-s\fR
+Print spectrum for each reading
+.TP
+\fB\-S\fR
+Plot spectrum for each reading
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-t\fR
+Use transmission measurement mode
+.TP
+\fB\-e\fR
+Use emissive measurement mode (absolute results)
+.TP
+\fB\-eb\fR
+Use display white brightness relative measurement mode
+.TP
+\fB\-ew\fR
+Use display white point relative chromatically adjusted mode
+.TP
+\fB\-p\fR
+Use telephoto measurement mode (absolute results)
+.TP
+\fB\-pb\fR
+Use projector white brightness relative measurement mode
+.TP
+\fB\-pw\fR
+Use projector white point relative chromatically adjusted mode
+.TP
+\fB\-a\fR
+Use ambient measurement mode (absolute results)
+.TP
+\fB\-f\fR
+Use ambient flash measurement mode (absolute results)
+.TP
+\fB\-I\fR illum
+Set simulated instrument illumination using FWA (def \fB\-i\fR illum):
+M0, M1, M2, A, C, D50, D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectral data or CCSS instrument:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+(Choose FWA during operation)
+.TP
+\fB\-F\fR filter
+Set filter configuration (if aplicable):
+.TP
+n
+None
+.TP
+p
+Polarising filter
+.TP
+6
+D65
+.TP
+u
+U.V. Cut
+.TP
+\fB\-E\fR extrafilterfile
+Apply extra filter compensation file
+.TP
+\fB\-x\fR
+Display Yxy instead of Lab
+.TP
+\fB\-h\fR
+Display LCh instead of Lab
+.TP
+\fB\-V\fR
+Show running average and std. devation from ref.
+.TP
+\fB\-T\fR
+Display correlated color temperatures and CRI
+.TP
+\fB\-N\fR
+Disable auto calibration of instrument
+.TP
+\fB\-H\fR
+Start in high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Y\fR r|n
+Override refresh, non\-refresh display mode
+.TP
+\fB\-Y\fR R:rate
+Override measured refresh rate with rate Hz
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+logfile
+Optional file to save reading results as text
diff --git a/debian/man/synthcal.1 b/debian/man/synthcal.1
new file mode 100644
index 0000000..5fce9da
--- /dev/null
+++ b/debian/man/synthcal.1
@@ -0,0 +1,47 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "synthcal" "User Commands"
+.SH NAME
+Create \- Create a synthetic calibration file.
+.SH DESCRIPTION
+Create a synthetic calibration file, Version 1.6.3
+.SH SYNOPSIS
+.B synthcal
+.RB [\-options]\ outfile
+.TP
+\fB\-t\fR N
+i = input, o = output, d = display (default)
+.TP
+\fB\-d\fR col_comb
+choose colorant combination from the following (default 3):
+0: Print grey
+1: Video grey
+2: Print RGB
+3: Video RGB
+4: CMYK
+5: CMY
+6: CMYK + Light CM
+7: CMYK + Light CMK
+8: CMYK + Red + Blue
+9: CMYK + Orange + Green
+10: CMYK + Light CMK + Light Light K
+11: CMYK + Orange + Green + Light CM
+12: CMYK + Light CM + Medium CM
+.TP
+\fB\-D\fR colorant
+Add or delete colorant from combination:
+(Use \-?? to list known colorants)
+.TP
+\fB\-o\fR o1,o2,o3,
+Set non\-linear curve offset (default 0.0)
+.TP
+\fB\-s\fR s1,s2,s3,
+Set non\-linear curve scale (default 1.0)
+.TP
+\fB\-p\fR p1,p2,p3,
+Set non\-linear curve powers (default 1.0)
+.TP
+\fB\-E\fR description
+Set the profile dEscription string
+.TP
+outfile
+Base name for output .cal file
diff --git a/debian/man/synthread.1 b/debian/man/synthread.1
new file mode 100644
index 0000000..9a52806
--- /dev/null
+++ b/debian/man/synthread.1
@@ -0,0 +1,45 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH SYNTHETIC "1" "September 2014" "synthread" "User Commands"
+.SH NAME
+Synthetic \- Synthetic device model test chart reader.
+.SH DESCRIPTION
+Synthetic device model test chart reader \- Version 1.6.3
+.SH SYNOPSIS
+.B synthread
+.RB [\-v]\ [\-s]\ [separation.icm]\ profile.[icc|mpp|ti3]\ outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-p\fR
+Use separation profile
+.TP
+\fB\-l\fR
+Construct and output in Lab rather than XYZ
+.TP
+\fB\-i\fR p1,p2,p3,
+Set input channel curve powers (default 1.0)
+.TP
+\fB\-k\fR x1:y1,x2:y2,x3:y2
+Set input channel inflection points (default 0.5,0.5)
+.TP
+\fB\-o\fR p1,p2,p3,
+Set output channel curve powers (default 1.0)
+.TP
+\fB\-r\fR level
+Add average random deviation of <level>% to input device values (after sep.)
+.TP
+\fB\-R\fR level
+Add average random deviation of <level>% to output PCS values
+.TP
+\fB\-u\fR
+Make random deviations have uniform distributions rather than normal
+.TP
+\fB\-b\fR L,a,b
+Scale black point to target Lab value
+.TP
+[separation.icm]
+Device link separation profile
+.IP
+profile.[icc|mpp|ti3] ICC, MPP profile or TI3 to use
+outfile Base name for input[ti1]/output[ti3] file
diff --git a/debian/man/targen.1 b/debian/man/targen.1
new file mode 100644
index 0000000..6ad7229
--- /dev/null
+++ b/debian/man/targen.1
@@ -0,0 +1,112 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH GENERATE "1" "September 2014" "targen" "User Commands"
+.SH NAME
+Generate \- Generate Target deviceb test chart color values.
+.SH DESCRIPTION
+Generate Target deviceb test chart color values, Version 1.6.3
+.SH SYNOPSIS
+.B targen
+.RB [options]\ outfile
+.TP
+\fB\-v\fR [level]
+Verbose mode [optional level 1..N]
+.TP
+\fB\-d\fR col_comb
+choose colorant combination from the following:
+0: Print grey
+1: Video grey
+2: Print RGB
+3: Video RGB
+4: CMYK
+5: CMY
+6: CMYK + Light CM
+7: CMYK + Light CMK
+8: CMYK + Red + Blue
+9: CMYK + Orange + Green
+10: CMYK + Light CMK + Light Light K
+11: CMYK + Orange + Green + Light CM
+12: CMYK + Light CM + Medium CM
+.TP
+\fB\-D\fR colorant
+Add or delete colorant from combination:
+(Use \-?? to list known colorants)
+.TP
+\fB\-G\fR
+Generate good optimized points rather than Fast
+.TP
+\fB\-e\fR patches
+White test patches (default 4)
+.TP
+\fB\-B\fR patches
+Black test patches (default 4 Grey/RGB, else 0)
+.TP
+\fB\-s\fR steps
+Single channel steps (default grey 50, color 0)
+.TP
+\fB\-g\fR steps
+Grey axis RGB or CMY steps (default 0)
+.TP
+\fB\-m\fR steps
+Multidimensional device space cube steps (default 0)
+.TP
+\fB\-b\fR steps
+Multidimensional body centered cubic steps (default 0)
+.TP
+\fB\-f\fR patches
+Add iterative & adaptive full spread patches to total (default grey 0, color 836)
+Default is Optimised Farthest Point Sampling (OFPS)
+.TP
+\fB\-t\fR
+Use incremental far point for full spread
+.TP
+\fB\-r\fR
+Use device space random for full spread
+.TP
+\fB\-R\fR
+Use perceptual space random for full spread
+.TP
+\fB\-q\fR
+Use device space\-filling quasi\-random for full spread
+.TP
+\fB\-Q\fR
+Use perceptual space\-filling quasi\-random for full spread
+.TP
+\fB\-i\fR
+Use device space body centered cubic grid for full spread
+.TP
+\fB\-I\fR
+Use perceptual space body centered cubic grid for full spread
+.TP
+\fB\-a\fR angle
+Simplex grid angle 0.0 \- 0.5 for B.C.C. grid, default 0.333300
+.TP
+\fB\-A\fR adaptation
+Degree of adaptation of OFPS 0.0 \- 1.0 (default 0.1, \fB\-c\fR profile used 1.0)
+.TP
+\fB\-l\fR ilimit
+Total ink limit in % (default = none)
+.TP
+\fB\-p\fR power
+Optional power\-like value applied to all device values.
+.TP
+\fB\-c\fR profile
+Optional device ICC or MPP pre\-conditioning profile filename
+(Use "none" to turn off any conditioning)
+.TP
+\fB\-N\fR nemphasis
+Degree of neutral axis patch concentration 0.0\-1.0 (default 0.50)
+.TP
+\fB\-V\fR demphasis
+Degree of dark region patch concentration 1.0\-4.0 (default 1.00 = none)
+.TP
+\fB\-F\fR L,a,b,rad
+Filter out samples outside Lab sphere.
+.TP
+\fB\-w\fR
+Dump diagnostic outfilel.wrl file (Lab locations)
+.TP
+\fB\-W\fR
+Dump diagnostic outfiled.wrl file (Device locations)
+.TP
+outfile
+Base name for output(.ti1)
diff --git a/debian/man/tiffgamut.1 b/debian/man/tiffgamut.1
new file mode 100644
index 0000000..760c72f
--- /dev/null
+++ b/debian/man/tiffgamut.1
@@ -0,0 +1,90 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "tiffgamut" "User Commands"
+.SH NAME
+Create \- Create VRML image of the gamut surface of a TIFF.
+.SH DESCRIPTION
+Create VRML image of the gamut surface of a TIFF or JPEG, Version 1.6.3
+.SH SYNOPSIS
+.B tiffgamut
+.RB [\-v\ level]\ [profile.icm\ |\ embedded.tif/jpg]\ infile1.tif/jpg\ [infile2.tif/jpg\ ...]
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-d\fR sres
+Surface resolution details 1.0 \- 50.0
+.TP
+\fB\-w\fR
+emit VRML .wrl file as well as CGATS .gam file
+.TP
+\fB\-n\fR
+Don't add VRML axes or white/black point
+.TP
+\fB\-k\fR
+Add markers for prim. & sec. "cusp" points
+.TP
+\fB\-f\fR perc
+Filter by popularity, perc = percent to use
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute (default), d = profile default
+.TP
+\fB\-p\fR oride
+l = Lab_PCS (default), j = CIECAM02 Appearance Jab
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-c\fR viewcond
+set appearance mode and viewing conditions for CIECAM02,
+either an enumerated choice, or a parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+tv \- Television/Film Studio
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:imagewhite
+Image white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 0)
+.TP
+g:glare
+Flare light % of ambient (default 1)
+.TP
+g:X:Y:Z
+Flare color as XYZ (default media white, Abs: D50)
+.TP
+g:x:y
+Flare color as x, y
+.HP
+\fB\-O\fR outputfile Override the default output filename.
diff --git a/debian/man/timage.1 b/debian/man/timage.1
new file mode 100644
index 0000000..2ac441a
--- /dev/null
+++ b/debian/man/timage.1
@@ -0,0 +1,33 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CREATE "1" "September 2014" "timage" "User Commands"
+.SH NAME
+Create \- Create test images, default hex RGB surface and wedge.
+.SH DESCRIPTION
+Create test images, default hex RGB surface and wedge, Version 1.6.3
+.SH SYNOPSIS
+.B timage
+.RB [\-options]\ outfile.tif
+.TP
+\fB\-t\fR
+Generate rectangular gamut boundary test chart
+.TP
+\fB\-p\fR steps
+Generate a colorspace step chart with L* steps^2
+.TP
+\fB\-r\fR res
+Resolution in DPI (default 200)
+.TP
+\fB\-s\fR
+Smooth blend
+.TP
+\fB\-x\fR
+16 bit output
+.TP
+\fB\-4\fR
+CMYK output
+.TP
+\fB\-g\fR prop
+Percentage towards grey (default 0%)
+.TP
+outfile.tif
+Profile to check against
diff --git a/debian/man/txt2ti3.1 b/debian/man/txt2ti3.1
new file mode 100644
index 0000000..f0c44c4
--- /dev/null
+++ b/debian/man/txt2ti3.1
@@ -0,0 +1,33 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH CONVERT "1" "September 2014" "txt2ti3" "User Commands"
+.SH NAME
+Convert \- Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data.
+.SH DESCRIPTION
+Convert Gretag/Logo or X\-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data, Version 1.6.3
+.SH SYNOPSIS
+.B txt2ti3
+.RB [\-v]\ [\-l\ limit]\ [devfile]\ infile\ [specfile]\ outbase
+.TP
+\fB\-2\fR
+Create dummy .ti2 file as well
+.TP
+\fB\-l\fR limit
+set ink limit, 0 \- 400% (default max in file)
+.TP
+\fB\-d\fR
+Set type of device as Display, not Output
+.TP
+\fB\-i\fR
+Set type of device as Input, not Output
+.TP
+[devfile]
+Input Device CMYK target file (typically file.txt)
+.TP
+infile
+Input CIE, Spectral or Device & Spectral file (typically file.txt)
+.TP
+[specfile]
+Input Spectral file (typically file.txt)
+.TP
+outbasename
+Output file basename for .ti3 and .ti2
diff --git a/debian/man/viewgam.1 b/debian/man/viewgam.1
new file mode 100644
index 0000000..83afd63
--- /dev/null
+++ b/debian/man/viewgam.1
@@ -0,0 +1,42 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH VIEW "1" "September 2014" "viewgam" "User Commands"
+.SH NAME
+View \- View gamuts.
+.SH DESCRIPTION
+View gamuts Version 1.6.3
+.SH SYNOPSIS
+.B viewgam
+.RB { [\-c\ color]\ [\-t\ trans]\ [\-w|s]\ infile.gam }\ ...\ outfile.wrl
+.TP
+\fB\-c\fR color
+Color to make gamut, r = red, g = green, b = blue
+c = cyan, m = magenta, y = yellow, e = grey, w = white
+n = natural color
+.TP
+\fB\-t\fR trans
+Set transparency from 0.0 (opaque) to 1.0 (invisible)
+.TP
+\fB\-w\fR
+Show as a wireframe
+.TP
+\fB\-s\fR
+Show as a solid surace
+.TP
+infile.gam
+Name of .gam file
+Repeat above for each input file
+.TP
+\fB\-n\fR
+Don't add Lab axes
+.TP
+\fB\-k\fR
+Add markers for prim. & sec. "cusp" points
+.TP
+\fB\-i\fR
+Compute and print intersecting volume of first 2 gamuts
+.TP
+\fB\-I\fR isect.gam
+Same as \fB\-i\fR, but save intersection gamut to isect.gam
+.TP
+outfile.wrl
+Name of output .wrl file
diff --git a/debian/man/xicclu.1 b/debian/man/xicclu.1
new file mode 100644
index 0000000..b5aa7e9
--- /dev/null
+++ b/debian/man/xicclu.1
@@ -0,0 +1,162 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH LOOKUP "1" "September 2014" "xicclu" "User Commands"
+.SH NAME
+Lookup \- Translate colors through an xicc.
+.SH DESCRIPTION
+Lookup ICC or CAL colors, Version 1.6.3
+.SH SYNOPSIS
+.B xicclu
+.RB [\-options]\ profile_or_cal
+.TP
+\fB\-v\fR level
+Verbosity level 0 \- 2 (default = 1)
+.TP
+\fB\-g\fR
+Plot slice instead of looking colors up. (Default white to black)
+.TP
+\fB\-G\fR s:L:a:b
+Override plot slice start with Lab or Jab co\-ordinate
+.TP
+\fB\-G\fR e:L:a:b
+Override plot slice end with Lab or Jab co\-ordinate
+.TP
+\fB\-f\fR function
+f = forward, b = backwards, g = gamut, p = preview
+if = inverted forward, ib = inverted backwards
+.TP
+\fB\-i\fR intent
+a = absolute, r = relative colorimetric
+p = perceptual, s = saturation
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, X = XYZ * 100, l = Lab_PCS, L = LCh, y = Yxy
+j = CIECAM02 Appearance Jab, J = CIECAM02 Appearance JCh
+.TP
+\fB\-s\fR scale
+Scale device range 0.0 \- scale rather than 0.0 \- 1.0
+.TP
+\fB\-e\fR flag
+Video encode device input as:
+.TP
+\fB\-E\fR flag
+Video decode device output as:
+.TP
+n
+normal 0..1 full range RGB levels (default)
+.TP
+t
+(16\-235)/255 "TV" RGB levels
+.TP
+6
+Rec601 YCbCr SD (16\-235,240)/255 "TV" levels
+.TP
+7
+Rec709 1125/60Hz YCbCr HD (16\-235,240)/255 "TV" levels
+.TP
+5
+Rec709 1250/50Hz YCbCr HD (16\-235,240)/255 "TV" levels
+.TP
+2
+Rec2020 YCbCr UHD (16\-235,240)/255 "TV" levels
+.TP
+C
+Rec2020 Constant Luminance YCbCr UHD (16\-235,240)/255 "TV" levels
+.TP
+\fB\-k\fR [zhxrlv]
+Black value target: z = zero K,
+h = 0.5 K, x = max K, r = ramp K (def.)
+l = extra PCS input is portion of K locus
+v = extra PCS input is K target value
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.HP
+\fB\-k\fR q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2
+.IP
+Transfer extra PCS input to dual curve limits
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-a\fR
+show actual target values if clipped
+.TP
+\fB\-u\fR
+warn if output PCS is outside the spectrum locus
+.TP
+\fB\-m\fR
+merge output processing into clut
+.TP
+\fB\-b\fR
+use CAM Jab for clipping
+.TP
+\fB\-c\fR viewcond
+set viewing conditions for CIECAM97s,
+either an enumerated choice, or a parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+tv \- Television/Film Studio
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white, Abs: D50)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:imagewhite
+Image white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 0)
+.TP
+g:glare
+Flare light % of ambient (default 1)
+.TP
+g:X:Y:Z
+Flare color as XYZ (default media white, Abs: D50)
+.TP
+g:x:y
+Flare color as x, y
+.IP
+The colors to be translated should be fed into standard in,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
+Use \fB\-v0\fR for just output colors.
diff --git a/debian/missing-sources/deep_arrays.json b/debian/missing-sources/deep_arrays.json
new file mode 100644
index 0000000..3e1c094
--- /dev/null
+++ b/debian/missing-sources/deep_arrays.json
@@ -0,0 +1,18 @@
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+[[[[[[[[[[[[[[[[
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]] \ No newline at end of file
diff --git a/debian/missing-sources/difficult_json_c_test_case.json b/debian/missing-sources/difficult_json_c_test_case.json
new file mode 100644
index 0000000..d2bf5ea
--- /dev/null
+++ b/debian/missing-sources/difficult_json_c_test_case.json
@@ -0,0 +1,7 @@
+{ "glossary":
+ { "title": "example glossary", "GlossDiv":
+ { "title": "S", "GlossList":
+ [{ "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML", "markup"] } ]
+ }
+ }
+}
diff --git a/debian/missing-sources/difficult_json_c_test_case_with_comments.json b/debian/missing-sources/difficult_json_c_test_case_with_comments.json
new file mode 100644
index 0000000..189dca8
--- /dev/null
+++ b/debian/missing-sources/difficult_json_c_test_case_with_comments.json
@@ -0,0 +1,7 @@
+{ "glossary":
+ { /* you */ "title": /**/ "example glossary", /*should*/"GlossDiv":
+ { "title": /*never*/"S", /*ever*/"GlossList":
+ [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", /*see*/"GlossSeeAlso"/*this*/:/*coming*/[/*out*/"GML"/*of*/,/*the*/"XML"/*parser!*/, "markup"] /*hey*/}/*ho*/]/*hey*/
+ }/*ho*/
+ }
+} // and the parser won't even get this far, so chill. /* hah!
diff --git a/debian/missing-sources/non_utf8_char_in_string.json b/debian/missing-sources/non_utf8_char_in_string.json
new file mode 100644
index 0000000..7d75519
--- /dev/null
+++ b/debian/missing-sources/non_utf8_char_in_string.json
@@ -0,0 +1,88 @@
+{
+ "CoreletAPIVersion":2,
+ "CoreletType":"standalone",
+ "documentation":"A corelet that provides the capability to upload a folder’s contents into a user’s locker.",
+ "functions":
+ [
+ {
+ "documentation":"Displays a dialog box that allows user to select a folder on the local system.",
+ "name":"ShowBrowseDialog","parameters":
+ [
+ {
+ "documentation":"The callback function for results.",
+ "name":"callback",
+ "required":true,
+ "type":"callback"
+ }
+ ]
+ },
+ {
+ "documentation":"Uploads all mp3 files in the folder provided.",
+ "name":"UploadFolder","parameters":
+ [
+ {
+ "documentation":"The path to upload mp3 files from.",
+ "name":"path",
+ "required":true,
+ "type":"string"
+ },
+ {
+ "documentation":"The callback function for progress.",
+ "name":"callback",
+ "required":true,
+ "type":"callback"
+ }
+ ]
+ },
+ {
+ "documentation":"Returns the server name to the current locker service.",
+ "name":"GetLockerService",
+ "parameters":[]
+ },
+ {
+ "documentation":"Changes the name of the locker service.",
+ "name":"SetLockerService",
+ "parameters":
+ [
+ {
+ "documentation":"The value of the locker service to set active.",
+ "name":"LockerService",
+ "required":true,
+ "type":"string"
+ }
+ ]
+ },
+ {
+ "documentation":"Downloads locker files to the suggested folder.",
+ "name":"DownloadFile",
+ "parameters":
+ [
+ {
+ "documentation":"The origin path of the locker file.",
+ "name":"path",
+ "required":true,
+ "type":"string"
+ },
+ {
+ "documentation":"The Window destination path of the locker file.",
+ "name":"destination",
+ "required":true,"type":"integer"
+ },
+ {
+ "documentation":"The callback function for progress.",
+ "name":"callback",
+ "required":true,
+ "type":"callback"
+ }
+ ]
+ }
+ ],
+ "name":"LockerUploader",
+ "version":
+ {
+ "major":0,
+ "micro":1,
+ "minor":0
+ },
+ "versionString":"0.0.1"
+} \ No newline at end of file
diff --git a/debian/missing-sources/x3dom.debug.js b/debian/missing-sources/x3dom.debug.js
new file mode 100644
index 0000000..0703be4
--- /dev/null
+++ b/debian/missing-sources/x3dom.debug.js
@@ -0,0 +1,53578 @@
+/** X3DOM Runtime, http://www.x3dom.org/ 1.6.2 - 8f5655cec1951042e852ee9def292c9e0194186b - Sat Dec 20 00:03:52 2014 +0100 *//*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+// Add some JS1.6 Array functions:
+// (This only includes the non-prototype versions, because otherwise it messes up 'for in' loops)
+
+if (!Array.forEach) {
+ /*
+ * Function: Array.forEach
+ *
+ * Javascript array forEach() method calls a function for each element in the array.
+ *
+ * Parameters:
+ *
+ * array - The array
+ * fun - Function to test each element of the array
+ * thisp - Object to use as __this__ when executing callback
+ *
+ * Returns:
+ *
+ * The created array
+ */
+ Array.forEach = function (array, fun, thisp) {
+ var len = array.length;
+ for (var i = 0; i < len; i++) {
+ if (i in array) {
+ fun.call(thisp, array[i], i, array);
+ }
+ }
+ };
+}
+
+if (!Array.map) {
+ Array.map = function(array, fun, thisp) {
+ var len = array.length;
+ var res = [];
+ for (var i = 0; i < len; i++) {
+ if (i in array) {
+ res[i] = fun.call(thisp, array[i], i, array);
+ }
+ }
+ return res;
+ };
+}
+
+if (!Array.filter) {
+ Array.filter = function(array, fun, thisp) {
+ var len = array.length;
+ var res = [];
+ for (var i = 0; i < len; i++) {
+ if (i in array) {
+ var val = array[i];
+ if (fun.call(thisp, val, i, array)) {
+ res.push(val);
+ }
+ }
+ }
+ return res;
+ };
+}
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * The Namespace container for x3dom objects.
+ * @namespace x3dom
+ * */
+var x3dom = {
+ canvases : [],
+
+ x3dNS : 'http://www.web3d.org/specifications/x3d-namespace',
+ x3dextNS : 'http://philip.html5.org/x3d/ext',
+ xsltNS : 'http://www.w3.org/1999/XSL/x3dom.Transform',
+ xhtmlNS : 'http://www.w3.org/1999/xhtml'
+};
+
+/**
+ * The x3dom.nodeTypes namespace.
+ * @namespace x3dom.nodeTypes
+ * */
+x3dom.nodeTypes = {};
+
+/**
+ * The x3dom.nodeTypesLC namespace. Stores nodetypes in lowercase
+ * @namespace x3dom.nodeTypesLC
+ * */
+x3dom.nodeTypesLC = {};
+
+/**
+ * The x3dom.components namespace.
+ * @namespace x3dom.components
+ * */
+x3dom.components = {};
+
+/** Cache for primitive nodes (Box, Sphere, etc.) */
+x3dom.geoCache = [];
+
+/** Stores information about Browser and hardware capabilities */
+x3dom.caps = { PLATFORM: navigator.platform, AGENT: navigator.userAgent, RENDERMODE: "HARDWARE" };
+
+/** Registers the node defined by @p nodeDef.
+
+ The node is registered with the given @p nodeTypeName and @p componentName.
+
+ @param nodeTypeName the name of the node type (e.g. Material, Shape, ...)
+ @param componentName the name of the component the node type belongs to
+ @param nodeDef the definition of the node type
+ */
+x3dom.registerNodeType = function(nodeTypeName, componentName, nodeDef) {
+ //console.log("Registering nodetype [" + nodeTypeName + "] in component [" + componentName + "]");
+ if (x3dom.components[componentName] === undefined) {
+ x3dom.components[componentName] = {};
+ }
+ nodeDef._typeName = nodeTypeName;
+ nodeDef._compName = componentName;
+ x3dom.components[componentName][nodeTypeName] = nodeDef;
+ x3dom.nodeTypes[nodeTypeName] = nodeDef;
+ x3dom.nodeTypesLC[nodeTypeName.toLowerCase()] = nodeDef;
+};
+
+/** Test if node is registered X3D element */
+x3dom.isX3DElement = function(node) {
+ // x3dom.debug.logInfo("node=" + node + "node.nodeType=" + node.nodeType + ", node.localName=" + node.localName + ", ");
+ var name = (node.nodeType === Node.ELEMENT_NODE && node.localName) ? node.localName.toLowerCase() : null;
+ return (name && (x3dom.nodeTypes[node.localName] || x3dom.nodeTypesLC[name] ||
+ name == "x3d" || name == "websg" || name == "route"));
+};
+
+/*
+ * Function: x3dom.extend
+ *
+ * Returns a prototype object suitable for extending the given class
+ * _f_. Rather than constructing a new instance of _f_ to serve as
+ * the prototype (which unnecessarily runs the constructor on the created
+ * prototype object, potentially polluting it), an anonymous function is
+ * generated internally that shares the same prototype:
+ *
+ * Parameters:
+ * f - Method f a constructor
+ *
+ * Returns:
+ * A suitable prototype object
+ *
+ * See Also:
+ * Douglas Crockford's essay on <prototypical inheritance at http://javascript.crockford.com/prototypal.html>.
+ */
+// TODO; unify with defineClass, which does basically the same
+x3dom.extend = function(f) {
+ function G() {}
+ G.prototype = f.prototype || f;
+ return new G();
+};
+
+/**
+ * Function x3dom.getStyle
+ *
+ * Computes the value of the specified CSS property <tt>p</tt> on the
+ * specified element <tt>e</tt>.
+ *
+ * Parameters:
+ * oElm - The element on which to compute the CSS property
+ * strCssRule - The name of the CSS property
+ *
+ * Returns:
+ *
+ * The computed value of the CSS property
+ */
+x3dom.getStyle = function(oElm, strCssRule) {
+ var strValue = "";
+ var style = document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(oElm, null) : null;
+ if (style) {
+ strValue = style.getPropertyValue(strCssRule);
+ }
+ else if(oElm.currentStyle){
+ strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){ return p1.toUpperCase(); });
+ strValue = oElm.currentStyle[strCssRule];
+ }
+ return strValue;
+};
+
+
+/** Utility function for defining a new class.
+
+ @param parent the parent class of the new class
+ @param ctor the constructor of the new class
+ @param methods an object literal containing the methods of the new class
+ @return the constructor function of the new class
+ */
+function defineClass(parent, ctor, methods) {
+ if (parent) {
+ function Inheritance() {}
+ Inheritance.prototype = parent.prototype;
+
+ ctor.prototype = new Inheritance();
+ ctor.prototype.constructor = ctor;
+ ctor.superClass = parent;
+ }
+ if (methods) {
+ for (var m in methods) {
+ ctor.prototype[m] = methods[m];
+ }
+ }
+ return ctor;
+}
+
+/** Utility function for testing a node type.
+
+ @param object the object to test
+ @param clazz the type of the class
+ @return true or false
+ */
+x3dom.isa = function(object, clazz) {
+ /*
+ if (!object || !object.constructor || object.constructor.superClass === undefined) {
+ return false;
+ }
+ if (object.constructor === clazz) {
+ return true;
+ }
+
+ function f(c) {
+ if (c === clazz) {
+ return true;
+ }
+ if (c.prototype && c.prototype.constructor && c.prototype.constructor.superClass) {
+ return f(c.prototype.constructor.superClass);
+ }
+ return false;
+ }
+ return f(object.constructor.superClass);
+ */
+ return (object instanceof clazz);
+};
+
+
+/// helper
+x3dom.getGlobal = function () {
+ return (function () {
+ return this;
+ }).call(null);
+};
+
+
+/**
+ * Load javascript file either by performing an synchronous jax request
+ * an eval'ing the response or by dynamically creating a <script> tag.
+ *
+ * CAUTION: This function is a possible source for Cross-Site
+ * Scripting Attacks.
+ *
+ * @param src The location of the source file relative to
+ * path_prefix. If path_prefix is omitted, the
+ * current directory (relative to the HTML document)
+ * is used instead.
+ * @param path_prefix A prefix URI to add to the resource to be loaded.
+ * The URI must be given in normalized path form ending in a
+ * path separator (i.e. src/nodes/). It can be in absolute
+ * URI form (http://somedomain.tld/src/nodes/)
+ * @param blocking By default the lookup is done via blocking jax request.
+ * set to false to use the script i
+ */
+x3dom.loadJS = function(src, path_prefix, blocking) {
+ blocking = (blocking === false) ? blocking : true; // default to true
+
+ if (blocking) {
+ var url = (path_prefix) ? path_prefix.trim() + src : src;
+ var req = new XMLHttpRequest();
+
+ if (req) {
+ // third parameter false = synchronous/blocking call
+ // need this to load the JS before onload completes
+ req.open("GET", url, false);
+ req.send(null); // blocking
+
+ // maybe consider global eval
+ // http://perfectionkills.com/global-eval-what-are-the-options/#indirect_eval_call_examples
+ eval(req.responseText);
+ }
+ } else {
+ var head = document.getElementsByTagName('HEAD').item(0);
+ var script = document.createElement("script");
+ var loadpath = (path_prefix) ? path_prefix.trim() + src : src;
+ if (head) {
+ x3dom.debug.logError("Trying to load external JS file: " + loadpath);
+ //alert("Trying to load external JS file: " + loadpath);
+ script.type = "text/javascript";
+ script.src = loadpath;
+ head.appendChild(script);
+ } else {
+ alert("No document object found. Can't load components!");
+ //x3dom.debug.logError("No document object found. Can't load components");
+ }
+ }
+};
+
+// helper
+function array_to_object(a) {
+ var o = {};
+ for(var i=0;i<a.length;i++) {
+ o[a[i]]='';
+ }
+ return o;
+}
+
+/**
+ * Provides requestAnimationFrame in a cross browser way.
+ * https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/common/webgl-utils.js
+ */
+window.requestAnimFrame = (function() {
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
+ window.setTimeout(callback, 16);
+ };
+})();
+
+/**
+ * Toggle full-screen mode
+ */
+x3dom.toggleFullScreen = function() {
+ if (document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen) {
+ if (document.cancelFullScreen) {
+ document.cancelFullScreen();
+ }
+ else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen();
+ }
+ else if (document.webkitCancelFullScreen) {
+ document.webkitCancelFullScreen();
+ }
+ }
+ else {
+ var docElem = document.documentElement;
+ if (docElem.requestFullScreen) {
+ docElem.requestFullScreen();
+ }
+ else if (docElem.mozRequestFullScreen) {
+ docElem.mozRequestFullScreen();
+ }
+ else if (docElem.webkitRequestFullScreen) {
+ docElem.webkitRequestFullScreen();
+ }
+ }
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+x3dom.debug = {
+
+ INFO: "INFO",
+ WARNING: "WARNING",
+ ERROR: "ERROR",
+ EXCEPTION: "EXCEPTION",
+
+ // determines whether debugging/logging is active. If set to "false"
+ // no debugging messages will be logged.
+ isActive: false,
+
+ // stores if firebug is available
+ isFirebugAvailable: false,
+
+ // stores if the x3dom.debug object is initialized already
+ isSetup: false,
+
+ // stores if x3dom.debug object is append already (Need for IE integration)
+ isAppend: false,
+
+ // stores the number of lines logged
+ numLinesLogged: 0,
+
+ // the maximum number of lines to log in order to prevent
+ // the browser to slow down
+ maxLinesToLog: 10000,
+
+ // the container div for the logging messages
+ logContainer: null,
+
+ /** @brief Setup the x3dom.debug object.
+
+ Checks for firebug and creates the container div for the logging
+ messages.
+ */
+ setup: function() {
+ // If debugging is already setup simply return
+ if (x3dom.debug.isSetup) { return; }
+
+ // Check for firebug console
+ try {
+ if (window.console.firebug !== undefined) {
+ x3dom.debug.isFirebugAvailable = true;
+ }
+ }
+ catch (err) {
+ x3dom.debug.isFirebugAvailable = false;
+ }
+
+ //
+ x3dom.debug.setupLogContainer();
+
+ // setup should be setup only once, thus store if we done that already
+ x3dom.debug.isSetup = true;
+ },
+
+ /** @brief Activates the log
+ */
+ activate: function(visible) {
+ x3dom.debug.isActive = true;
+
+ //var aDiv = document.createElement("div");
+ //aDiv.style.clear = "both";
+ //aDiv.appendChild(document.createTextNode("\r\n"));
+ //aDiv.style.display = (visible) ? "block" : "none";
+ x3dom.debug.logContainer.style.display = (visible) ? "block" : "none";
+
+ //Need this HACK for IE/Flash integration. IE don't have a document.body at this time when starting Flash-Backend
+ if(!x3dom.debug.isAppend) {
+ if(navigator.appName == "Microsoft Internet Explorer") {
+ //document.documentElement.appendChild(aDiv);
+ x3dom.debug.logContainer.style.marginLeft = "8px";
+ document.documentElement.appendChild(x3dom.debug.logContainer);
+ }else{
+ //document.body.appendChild(aDiv);
+ document.body.appendChild(x3dom.debug.logContainer);
+ }
+ x3dom.debug.isAppend = true;
+ }
+ },
+
+ /** @brief Inserts a container div for the logging messages into the HTML page
+ */
+ setupLogContainer: function() {
+ x3dom.debug.logContainer = document.createElement("div");
+ x3dom.debug.logContainer.id = "x3dom_logdiv";
+ x3dom.debug.logContainer.setAttribute("class", "x3dom-logContainer");
+ x3dom.debug.logContainer.style.clear = "both";
+ //document.body.appendChild(x3dom.debug.logContainer);
+ },
+
+ /** @brief Generic logging function which does all the work.
+
+ @param msg the log message
+ @param logType the type of the log message. One of INFO, WARNING, ERROR
+ or EXCEPTION.
+ */
+ doLog: function(msg, logType) {
+
+ // If logging is deactivated do nothing and simply return
+ if (!x3dom.debug.isActive) { return; }
+
+ // If we have reached the maximum number of logged lines output
+ // a warning message
+ if (x3dom.debug.numLinesLogged === x3dom.debug.maxLinesToLog) {
+ msg = "Maximum number of log lines (=" + x3dom.debug.maxLinesToLog +
+ ") reached. Deactivating logging...";
+ }
+
+ // If the maximum number of log lines is exceeded do not log anything
+ // but simply return
+ if (x3dom.debug.numLinesLogged > x3dom.debug.maxLinesToLog) { return; }
+
+ // Output a log line to the HTML page
+ var node = document.createElement("p");
+ node.style.margin = 0;
+ switch (logType) {
+ case x3dom.debug.INFO:
+ node.style.color = "#00ff00";
+ break;
+ case x3dom.debug.WARNING:
+ node.style.color = "#cd853f";
+ break;
+ case x3dom.debug.ERROR:
+ node.style.color = "#ff4500";
+ break;
+ case x3dom.debug.EXCEPTION:
+ node.style.color = "#ffff00";
+ break;
+ default:
+ node.style.color = "#00ff00";
+ break;
+ }
+
+ // not sure if try/catch solves problem http://sourceforge.net/apps/trac/x3dom/ticket/52
+ // but due to no avail of ATI gfxcard can't test
+ try {
+ node.innerHTML = logType + ": " + msg;
+ x3dom.debug.logContainer.insertBefore(node, x3dom.debug.logContainer.firstChild);
+ } catch (err) {
+ if (window.console.firebug !== undefined) {
+ window.console.warn(msg);
+ }
+ }
+
+ // Use firebug's console if available
+ if (x3dom.debug.isFirebugAvailable) {
+ switch (logType) {
+ case x3dom.debug.INFO:
+ window.console.info(msg);
+ break;
+ case x3dom.debug.WARNING:
+ window.console.warn(msg);
+ break;
+ case x3dom.debug.ERROR:
+ window.console.error(msg);
+ break;
+ case x3dom.debug.EXCEPTION:
+ window.console.debug(msg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ x3dom.debug.numLinesLogged++;
+ },
+
+ /** Log an info message. */
+ logInfo: function(msg) {
+ x3dom.debug.doLog(msg, x3dom.debug.INFO);
+ },
+
+ /** Log a warning message. */
+ logWarning: function(msg) {
+ x3dom.debug.doLog(msg, x3dom.debug.WARNING);
+ },
+
+ /** Log an error message. */
+ logError: function(msg) {
+ x3dom.debug.doLog(msg, x3dom.debug.ERROR);
+ },
+
+ /** Log an exception message. */
+ logException: function(msg) {
+ x3dom.debug.doLog(msg, x3dom.debug.EXCEPTION);
+ },
+
+ /** Log an assertion. */
+ assert: function(c, msg) {
+ if (!c) {
+ x3dom.debug.doLog("Assertion failed in " +
+ x3dom.debug.assert.caller.name + ': ' +
+ msg, x3dom.debug.ERROR);
+ }
+ },
+
+ /**
+ Checks the type of a given object.
+
+ @param obj the object to check.
+ @returns one of; "boolean", "number", "string", "object",
+ "function", or "null".
+ */
+ typeOf: function (obj) {
+ var type = typeof obj;
+ return type === "object" && !obj ? "null" : type;
+ },
+
+ /**
+ Checks if a property of a specified object has the given type.
+
+ @param obj the object to check.
+ @param name the property name.
+ @param type the property type (optional, default is "function").
+ @returns true if the property exists and has the specified type,
+ otherwise false.
+ */
+ exists: function (obj, name, type) {
+ type = type || "function";
+ return (obj ? this.typeOf(obj[name]) : "null") === type;
+ },
+
+ /**
+ Dumps all members of the given object.
+ */
+ dumpFields: function (node) {
+ var str = "";
+ for (var fName in node) {
+ str += (fName + ", ");
+ }
+ str += '\n';
+ x3dom.debug.logInfo(str);
+ return str;
+ }
+};
+
+// Call the setup function to... umm, well, setup x3dom.debug
+x3dom.debug.setup();
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+//---------------------------------------------------------------------------------------------------------------------
+
+x3dom.arc = {};
+x3dom.arc.instance = null;
+
+x3dom.arc.Limits = function(min, max, initial)
+{
+ this._min = min;
+ this._max = max;
+
+ this.getValue = function(value)
+ {
+ value = this._min + (this._max - this._min) * value;
+ return this._max >= value ? (this._min <= value ? value : this._min ) : this._max;
+ };
+};
+
+//---------------------------------------------------------------------------------------------------------------------
+
+x3dom.arc.ARF = function(name, min, max, dirFac, factorGetterFunc, factorSetterFunc, getterFunc, setterFunc)
+{
+ this._name = name;
+ //start with average
+ this._stateValue = [ 0.5, 0.5 ];
+
+ this._limits = new x3dom.arc.Limits(min, max);
+ this._factorGetterFunc = factorGetterFunc;
+ this._factorSetterFunc = factorSetterFunc;
+ this._setterFunc = setterFunc;
+ this._getterFunc = getterFunc;
+ this._dirFac = dirFac;
+
+ this.getFactor = function()
+ {
+ return this._factorGetterFunc();
+ };
+
+ this.update = function(state, step)
+ {
+ var stateVal = this._stateValue[state] + step * this._dirFac;
+ this._stateValue[state] = 0 <= stateVal ? ( 1 >= stateVal ? stateVal : 1 ) : 0;
+ this._setterFunc(this._limits.getValue(this._stateValue[state]));
+
+ //console.log(this.name +" "+this._factorGetterFunc() +" * " + step +" "+ this._stateValue[state] +" "+ state);
+ };
+
+ this.reset = function()
+ {
+ this._stateValue[0] = 0.5;
+ this._stateValue[1] = 0.5;
+ };
+};
+
+//---------------------------------------------------------------------------------------------------------------------
+
+x3dom.arc.AdaptiveRenderControl = defineClass(
+ null,
+ function(scene)
+ {
+ x3dom.arc.instance = this;
+
+ this._scene = scene;
+ this._targetFrameRate = [];
+ this._targetFrameRate[0] = this._scene._vf.minFrameRate;
+ this._targetFrameRate[1] = this._scene._vf.maxFrameRate;
+
+ this._currentState = 0;
+
+ var that = this;
+ var environment = that._scene.getEnvironment();
+
+ this._arfs = [];
+
+ this._arfs.push(
+ new x3dom.arc.ARF("smallFeatureCulling",
+ 0, 10, -1,
+ function()
+ {
+ return environment._vf.smallFeatureFactor;
+ },
+ function(value)
+ {
+ environment._vf.smallFeatureFactor = value;
+ },
+ function()
+ {
+ return environment._vf.smallFeatureThreshold;
+ },
+ function(value)
+ {
+ environment._vf.smallFeatureThreshold = value;
+ }
+ )
+ );
+
+ this._arfs.push(
+ new x3dom.arc.ARF("lowPriorityCulling",
+ 0,100,1,
+ function()
+ {
+ return environment._vf.lowPriorityFactor;
+ },
+ function(value)
+ {
+ environment._vf.lowPriorityFactor = value;
+ },
+ function()
+ {
+ return environment._vf.lowPriorityThreshold * 100;
+ },
+ function(value)
+ {
+ environment._vf.lowPriorityThreshold = value / 100;
+ }
+ )
+ );
+
+ this._arfs.push(
+ new x3dom.arc.ARF("tessellationDetailCulling",
+ 1,12,-1,
+ function()
+ {
+ return environment._vf.tessellationErrorFactor;
+ },
+ function(value)
+ {
+ environment._vf.tessellationErrorFactor = value;
+ },
+ //@todo: this factor is a static member of PopGeo... should it belong to scene instead?
+ function()
+ {
+ return environment.tessellationErrorThreshold;
+ },
+ function(value)
+ {
+ environment.tessellationErrorThreshold = value;
+ }
+ )
+ );
+
+ this._stepWidth = 0.1;
+ },
+ {
+ update : function(state, fps) // state: 0 = static, 1 : moving
+ {
+ this._currentState = state;
+ var delta = fps - this._targetFrameRate[state];
+
+ //to prevent flickering
+ this._stepWidth = Math.abs(delta) > 10 ? 0.1 : 0.01;
+
+ /*if( (delta > 0 && state == 1) || (delta < 0 && state == 0))
+ return;
+ */
+
+ var factorSum = 0;
+ var normFactors = [];
+
+ //normalize factors
+ var i, n = this._arfs.length;
+
+ for(i = 0; i < n; ++i)
+ {
+ normFactors[i] = this._arfs[i].getFactor();
+ if(normFactors[i] > 0)
+ factorSum += normFactors[i];
+ }
+
+ var dirFac = delta < 0 ? -1 : 1;
+ for(i = 0; i < n; ++i)
+ {
+ if(normFactors[i] > 0)
+ {
+ normFactors[i] /= factorSum;
+ this._arfs[i].update(state, this._stepWidth * normFactors[i] * dirFac);
+ }
+ }
+ },
+
+ reset: function()
+ {
+ for( var i = 0, n = this._arfs.length; i < n; ++i)
+ {
+ this._arfs[i].reset();
+ }
+ }
+ }
+);
+
+//---------------------------------------------------------------------------------------------------------------------
+
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+ /**
+ * Class: x3dom.DownloadManager
+ *
+ * Simple priority-based download manager.
+ * Before objects of priority n+1 are available,
+ * all objects of priority n must have been already delivered.
+ * The highest priority key is 0.
+ *
+ */
+
+/// a small Request class
+var Request = function(url, onloadCallback, priority){
+ this.url = url;
+ this.priority = priority;
+ this.xhr = new XMLHttpRequest();
+ this.onloadCallbacks = [onloadCallback];
+
+ var self = this;
+
+ this.xhr.onload = function() {
+ if (x3dom.DownloadManager.debugOutput) {
+ x3dom.debug.logInfo('Download manager received data for URL \'' + self.url + '\'.');
+ }
+
+ --x3dom.DownloadManager.activeDownloads;
+
+ if ((x3dom.DownloadManager.stallToKeepOrder === false ) || (x3dom.DownloadManager.resultGetsStalled(self.priority) === false)) {
+ var i;
+ for (i = 0; i < self.onloadCallbacks.length; ++i) {
+ self.onloadCallbacks[i](self.xhr.response);
+ }
+
+ x3dom.DownloadManager.removeDownload(self);
+
+ x3dom.DownloadManager.updateStalledResults();
+ }
+ else if (x3dom.DownloadManager.debugOutput) {
+ x3dom.debug.logInfo('Download manager stalled downloaded result for URL \'' + self.url + '\'.');
+ }
+
+ x3dom.DownloadManager.tryNextDownload();
+ };
+};
+
+
+Request.prototype.send = function() {
+ this.xhr.open('GET', encodeURI(this.url), true); //asynchronous
+
+ //at the moment, ArrayBuffer is the only possible return type
+ this.xhr.responseType = 'arraybuffer';
+
+ this.xhr.send(null);
+
+ if (x3dom.DownloadManager.debugOutput) {
+ x3dom.debug.logInfo('Download manager posted XHR for URL \'' + this.url + '\'.');
+ }
+};
+
+
+x3dom.DownloadManager = {
+
+requests : [], //map priority->[requests]
+
+maxDownloads : 6, //number of max. concurrent downloads
+
+activeDownloads : 0, //number of active downloads
+
+debugOutput : false,
+
+stallToKeepOrder : false,
+
+
+toggleDebugOutput : function(flag) {
+ this.debugOutput = flag;
+},
+
+
+toggleStrictReturnOrder : function(flag) {
+ //@todo: this is not working properly yet!
+ this.stallToKeepOrder = false;
+ //this.stallToKeepOrder = flag;
+},
+
+
+removeDownload : function(req) {
+ var i, j;
+ var done = false;
+
+ for (i = 0; i < this.requests.length && !done; ++i) {
+ if (this.requests[i]){
+ for (j = 0; j < this.requests[i].length; ++j) {
+ if (this.requests[i][j] === req) {
+ this.requests[i].splice(j, 1);
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+},
+
+
+tryNextDownload : function() {
+ var firstRequest;
+ var i, j;
+
+ //if there are less then maxDownloads running, start a new one,
+ //otherwise do nothing
+ if (this.activeDownloads < this.maxDownloads) {
+ //remove first queue element, if any
+ for (i = 0; i < this.requests.length && !firstRequest; ++i) {
+ //find the request queue with the highest priority
+ if (this.requests[i]) {
+ //remove first unsent request from the queue, if any
+ for (j = 0; j < this.requests[i].length; ++j) {
+ if (this.requests[i][j].xhr.readyState === XMLHttpRequest.UNSENT) {
+ firstRequest = this.requests[i][j];
+ break;
+ }
+ }
+ }
+ }
+
+ if (firstRequest) {
+ firstRequest.send();
+
+ ++this.activeDownloads;
+ }
+ }
+},
+
+
+resultGetsStalled : function(priority) {
+ var i;
+
+ for (i = 0; i < priority; ++i) {
+ if (this.requests[i] && this.requests[i].length) {
+ return true;
+ }
+ }
+
+ return false;
+},
+
+
+updateStalledResults : function() {
+ if (x3dom.DownloadManager.stallToKeepOrder) {
+ var i, j, k;
+ var req, pendingRequestFound = false;
+
+ for (i = 0; i < this.requests.length && !pendingRequestFound; ++i) {
+
+ if (this.requests[i]) {
+ for (j = 0; j < this.requests[i].length; ++j) {
+ //check if there is a stalled result and relase it, if so
+ req = this.requests[i][j];
+
+ if (req.xhr.readyState === XMLHttpRequest.DONE) {
+
+ if (x3dom.DownloadManager.debugOutput) {
+ x3dom.debug.logInfo('Download manager releases stalled result for URL \'' + req.url + '\'.');
+ }
+
+ for (k = 0; k < req.onloadCallbacks.length; ++k) {
+ req.onloadCallbacks[k](req.xhr.response);
+ }
+
+ //remove request from the list
+ this.requests[i].splice(j, 1);
+ }
+ //if there is an unfinished result, stop releasing results of lower priorities
+ else {
+ pendingRequestFound = true;
+ }
+ }
+ }
+
+ }
+ }
+},
+
+
+/**
+ * Requests a download from the given URL, with the given onloadCallback and priority.
+ * The callback function will be invoked with a JSON object as parameter, where the
+ * 'arrayBuffer' member contains a reference to the requested data and the 'url' member
+ * contains the original user-given URL of the object.
+ *
+ * If there is no data from the given url available, but there is already a registered request
+ * for it, the new callback is just appended to the old registered request object. Note that,
+ * in this special case, the priority of the old request is not changed, i.e. the priority
+ * of the new request to the same url is ignored.
+ */
+get : function(urls, onloadCallbacks, priorities) {
+ var i, j, k, r;
+ var found = false;
+ var url, onloadCallback, priority;
+
+ if (urls.length !== onloadCallbacks.length || urls.length !== priorities.length)
+ {
+ x3dom.debug.logError('DownloadManager: The number of given urls, onload callbacks and priorities is not equal. Ignoring requests.');
+ return;
+ }
+
+ //insert requests
+ for (k = 0; k < urls.length; ++k) {
+ if (!onloadCallbacks[k] === undefined || !priorities[k] === undefined) {
+ x3dom.debug.logError('DownloadManager: No onload callback and / or priority specified. Ignoring request for \"' + url + '\"');
+ continue;
+ }
+ else {
+ url = urls[k];
+ onloadCallback = onloadCallbacks[k];
+ priority = priorities[k];
+
+ //enqueue request priority-based or append callback to a matching active request
+
+ //check if there is already an enqueued or sent request for the given url
+ for (i = 0; i < this.requests.length && !found; ++i) {
+ if (this.requests[i]) {
+ for (j = 0; j < this.requests[i].length; ++j) {
+ if (this.requests[i][j].url === url) {
+ this.requests[i][j].onloadCallbacks.push(onloadCallback);
+
+ if (x3dom.DownloadManager.debugOutput) {
+ x3dom.debug.logInfo('Download manager appended onload callback for URL \'' + url + '\' to a registered request using the same URL.');
+ }
+
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ r = new Request(url, onloadCallback, priority);
+
+ if (this.requests[priority]) {
+ this.requests[priority].push(r);
+ }
+ else {
+ this.requests[priority] = [r];
+ }
+ }
+ }
+ }
+
+ //try to download data
+ for (i = 0; i < urls.length && this.activeDownloads < this.maxDownloads; ++i) {
+ this.tryNextDownload();
+ }
+}
+
+};
+
+/**
+ * Created by tsturm on 30.10.2014.
+ */
+/**
+ * Parts Object is return
+ */
+x3dom.MultiMaterial = function( params )
+{
+ this._origAmbientIntensity = params.ambientIntensity;
+ this._origDiffuseColor = params.diffuseColor;
+ this._origEmissiveColor = params.emissiveColor;
+ this._origShininess = params.shininess;
+ this._origSpeclarColor = params.specularColor;
+ this._origTransparency = params.transparency;
+
+ this._origBackAmbientIntensity = params.backAmbientIntensity;
+ this._origBackDiffuseColor = params.backDiffuseColor;
+ this._origBackEmissiveColor = params.backEmissiveColor;
+ this._origBackShininess = params.backShininess;
+ this._origBackSpecularColor = params.backSpecularColor;
+ this._origBackTransparency = params.backTransparency;
+
+ this._ambientIntensity = params.ambientIntensity;
+ this._diffuseColor = params.diffuseColor;
+ this._emissiveColor = params.emissiveColor;
+ this._shininess = params.shininess;
+ this._specularColor = params.specularColor;
+ this._transparency = params.transparency;
+
+ this._backAmbientIntensity = params.backAmbientIntensity;
+ this._backDiffuseColor = params.backDiffuseColor;
+ this._backEmissiveColor = params.backEmissiveColor;
+ this._backShininess = params.backShininess;
+ this._backSpecularColor = params.backSpecularColor;
+ this._backTransparency = params.backTransparency;
+
+ this._highlighted = false;
+
+ this.reset = function () {
+ this._ambientIntensity = this._origAmbientIntensity;
+ this._diffuseColor = this._origDiffuseColor;
+ this._emissiveColor = this._origEmissiveColor;
+ this._shininess = this._origShininess;
+ this._specularColor = this._origSpeclarColor;
+ this._transparency = this._origTransparency;
+ this._backAmbientIntensity = this._origBackAmbientIntensity;
+ this._backDiffuseColor = this._origBackDiffuseColor;
+ this._backEmissiveColor = this._origBackEmissiveColor;
+ this._backShininess = this._origBackShininess;
+ this._backSpecularColor = this._origBackSpecularColor;
+ this._backTransparency = this._origBackTransparency;
+ };
+
+};
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/**
+ * Parts Object is return
+ */
+x3dom.Parts = function(multiPart, ids, colorMap, emissiveMap, specularMap, visibilityMap)
+{
+ var parts = this;
+ this.multiPart = multiPart;
+ this.ids = ids;
+ this.colorMap = colorMap;
+ this.emissiveMap = emissiveMap;
+ this.specularMap = specularMap;
+ this.visibilityMap = visibilityMap;
+ this.width = parts.colorMap.getWidth();
+ this.widthTwo = this.width * this.width;
+
+ /**
+ *
+ * @param color
+ * @param frontSide
+ */
+ this.setDiffuseColor = function(color, side)
+ {
+ var i, partID, pixelIDFront, pixelIDBack;
+
+ if(side == undefined && side != "front" && side != "back" && side != "both") {
+ side = "both";
+ }
+
+ color = x3dom.fields.SFColor.parse( color );
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var pixels = parts.colorMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ this.multiPart._materials[partID]._diffuseColor = color;
+ }
+ else if(side == "back")
+ {
+ this.multiPart._materials[partID]._backDiffuseColor = color;
+ }
+ else if(side == "both")
+ {
+ this.multiPart._materials[partID]._diffuseColor = color;
+ this.multiPart._materials[partID]._backDiffuseColor = color;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front") {
+ pixels[pixelIDFront].r = color.r;
+ pixels[pixelIDFront].g = color.g;
+ pixels[pixelIDFront].b = color.b;
+ } else if(side == "back") {
+ pixels[pixelIDBack].r = color.r;
+ pixels[pixelIDBack].g = color.g;
+ pixels[pixelIDBack].b = color.b;
+ } else if(side == "both") {
+ pixels[pixelIDFront].r = color.r;
+ pixels[pixelIDFront].g = color.g;
+ pixels[pixelIDFront].b = color.b;
+ pixels[pixelIDBack].r = color.r;
+ pixels[pixelIDBack].g = color.g;
+ pixels[pixelIDBack].b = color.b;
+ }
+ }
+ }
+
+ parts.colorMap.setPixels(pixels);
+ }
+ else
+ {
+ var xFront, yFront, xBack, yBack, pixelFront, pixelBack;
+
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ pixelFront = parts.colorMap.getPixel(xFront, yFront);
+ this.multiPart._materials[partID]._diffuseColor = color;
+ }
+ else if(side == "back")
+ {
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelBack = parts.colorMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._backDiffuseColor = color;
+ }
+ else if(side == "both")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelFront = parts.colorMap.getPixel(xFront, yFront);
+ pixelBack = parts.colorMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._diffuseColor = color;
+ this.multiPart._materials[partID]._backDiffuseColor = color;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front")
+ {
+ pixelFront.r = color.r;
+ pixelFront.g = color.g;
+ pixelFront.b = color.b;
+
+ parts.colorMap.setPixel(x, y, pixelFront);
+ }
+ else if(side == "back")
+ {
+ pixelBack.r = color.r;
+ pixelBack.g = color.g;
+ pixelBack.b = color.b;
+
+ parts.colorMap.setPixel(x, y, pixelBack);
+ }
+ else if(side == "both")
+ {
+ pixelFront.r = color.r;
+ pixelFront.g = color.g;
+ pixelFront.b = color.b;
+ pixelBack.r = color.r;
+ pixelBack.g = color.g;
+ pixelBack.b = color.b;
+
+ parts.colorMap.setPixel(x, y, pixelFront);
+ parts.colorMap.setPixel(x, y, pixelBack);
+ }
+ }
+ }
+ };
+
+ /**
+ *
+ * @param frontSide
+ * @returns {*}
+ */
+ this.getDiffuseColor = function(side)
+ {
+ var i, partID;
+
+ if(side == undefined && side != "front" && side != "back") {
+ side = "front";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ var diffuseColors = [];
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+
+ if(side == "front")
+ {
+ diffuseColors.push(this.multiPart._materials[partID]._diffuseColor);
+ }
+ else if(side == "back")
+ {
+ diffuseColors.push(this.multiPart._materials[partID]._backDiffuseColor);
+ }
+ }
+ return diffuseColors;
+ }
+ else
+ {
+ partID = parts.ids[0];
+
+ if(side == "front")
+ {
+ return this.multiPart._materials[partID]._diffuseColor;
+ }
+ else if(side == "back")
+ {
+ return this.multiPart._materials[partID]._backDiffuseColor;
+ }
+ }
+ };
+
+ /**
+ *
+ * @param color
+ * @param side
+ */
+ this.setEmissiveColor = function(color, side)
+ {
+ var i, partID, pixelIDFront, pixelIDBack;
+
+ if(side == undefined && side != "front" && side != "back" && side != "both") {
+ side = "both";
+ }
+
+ color = x3dom.fields.SFColor.parse( color );
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var pixels = parts.emissiveMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ this.multiPart._materials[partID]._emissiveColor = color;
+ }
+ else if(side == "back")
+ {
+ this.multiPart._materials[partID]._backEmissiveColor = color;
+ }
+ else if(side == "both")
+ {
+ this.multiPart._materials[partID]._emissiveColor = color;
+ this.multiPart._materials[partID]._backEmissiveColor = color;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front") {
+ pixels[pixelIDFront].r = color.r;
+ pixels[pixelIDFront].g = color.g;
+ pixels[pixelIDFront].b = color.b;
+ } else if(side == "back") {
+ pixels[pixelIDBack].r = color.r;
+ pixels[pixelIDBack].g = color.g;
+ pixels[pixelIDBack].b = color.b;
+ } else if(side == "both") {
+ pixels[pixelIDFront].r = color.r;
+ pixels[pixelIDFront].g = color.g;
+ pixels[pixelIDFront].b = color.b;
+ pixels[pixelIDBack].r = color.r;
+ pixels[pixelIDBack].g = color.g;
+ pixels[pixelIDBack].b = color.b;
+ }
+ }
+ }
+
+ parts.emissiveMap.setPixels(pixels);
+ }
+ else
+ {
+ var xFront, yFront, xBack, yBack, pixelFront, pixelBack;
+
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ pixelFront = parts.emissiveMap.getPixel(xFront, yFront);
+ this.multiPart._materials[partID]._emissiveColor = color;
+ }
+ else if(side == "back")
+ {
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelBack = parts.emissiveMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._backEmissiveColor = color;
+ }
+ else if(side == "both")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelFront = parts.emissiveMap.getPixel(xFront, yFront);
+ pixelBack = parts.emissiveMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._emissiveColor = color;
+ this.multiPart._materials[partID]._backEmissiveColor = color;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front")
+ {
+ pixelFront.r = color.r;
+ pixelFront.g = color.g;
+ pixelFront.b = color.b;
+
+ parts.emissiveMap.setPixel(x, y, pixelFront);
+ }
+ else if(side == "back")
+ {
+ pixelBack.r = color.r;
+ pixelBack.g = color.g;
+ pixelBack.b = color.b;
+
+ parts.emissiveMap.setPixel(x, y, pixelBack);
+ }
+ else if(side == "both")
+ {
+ pixelFront.r = color.r;
+ pixelFront.g = color.g;
+ pixelFront.b = color.b;
+ pixelBack.r = color.r;
+ pixelBack.g = color.g;
+ pixelBack.b = color.b;
+
+ parts.emissiveMap.setPixel(x, y, pixelFront);
+ parts.emissiveMap.setPixel(x, y, pixelBack);
+ }
+ }
+ }
+ };
+
+ /**
+ *
+ * @param side
+ * @returns {*}
+ */
+ this.getEmissiveColor = function(side)
+ {
+ var i, partID;
+
+ if(side == undefined && side != "front" && side != "back") {
+ side = "front";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ var emissiveColors = [];
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+
+ if(side == "front")
+ {
+ emissiveColors.push(this.multiPart._materials[partID]._emissiveColor);
+ }
+ else if(side == "back")
+ {
+ emissiveColors.push(this.multiPart._materials[partID]._backEmissiveColor);
+ }
+ }
+ return emissiveColors;
+ }
+ else
+ {
+ partID = parts.ids[0];
+
+ if(side == "front")
+ {
+ return this.multiPart._materials[partID]._emissiveColor;
+ }
+ else if(side == "back")
+ {
+ return this.multiPart._materials[partID]._backEmissiveColor;
+ }
+ }
+ };
+
+ /**
+ *
+ * @param color
+ * @param side
+ */
+ this.setSpecularColor = function(color, side)
+ {
+ var i, partID, pixelIDFront, pixelIDBack;
+
+ if(side == undefined && side != "front" && side != "back" && side != "both") {
+ side = "both";
+ }
+
+ color = x3dom.fields.SFColor.parse( color );
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var pixels = parts.specularMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ this.multiPart._materials[partID]._specularColor = color;
+ }
+ else if(side == "back")
+ {
+ this.multiPart._materials[partID]._backSpecularColor = color;
+ }
+ else if(side == "both")
+ {
+ this.multiPart._materials[partID]._specularColor = color;
+ this.multiPart._materials[partID]._backSpecularColor = color;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front") {
+ pixels[pixelIDFront].r = color.r;
+ pixels[pixelIDFront].g = color.g;
+ pixels[pixelIDFront].b = color.b;
+ } else if(side == "back") {
+ pixels[pixelIDBack].r = color.r;
+ pixels[pixelIDBack].g = color.g;
+ pixels[pixelIDBack].b = color.b;
+ } else if(side == "both") {
+ pixels[pixelIDFront].r = color.r;
+ pixels[pixelIDFront].g = color.g;
+ pixels[pixelIDFront].b = color.b;
+ pixels[pixelIDBack].r = color.r;
+ pixels[pixelIDBack].g = color.g;
+ pixels[pixelIDBack].b = color.b;
+ }
+ }
+ }
+
+ parts.specularMap.setPixels(pixels);
+ }
+ else
+ {
+ var xFront, yFront, xBack, yBack, pixelFront, pixelBack;
+
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ pixelFront = parts.specularMap.getPixel(xFront, yFront);
+ this.multiPart._materials[partID]._specularColor = color;
+ }
+ else if(side == "back")
+ {
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelBack = parts.specularMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._backSpecularColor = color;
+ }
+ else if(side == "both")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelFront = parts.specularMap.getPixel(xFront, yFront);
+ pixelBack = parts.specularMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._specularColor = color;
+ this.multiPart._materials[partID]._backSpecularColor = color;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front")
+ {
+ pixelFront.r = color.r;
+ pixelFront.g = color.g;
+ pixelFront.b = color.b;
+
+ parts.specularMap.setPixel(x, y, pixelFront);
+ }
+ else if(side == "back")
+ {
+ pixelBack.r = color.r;
+ pixelBack.g = color.g;
+ pixelBack.b = color.b;
+
+ parts.specularMap.setPixel(x, y, pixelBack);
+ }
+ else if(side == "both")
+ {
+ pixelFront.r = color.r;
+ pixelFront.g = color.g;
+ pixelFront.b = color.b;
+ pixelBack.r = color.r;
+ pixelBack.g = color.g;
+ pixelBack.b = color.b;
+
+ parts.specularMap.setPixel(x, y, pixelFront);
+ parts.specularMap.setPixel(x, y, pixelBack);
+ }
+ }
+ }
+ };
+
+
+ /**
+ *
+ * @param side
+ * @returns {*}
+ */
+ this.getSpecularColor = function(side)
+ {
+ var i, partID;
+
+ if(side == undefined && side != "front" && side != "back") {
+ side = "front";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ var specularColors = [];
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+
+ if(side == "front")
+ {
+ specularColors.push(this.multiPart._materials[partID]._specularColor);
+ }
+ else if(side == "back")
+ {
+ specularColors.push(this.multiPart._materials[partID]._backSpecularColor);
+ }
+ }
+ return specularColors;
+ }
+ else
+ {
+ partID = parts.ids[0];
+
+ if(side == "front")
+ {
+ return this.multiPart._materials[partID]._specularColor;
+ }
+ else if(side == "back")
+ {
+ return this.multiPart._materials[partID]._backSpecularColor;
+ }
+ }
+ };
+
+ /**
+ *
+ * @param transparency
+ * @param side
+ */
+ this.setTransparency = function(transparency, side)
+ {
+ var i, partID, pixelIDFront, pixelIDBack;
+
+ if(side == undefined && side != "front" && side != "back" && side != "both") {
+ side = "both";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var pixels = parts.colorMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ this.multiPart._materials[partID]._transparency = transparency;
+ }
+ else if(side == "back")
+ {
+ this.multiPart._materials[partID]._backTransparency = transparency;
+ }
+ else if(side == "both")
+ {
+ this.multiPart._materials[partID]._transparency = transparency;
+ this.multiPart._materials[partID]._backTransparency = transparency;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front") {
+ pixels[pixelIDFront].a = 1.0 - transparency;
+ } else if(side == "back") {
+ pixels[pixelIDBack].a = 1.0 - transparency;
+ } else if(side == "both") {
+ pixels[pixelIDFront].a = 1.0 - transparency;
+ pixels[pixelIDBack].a = 1.0 - transparency;
+ }
+ }
+ }
+
+ parts.colorMap.setPixels(pixels);
+ }
+ else
+ {
+ var xFront, yFront, xBack, yBack, pixelFront, pixelBack;
+
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ pixelFront = parts.colorMap.getPixel(xFront, yFront);
+ this.multiPart._materials[partID]._transparency = transparency;
+ }
+ else if(side == "back")
+ {
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelBack = parts.colorMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._backTransparency = transparency;
+ }
+ else if(side == "both")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelFront = parts.colorMap.getPixel(xFront, yFront);
+ pixelBack = parts.colorMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._transparency = transparency;
+ this.multiPart._materials[partID]._backTransparency = transparency;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front")
+ {
+ pixelFront.a = 1.0 - transparency;
+
+ parts.colorMap.setPixel(x, y, pixelFront);
+ }
+ else if(side == "back")
+ {
+ pixelBack.a = 1.0 - transparency;
+
+ parts.colorMap.setPixel(x, y, pixelBack);
+ }
+ else if(side == "both")
+ {
+ pixelFront.a = 1.0 - transparency;
+ pixelBack.a = 1.0 - transparency;
+
+ parts.colorMap.setPixel(x, y, pixelFront);
+ parts.colorMap.setPixel(x, y, pixelBack);
+ }
+ }
+ }
+ };
+
+
+ /**
+ *
+ * @param side
+ * @returns {*}
+ */
+ this.getTransparency = function(side)
+ {
+ var i, partID;
+
+ if(side == undefined && side != "front" && side != "back") {
+ side = "front";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ var transparencies = [];
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+
+ if(side == "front")
+ {
+ transparencies.push(this.multiPart._materials[partID]._transparency);
+ }
+ else if(side == "back")
+ {
+ transparencies.push(this.multiPart._materials[partID]._backTransparency);
+ }
+ }
+ return transparencies;
+ }
+ else
+ {
+ partID = parts.ids[0];
+
+ if(side == "front")
+ {
+ return this.multiPart._materials[partID]._transparency;
+ }
+ else if(side == "back")
+ {
+ return this.multiPart._materials[partID]._backTransparency;
+ }
+ }
+ };
+
+ /**
+ *
+ * @param shininess
+ * @param frontSide
+ */
+ this.setShininess = function(shininess, side)
+ {
+ var i, partID, pixelIDFront, pixelIDBack;
+
+ if(side == undefined && side != "front" && side != "back" && side != "both") {
+ side = "both";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var pixels = parts.specularMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ this.multiPart._materials[partID]._shininess = shininess;
+ }
+ else if(side == "back")
+ {
+ this.multiPart._materials[partID]._backShininess = shininess;
+ }
+ else if(side == "both")
+ {
+ this.multiPart._materials[partID]._shininess = shininess;
+ this.multiPart._materials[partID]._backShininess = shininess;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front") {
+ pixels[pixelIDFront].a = shininess;
+ } else if(side == "back") {
+ pixels[pixelIDBack].a = shininess;
+ } else if(side == "both") {
+ pixels[pixelIDFront].a = shininess;
+ pixels[pixelIDBack].a = shininess;
+ }
+ }
+ }
+
+ parts.specularMap.setPixels(pixels);
+ }
+ else
+ {
+ var xFront, yFront, xBack, yBack, pixelFront, pixelBack;
+
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ pixelFront = parts.specularMap.getPixel(xFront, yFront);
+ this.multiPart._materials[partID]._shininess = shininess;
+ }
+ else if(side == "back")
+ {
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelBack = parts.specularMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._backShininess = shininess;
+ }
+ else if(side == "both")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelFront = parts.specularMap.getPixel(xFront, yFront);
+ pixelBack = parts.specularMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._shininess = shininess;
+ this.multiPart._materials[partID]._backShininess = shininess;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front")
+ {
+ pixelFront.a = shininess;
+
+ parts.specularMap.setPixel(x, y, pixelFront);
+ }
+ else if(side == "back")
+ {
+ pixelBack.a = shininess;
+
+ parts.specularMap.setPixel(x, y, pixelBack);
+ }
+ else if(side == "both")
+ {
+ pixelFront.a = shininess;
+ pixelBack.a = shininess;
+
+ parts.specularMap.setPixel(x, y, pixelFront);
+ parts.specularMap.setPixel(x, y, pixelBack);
+ }
+ }
+ }
+ };
+
+
+ /**
+ *
+ * @param side
+ * @returns {*}
+ */
+ this.getShininess = function(side)
+ {
+ var i, partID;
+
+ if(side == undefined && side != "front" && side != "back") {
+ side = "front";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ var shininesses = [];
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+
+ if(side == "front")
+ {
+ shininesses.push(this.multiPart._materials[partID]._shininess);
+ }
+ else if(side == "back")
+ {
+ shininesses.push(this.multiPart._materials[partID]._backShininess);
+ }
+ }
+ return shininesses;
+ }
+ else
+ {
+ partID = parts.ids[0];
+
+ if(side == "front")
+ {
+ return this.multiPart._materials[partID]._shininess;
+ }
+ else if(side == "back")
+ {
+ return this.multiPart._materials[partID]._backShininess;
+ }
+ }
+ };
+
+ /**
+ *
+ * @param ambientIntensity
+ * @param side
+ */
+ this.setAmbientIntensity = function(ambientIntensity, side)
+ {
+ var i, partID, pixelIDFront, pixelIDBack;
+
+ if(side == undefined && side != "front" && side != "back" && side != "both") {
+ side = "both";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var pixels = parts.emissiveMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ this.multiPart._materials[partID]._ambientIntensity = ambientIntensity;
+ }
+ else if(side == "back")
+ {
+ this.multiPart._materials[partID]._backAmbientIntensity = ambientIntensity;
+ }
+ else if(side == "both")
+ {
+ this.multiPart._materials[partID]._ambientIntensity = ambientIntensity;
+ this.multiPart._materials[partID]._backAmbientIntensity = ambientIntensity;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front") {
+ pixels[pixelIDFront].a = ambientIntensity;
+ } else if(side == "back") {
+ pixels[pixelIDBack].a = ambientIntensity;
+ } else if(side == "both") {
+ pixels[pixelIDFront].a = ambientIntensity;
+ pixels[pixelIDBack].a = ambientIntensity;
+ }
+ }
+ }
+
+ parts.emissiveMap.setPixels(pixels);
+ }
+ else
+ {
+ var xFront, yFront, xBack, yBack, pixelFront, pixelBack;
+
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ //Check for front/back
+ if (side == "front")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ pixelFront = parts.emissiveMap.getPixel(xFront, yFront);
+ this.multiPart._materials[partID]._ambientIntensity = ambientIntensity;
+ }
+ else if(side == "back")
+ {
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelBack = parts.emissiveMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._backAmbientIntensity = ambientIntensity;
+ }
+ else if(side == "both")
+ {
+ xFront = pixelIDFront % this.width;
+ yFront = Math.floor(pixelIDFront / this.width);
+ xBack = pixelIDBack % this.width;
+ yBack = Math.floor(pixelIDBack / this.width);
+ pixelFront = parts.emissiveMap.getPixel(xFront, yFront);
+ pixelBack = parts.emissiveMap.getPixel(xBack, yBack);
+ this.multiPart._materials[partID]._ambientIntensity = ambientIntensity;
+ this.multiPart._materials[partID]._backAmbientIntensity = ambientIntensity;
+ }
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ if (side == "front")
+ {
+ pixelFront.a = ambientIntensity;
+
+ parts.emissiveMap.setPixel(x, y, pixelFront);
+ }
+ else if(side == "back")
+ {
+ pixelBack.a = ambientIntensity;
+
+ parts.emissiveMap.setPixel(x, y, pixelBack);
+ }
+ else if(side == "both")
+ {
+ pixelFront.a = ambientIntensity;
+ pixelBack.a = ambientIntensity;
+
+ parts.emissiveMap.setPixel(x, y, pixelFront);
+ parts.emissiveMap.setPixel(x, y, pixelBack);
+ }
+ }
+ }
+ };
+
+
+ /**
+ *
+ * @param side
+ * @returns {*}
+ */
+ this.getAmbientIntensity = function(side)
+ {
+ var i, partID;
+
+ if(side == undefined && side != "front" && side != "back") {
+ side = "front";
+ }
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ var ambientIntensities = [];
+
+ for ( i=0; i < parts.ids.length; i++ )
+ {
+ partID = parts.ids[i];
+
+ if(side == "front")
+ {
+ ambientIntensities.push(this.multiPart._materials[partID]._ambientIntensity);
+ }
+ else if(side == "back")
+ {
+ ambientIntensities.push(this.multiPart._materials[partID]._backAmbientIntensity);
+ }
+ }
+ return ambientIntensities;
+ }
+ else
+ {
+ partID = parts.ids[0];
+
+ if(side == "front")
+ {
+ return this.multiPart._materials[partID]._ambientIntensity;
+ }
+ else if(side == "back")
+ {
+ return this.multiPart._materials[partID]._backAmbientIntensity;
+ }
+ }
+ };
+
+ /**
+ *
+ * @param color
+ */
+ this.highlight = function (color)
+ {
+ var i, partID, pixelIDFront, pixelIDBack, dtColor, eaColor, ssColor;
+
+ color = x3dom.fields.SFColor.parse( color );
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var dtPixels = parts.colorMap.getPixels();
+ var eaPixels = parts.emissiveMap.getPixels();
+ var ssPixels = parts.specularMap.getPixels();
+
+ dtColor = new x3dom.fields.SFColorRGBA(0, 0, 0, 1.0);
+ eaColor = new x3dom.fields.SFColorRGBA(color.r, color.g, color.b, 0);
+ ssColor = new x3dom.fields.SFColorRGBA(0, 0, 0, 0);
+
+ for ( i=0; i < parts.ids.length; i++ ) {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ if( !this.multiPart._materials[partID]._highlighted )
+ {
+ this.multiPart._materials[partID]._highlighted = true;
+
+ dtPixels[pixelIDFront] = dtColor;
+ eaPixels[pixelIDFront] = eaColor;
+ ssPixels[pixelIDFront] = ssColor;
+
+ dtPixels[pixelIDBack] = dtColor;
+ eaPixels[pixelIDBack] = eaColor;
+ ssPixels[pixelIDBack] = ssColor;
+ }
+ }
+
+ this.colorMap.setPixels(dtPixels, false);
+ this.emissiveMap.setPixels(eaPixels, false);
+ this.specularMap.setPixels(ssPixels, true);
+ }
+ else
+ {
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ var xFront = pixelIDFront % this.width;
+ var yFront = Math.floor(pixelIDFront / this.width);
+
+ var xBack = pixelIDBack % this.width;
+ var yBack = Math.floor(pixelIDBack / this.width);
+
+ //If part is not highlighted update the pixel
+ if ( !this.multiPart._materials[partID]._highlighted )
+ {
+ this.multiPart._materials[partID]._highlighted = true;
+
+ dtColor = new x3dom.fields.SFColorRGBA(0, 0, 0, 1);
+ eaColor = new x3dom.fields.SFColorRGBA(color.r, color.g, color.b, 0);
+ ssColor = new x3dom.fields.SFColorRGBA(0, 0, 0, 0);
+
+ this.colorMap.setPixel(xFront, yFront, dtColor, false);
+ this.emissiveMap.setPixel(xFront, yFront, eaColor, false);
+ this.specularMap.setPixel(xFront, yFront, ssColor, false);
+
+ this.colorMap.setPixel(xBack, yBack, dtColor, false);
+ this.emissiveMap.setPixel(xBack, yBack, eaColor, false);
+ this.specularMap.setPixel(xBack, yBack, ssColor, true);
+ }
+ }
+ };
+
+ this.unhighlight = function() {
+ var i, partID, pixelIDFront, pixelIDBack, material;
+ var dtColorFront, eaColorFront, ssColorFront;
+ var dtColorBack, eaColorBack, ssColorBack;
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var dtPixels = parts.colorMap.getPixels();
+ var eaPixels = parts.emissiveMap.getPixels();
+ var ssPixels = parts.specularMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ ) {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ material = this.multiPart._materials[partID];
+
+ if( material._highlighted )
+ {
+ material._highlighted = false;
+
+ dtPixels[pixelIDFront] = new x3dom.fields.SFColorRGBA(material._diffuseColor.r, material._diffuseColor.g,
+ material._diffuseColor.b, 1.0 - material._transparency);
+ eaPixels[pixelIDFront] = new x3dom.fields.SFColorRGBA(material._emissiveColor.r, material._emissiveColor.g,
+ material._emissiveColor.b, material._ambientIntensity);
+ ssPixels[pixelIDFront] = new x3dom.fields.SFColorRGBA(material._specularColor.r, material._specularColor.g,
+ material._specularColor.b, material._shininess);
+
+ dtPixels[pixelIDBack] = new x3dom.fields.SFColorRGBA(material._backDiffuseColor.r, material._backDiffuseColor.g,
+ material._backDiffuseColor.b, 1.0 - material._backTransparency);
+ eaPixels[pixelIDBack] = new x3dom.fields.SFColorRGBA(material._backEmissiveColor.r, material._backEmissiveColor.g,
+ material._backEmissiveColor.b, material._backAmbientIntensity);
+ ssPixels[pixelIDBack] = new x3dom.fields.SFColorRGBA(material._backSpecularColor.r, material._backSpecularColor.g,
+ material._backSpecularColor.b, material._backShininess);
+ }
+ }
+
+ this.colorMap.setPixels(dtPixels, false);
+ this.emissiveMap.setPixels(eaPixels, false);
+ this.specularMap.setPixels(ssPixels, true);
+ }
+ else
+ {
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ var xFront = pixelIDFront % this.width;
+ var yFront = Math.floor(pixelIDFront / this.width);
+
+ var xBack = pixelIDBack % this.width;
+ var yBack = Math.floor(pixelIDBack / this.width);
+
+ material = this.multiPart._materials[partID];
+
+ //If part is not highlighted update the pixel
+ if ( material._highlighted )
+ {
+ material._highlighted = false;
+
+ dtColorFront = new x3dom.fields.SFColorRGBA(material._diffuseColor.r, material._diffuseColor.g,
+ material._diffuseColor.b, 1.0 - material._transparency);
+ eaColorFront = new x3dom.fields.SFColorRGBA(material._emissiveColor.r, material._emissiveColor.g,
+ material._emissiveColor.b, material._ambientIntensity);
+ ssColorFront = new x3dom.fields.SFColorRGBA(material._specularColor.r, material._specularColor.g,
+ material._specularColor.b, material._shininess);
+
+ dtColorBack = new x3dom.fields.SFColorRGBA(material._backDiffuseColor.r, material._backDiffuseColor.g,
+ material._backDiffuseColor.b, 1.0 - material._backTransparency);
+ eaColorBack = new x3dom.fields.SFColorRGBA(material._backEmissiveColor.r, material._backEmissiveColor.g,
+ material._backEmissiveColor.b, material._backAmbientIntensity);
+ ssColorBack = new x3dom.fields.SFColorRGBA(material._backSpecularColor.r, material._backSpecularColor.g,
+ material._backSpecularColor.b, material._backShininess);
+
+ this.colorMap.setPixel(xFront, yFront, dtColorFront, false);
+ this.emissiveMap.setPixel(xFront, yFront, eaColorFront, false);
+ this.specularMap.setPixel(xFront, yFront, ssColorFront, false);
+
+ this.colorMap.setPixel(xBack, yBack, dtColorBack, false);
+ this.emissiveMap.setPixel(xBack, yBack, eaColorBack, false);
+ this.specularMap.setPixel(xBack, yBack, ssColorBack, true);
+ }
+ }
+ };
+
+
+ /**
+ *
+ * @param color
+ */
+ this.toggleHighlight = function ( color ) {
+ for ( var i=0; i < parts.ids.length; i++ ) {
+ if ( this.multiPart._materials[parts.ids[i]]._highlighted ) {
+ this.unhighlight();
+ } else {
+ this.highlight(color);
+ }
+ }
+ };
+
+
+ /**
+ *
+ * @param color
+ * @param side
+ */
+ this.setColor = function(color, side) {
+ this.setDiffuseColor(color, side);
+ };
+
+
+ /**
+ * Returns the RGB string representation of a color
+ * @returns {String}
+ */
+ this.getColorRGB = function() {
+ var str = this.getColorRGBA();
+
+ var values = str.split(" ");
+
+ return values[0] + " " + values[1] + " " + values[2];
+ };
+
+ /**
+ * Returns the RGBA string representation of a color
+ * @returns {String}
+ */
+ this.getColorRGBA = function() {
+ var x, y;
+
+ //in case of multi select, this function returns the color of the first object
+ var colorRGBA = this.multiPart._originalColor[parts.ids[0]];
+
+ if (this.multiPart._highlightedParts[parts.ids[0]]){
+ colorRGBA = this.multiPart._highlightedParts[parts.ids[0]];
+ } else {
+ x = parts.ids[0] % parts.colorMap.getWidth();
+ y = Math.floor(parts.ids[0] / parts.colorMap.getWidth());
+ colorRGBA = parts.colorMap.getPixel(x, y);
+ }
+
+ return colorRGBA.toString();
+ };
+
+ /**
+ *
+ */
+ this.resetColor = function() {
+
+ var i, partID, pixelIDFront, pixelIDBack, material;
+ var dtColorFront, eaColorFront, ssColorFront;
+ var dtColorBack, eaColorBack, ssColorBack;
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ //Get original pixels
+ var dtPixels = parts.colorMap.getPixels();
+ var eaPixels = parts.emissiveMap.getPixels();
+ var ssPixels = parts.specularMap.getPixels();
+
+ for ( i=0; i < parts.ids.length; i++ ) {
+ partID = parts.ids[i];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ material = this.multiPart._materials[partID];
+
+ material.reset();
+
+ if( !material._highlighted )
+ {
+ dtPixels[pixelIDFront] = new x3dom.fields.SFColorRGBA(material._diffuseColor.r, material._diffuseColor.g,
+ material._diffuseColor.b, 1.0 - material._transparency);
+ eaPixels[pixelIDFront] = new x3dom.fields.SFColorRGBA(material._emissiveColor.r, material._emissiveColor.g,
+ material._emissiveColor.b, material._ambientIntensity);
+ ssPixels[pixelIDFront] = new x3dom.fields.SFColorRGBA(material._specularColor.r, material._specularColor.g,
+ material._specularColor.b, material._shininess);
+
+ dtPixels[pixelIDBack] = new x3dom.fields.SFColorRGBA(material._backDiffuseColor.r, material._backDiffuseColor.g,
+ material._backDiffuseColor.b, 1.0 - material._backTransparency);
+ eaPixels[pixelIDBack] = new x3dom.fields.SFColorRGBA(material._backEmissiveColor.r, material._backEmissiveColor.g,
+ material._backEmissiveColor.b, material._backAmbientIntensity);
+ ssPixels[pixelIDBack] = new x3dom.fields.SFColorRGBA(material._backSpecularColor.r, material._backSpecularColor.g,
+ material._backSpecularColor.b, material._backShininess);
+ }
+ }
+
+ this.colorMap.setPixels(dtPixels, false);
+ this.emissiveMap.setPixels(eaPixels, false);
+ this.specularMap.setPixels(ssPixels, true);
+ }
+ else //Single select
+ {
+ partID = parts.ids[0];
+ pixelIDFront = partID;
+ pixelIDBack = partID + this.widthTwo;
+
+ var xFront = pixelIDFront % this.width;
+ var yFront = Math.floor(pixelIDFront / this.width);
+
+ var xBack = pixelIDBack % this.width;
+ var yBack = Math.floor(pixelIDBack / this.width);
+
+ material = this.multiPart._materials[partID];
+
+ material.reset();
+
+ //If part is not highlighted update the pixel
+ if ( !material._highlighted )
+ {
+ dtColorFront = new x3dom.fields.SFColorRGBA(material._diffuseColor.r, material._diffuseColor.g,
+ material._diffuseColor.b, 1.0 - material._transparency);
+ eaColorFront = new x3dom.fields.SFColorRGBA(material._emissiveColor.r, material._emissiveColor.g,
+ material._emissiveColor.b, material._ambientIntensity);
+ ssColorFront = new x3dom.fields.SFColorRGBA(material._specularColor.r, material._specularColor.g,
+ material._specularColor.b, material._shininess);
+
+ dtColorBack = new x3dom.fields.SFColorRGBA(material._backDiffuseColor.r, material._backDiffuseColor.g,
+ material._backDiffuseColor.b, 1.0 - material._backTransparency);
+ eaColorBack = new x3dom.fields.SFColorRGBA(material._backEmissiveColor.r, material._backEmissiveColor.g,
+ material._backEmissiveColor.b, material._backAmbientIntensity);
+ ssColorBack = new x3dom.fields.SFColorRGBA(material._backSpecularColor.r, material._backSpecularColor.g,
+ material._backSpecularColor.b, material._backShininess);
+
+ this.colorMap.setPixel(xFront, yFront, dtColorFront, false);
+ this.emissiveMap.setPixel(xFront, yFront, eaColorFront, false);
+ this.specularMap.setPixel(xFront, yFront, ssColorFront, false);
+
+ this.colorMap.setPixel(xBack, yBack, dtColorBack, false);
+ this.emissiveMap.setPixel(xBack, yBack, eaColorBack, false);
+ this.specularMap.setPixel(xBack, yBack, ssColorBack, true);
+ }
+ }
+ };
+
+ /**
+ *
+ * @param visibility
+ */
+ this.setVisibility = function(visibility) {
+
+ var i, j, x, y, usage, visibleCount, visibilityAsInt;
+
+ if (!(ids.length && ids.length > 1)) {
+ x = parts.ids[0] % parts.colorMap.getWidth();
+ y = Math.floor(parts.ids[0] / parts.colorMap.getWidth());
+
+ var pixel = parts.visibilityMap.getPixel(x, y);
+
+ visibilityAsInt = (visibility) ? 1 : 0;
+
+ if (pixel.r != visibilityAsInt) {
+ pixel.r = visibilityAsInt;
+
+ this.multiPart._partVisibility[parts.ids[0]] = visibility;
+
+ //get used shapes
+ usage = this.multiPart._idMap.mapping[parts.ids[0]].usage;
+
+ //Change the shapes render flag
+ for (j = 0; j < usage.length; j++) {
+ visibleCount = this.multiPart._visiblePartsPerShape[usage[j]];
+ if (visibility && visibleCount.val < visibleCount.max) {
+ visibleCount.val++;
+ } else if (!visibility && visibleCount.val > 0) {
+ visibleCount.val--;
+ }
+
+ if (visibleCount.val) {
+ this.multiPart._inlineNamespace.defMap[usage[j]]._vf.render = true;
+ } else {
+ this.multiPart._inlineNamespace.defMap[usage[j]]._vf.render = false;
+ }
+ }
+ }
+
+ parts.visibilityMap.setPixel(x, y, pixel);
+ this.multiPart.invalidateVolume();
+ }
+ else
+ {
+ var pixels = parts.visibilityMap.getPixels();
+
+ for (i = 0; i < parts.ids.length; i++) {
+
+ visibilityAsInt = (visibility) ? 1 : 0;
+
+ if (pixels[parts.ids[i]].r != visibilityAsInt) {
+ pixels[parts.ids[i]].r = visibilityAsInt;
+
+ this.multiPart._partVisibility[parts.ids[i]] = visibility;
+
+ //get used shapes
+ usage = this.multiPart._idMap.mapping[parts.ids[i]].usage;
+
+ //Change the shapes render flag
+ for (j = 0; j < usage.length; j++) {
+ visibleCount = this.multiPart._visiblePartsPerShape[usage[j]];
+ if (visibility && visibleCount.val < visibleCount.max) {
+ visibleCount.val++;
+ } else if (!visibility && visibleCount.val > 0) {
+ visibleCount.val--;
+ }
+
+ if (visibleCount.val) {
+ this.multiPart._inlineNamespace.defMap[usage[j]]._vf.render = true;
+ } else {
+ this.multiPart._inlineNamespace.defMap[usage[j]]._vf.render = false;
+ }
+ }
+ }
+ }
+
+ parts.visibilityMap.setPixels(pixels);
+ this.multiPart.invalidateVolume();
+ }
+ };
+
+
+ /**
+ * get bounding volume
+ *
+ */
+ this.getVolume = function() {
+
+ var volume;
+ var transmat = this.multiPart.getCurrentTransform();
+
+ if (ids.length && ids.length > 1) //Multi select
+ {
+ volume = new x3dom.fields.BoxVolume();
+
+ for(var i=0; i<parts.ids.length; i++) {
+ volume.extendBounds(this.multiPart._partVolume[parts.ids[i]].min, this.multiPart._partVolume[parts.ids[i]].max);
+ }
+
+ volume.transform(transmat);
+
+ return volume;
+ }
+ else
+ {
+ volume = x3dom.fields.BoxVolume.copy(this.multiPart._partVolume[parts.ids[0]]);
+ volume.transform(transmat);
+ return volume;
+ }
+ };
+
+ /**
+ * Fit the selected Parts to the screen
+ * @param updateCenterOfRotation
+ */
+ this.fit = function (updateCenterOfRotation) {
+
+ var volume = this.getVolume();
+
+ this.multiPart._nameSpace.doc._viewarea.fit(volume.min, volume.max, updateCenterOfRotation);
+ };
+};
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+x3dom.Properties = function() {
+ this.properties = {};
+};
+
+x3dom.Properties.prototype.setProperty = function(name, value) {
+ x3dom.debug.logInfo("Properties: Setting property '"+ name + "' to value '" + value + "'");
+ this.properties[name] = value;
+};
+
+x3dom.Properties.prototype.getProperty = function(name, def) {
+ if (this.properties[name]) {
+ return this.properties[name]
+ } else {
+ return def;
+ }
+};
+
+x3dom.Properties.prototype.merge = function(other) {
+ for (var attrname in other.properties) {
+ this.properties[attrname] = other.properties[attrname];
+ }
+};
+
+x3dom.Properties.prototype.toString = function() {
+ var str = "";
+ for (var name in this.properties) {
+ str += "Name: " + name + " Value: " + this.properties[name] + "\n";
+ }
+ return str;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+x3dom.DoublyLinkedList = function() {
+ this.length = 0;
+ this.first = null;
+ this.last = null;
+};
+
+x3dom.DoublyLinkedList.ListNode = function(point, point_index, normals, colors, texCoords) {
+ this.point = point;
+ this.point_index = point_index;
+ this.normals = normals;
+ this.colors = colors;
+ this.texCoords = texCoords;
+ this.next = null;
+ this.prev = null;
+};
+
+x3dom.DoublyLinkedList.prototype.appendNode = function(node) {
+ if (this.first === null) {
+ node.prev = node;
+ node.next = node;
+ this.first = node;
+ this.last = node;
+ } else {
+ node.prev = this.last;
+ node.next = this.first;
+ this.first.prev = node;
+ this.last.next = node;
+ this.last = node;
+ }
+ this.length++;
+};
+
+x3dom.DoublyLinkedList.prototype.insertAfterNode = function(node, newNode) {
+ newNode.prev = node;
+ newNode.next = node.next;
+ node.next.prev = newNode;
+ node.next = newNode;
+ if (newNode.prev == this.last) {
+ this.last = newNode;
+ }
+ this.length++;
+};
+
+x3dom.DoublyLinkedList.prototype.deleteNode = function(node) {
+ if (this.length > 1) {
+ node.prev.next = node.next;
+ node.next.prev = node.prev;
+ if (node == this.first) {
+ this.first = node.next;
+ }
+ if (node == this.last) {
+ this.last = node.prev;
+ }
+ } else {
+ this.first = null;
+ this.last = null;
+ }
+ node.prev = null;
+ node.next = null;
+ this.length--;
+};
+
+x3dom.DoublyLinkedList.prototype.getNode = function(index) {
+ var node = null;
+ if(index > this.length) {
+ return node;
+ }
+ for(var i = 0; i < this.length; i++) {
+ if(i == 0) {
+ node = this.first;
+ } else {
+ node = node.next;
+ }
+ if(i == index) {
+ return node;
+ }
+ }
+ return null;
+};
+
+x3dom.DoublyLinkedList.prototype.invert = function() {
+ var tmp = null;
+ var node = this.first;
+
+ for(var i = 0; i < this.length; i++) {
+ tmp = node.prev;
+ node.prev = node.next;
+ node.next = tmp;
+ node = node.prev;
+ }
+ tmp = this.first;
+ this.first = this.last;
+ this.last = tmp;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+x3dom.EarClipping = {
+
+ reversePointDirection: function (linklist, plane) {
+ var l, k;
+ var count = 0;
+ var z = 0;
+ var nodei, nodel, nodek;
+
+ if (linklist.length < 3) {
+ return false;
+ }
+
+ for (var i = 0; i < linklist.length; i++) {
+ l = (i + 1) % linklist.length;
+ k = (i + 2) % linklist.length;
+
+ nodei = linklist.getNode(i);
+ nodel = linklist.getNode(l);
+ nodek = linklist.getNode(k);
+
+ if(plane == 'YZ') {
+ z = (nodel.point.y - nodei.point.y) * (nodek.point.z - nodel.point.z);
+ z -= (nodel.point.z - nodei.point.z) * (nodek.point.y - nodel.point.y);
+ } else if(plane == 'XZ') {
+ z = (nodel.point.z - nodei.point.z) * (nodek.point.x - nodel.point.x);
+ z -= (nodel.point.x - nodei.point.x) * (nodek.point.z - nodel.point.z);
+ } else {
+ z = (nodel.point.x - nodei.point.x) * (nodek.point.y - nodel.point.y);
+ z -= (nodel.point.y - nodei.point.y) * (nodek.point.x - nodel.point.x);
+ }
+
+ if (z < 0) {
+ count--;
+ } else {
+ count++;
+ }
+ }
+
+ if (count < 0) {
+ linklist.invert();
+ return true;
+ }
+ return false;
+ },
+
+ getIndexes: function (linklist) {
+ var node = linklist.first.next;
+ var plane = this.identifyPlane(node.prev.point, node.point, node.next.point);
+
+ var invers = this.reversePointDirection(linklist, plane);
+ var indexes = [];
+ node = linklist.first.next;
+ var next = null;
+ var count = 0;
+
+ var isEar = true;
+
+ while(linklist.length >= 3 && count < 15) {
+ next = node.next;
+ for(var i = 0; i < linklist.length; i++) {
+ if(this.isNotEar(linklist.getNode(i).point, node.prev.point, node.point, node.next.point, plane)) {
+ isEar = false;
+ }
+ }
+
+ if(isEar) {
+ if(this.isKonvex(node.prev.point, node.point, node.next.point, plane)) {
+ indexes.push(node.prev.point_index, node.point_index, node.next.point_index);
+ linklist.deleteNode(node);
+ } else {
+ count++;
+ }
+ }
+
+ node = next;
+ isEar = true;
+ }
+ if(invers){
+ return indexes.reverse();
+ } else {
+ return indexes;
+ }
+ },
+
+ getMultiIndexes: function (linklist) {
+ var node = linklist.first.next;
+ var plane = this.identifyPlane(node.prev.point, node.point, node.next.point);
+ var invers = this.reversePointDirection(linklist, plane);
+
+ var data = {};
+ data.indices = [];
+ data.point = [];
+ data.normals = [];
+ data.colors = [];
+ data.texCoords = [];
+ node = linklist.first.next;
+ var next = null;
+ var count = 0;
+
+ var isEar = true;
+ while(linklist.length >= 3 && count < 15) {
+
+ next = node.next;
+ for(var i = 0; i < linklist.length; i++) {
+
+ if(this.isNotEar(linklist.getNode(i).point, node.prev.point, node.point, node.next.point, plane)) {
+ isEar = false;
+ }
+ }
+ if(isEar) {
+
+ if(this.isKonvex(node.prev.point, node.point, node.next.point, plane)) {
+ data.indices.push(node.prev.point_index, node.point_index, node.next.point_index);
+ data.point.push(node.prev.point,
+ node.point,
+ node.next.point);
+ if(node.normals) {
+ data.normals.push(node.prev.normals,
+ node.normals,
+ node.next.normals);
+
+ }
+ if(node.colors){
+ data.colors.push(node.prev.colors,
+ node.colors,
+ node.next.colors);
+ }
+ if(node.texCoords){
+ data.texCoords.push(node.prev.texCoords,
+ node.texCoords,
+ node.next.texCoords);
+ }
+ linklist.deleteNode(node);
+ } else {
+ count++;
+ }
+ }
+
+ node = next;
+ isEar = true;
+ }
+
+ if(invers){
+ data.indices = data.indices.reverse();
+ data.point = data.point.reverse();
+ data.normals = data.normals.reverse();
+ data.colors = data.colors.reverse();
+ data.texCoords = data.texCoords.reverse();
+ }
+
+ return data;
+ },
+
+ isNotEar: function (ap1, tp1, tp2, tp3, plane) {
+ var b0, b1, b2, b3;
+ var ap1a, ap1b, tp1a, tp1b, tp2a, tp2b, tp3a, tp3b;
+
+ if(plane == 'YZ') {
+ ap1a = ap1.y; ap1b = ap1.z;
+ tp1a = tp1.y; tp1b = tp1.z;
+ tp2a = tp2.y; tp2b = tp2.z;
+ tp3a = tp3.y; tp3b = tp3.z;
+ } else if(plane == 'XZ') {
+ ap1a = ap1.z; ap1b = ap1.x;
+ tp1a = tp1.z; tp1b = tp1.x;
+ tp2a = tp2.z; tp2b = tp2.x;
+ tp3a = tp3.z; tp3b = tp3.x;
+ } else {
+ ap1a = ap1.x; ap1b = ap1.y;
+ tp1a = tp1.x; tp1b = tp1.y;
+ tp2a = tp2.x; tp2b = tp2.y;
+ tp3a = tp3.x; tp3b = tp3.y;
+ }
+
+ b0 = ((tp2a - tp1a) * (tp3b - tp1b) - (tp3a - tp1a) * (tp2b - tp1b));
+ if (b0 != 0) {
+ b1 = (((tp2a - ap1a) * (tp3b - ap1b) - (tp3a - ap1a) * (tp2b - ap1b)) / b0);
+ b2 = (((tp3a - ap1a) * (tp1b - ap1b) - (tp1a - ap1a) * (tp3b - ap1b)) / b0);
+ b3 = 1 - b1 - b2;
+
+ return ((b1 > 0) && (b2 > 0) && (b3 > 0));
+ }
+ else {
+ return false;
+ }
+ },
+
+ isKonvex: function (p, p1, p2, plane) {
+ var pa, pb, p1a, p1b, p2a, p2b;
+ if(plane == 'YZ') {
+ pa = p.y; pb = p.z;
+ p1a = p1.y; p1b = p1.z;
+ p2a = p2.y; p2b = p2.z;
+ } else if(plane == 'XZ') {
+ pa = p.z; pb = p.x;
+ p1a = p1.z; p1b = p1.x;
+ p2a = p2.z; p2b = p2.x;
+ } else {
+ pa = p.x; pb = p.y;
+ p1a = p1.x; p1b = p1.y;
+ p2a = p2.x; p2b = p2.y;
+ }
+
+ var l = ((p1a - pa) * (p2b - pb) - (p1b - pb) * (p2a - pa));
+ return (l >= 0);
+ },
+
+ identifyPlane: function(p1, p2, p3) {
+ var v1x, v1y, v1z;
+ var v2x, v2y, v2z;
+ var v3x, v3y, v3z;
+
+ v1x = p2.x - p1.x; v1y = p2.y - p1.y; v1z = p2.z - p1.z;
+ v2x = p3.x - p1.x; v2y = p3.y - p1.y; v2z = p3.z - p1.z;
+
+ v3x = Math.abs(v1y*v2z - v1z*v2y);
+ v3y = Math.abs(v1z*v2x - v1x*v2z);
+ v3z = Math.abs(v1x*v2y - v1y*v2x);
+
+ var angle = Math.max(v3x, v3y, v3z);
+
+ if(angle == v3x) {
+ return 'YZ';
+ } else if(angle == v3y) {
+ return 'XZ';
+ } else if(angle == v3z) {
+ return 'XY';
+ } else {
+ return 'XZ'; // error
+ }
+ }
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/*****************************************************************************
+* Utils class holds utility functions for renderer
+*****************************************************************************/
+x3dom.Utils = {};
+
+x3dom.Utils.maxIndexableCoords = 65535;
+x3dom.Utils.needLineWidth = false; // lineWidth not impl. in IE11
+x3dom.Utils.measurements = [];
+
+
+// http://gent.ilcore.com/2012/06/better-timer-for-javascript.html
+window.performance = window.performance || {};
+performance.now = (function () {
+ return performance.now ||
+ performance.mozNow ||
+ performance.msNow ||
+ performance.oNow ||
+ performance.webkitNow ||
+ function () {
+ return new Date().getTime();
+ };
+})();
+
+x3dom.Utils.startMeasure = function (name) {
+ var uname = name.toUpperCase();
+ if (!x3dom.Utils.measurements[uname]) {
+ if (performance && performance.now) {
+ x3dom.Utils.measurements[uname] = performance.now();
+ } else {
+ x3dom.Utils.measurements[uname] = new Date().getTime();
+ }
+ }
+};
+
+x3dom.Utils.stopMeasure = function (name) {
+ var uname = name.toUpperCase();
+ if (x3dom.Utils.measurements[uname]) {
+ var startTime = x3dom.Utils.measurements[uname];
+ delete x3dom.Utils.measurements[uname];
+ if (performance && performance.now) {
+ return performance.now() - startTime;
+ } else {
+ return new Date().getTime() - startTime;
+ }
+ }
+ return 0;
+};
+
+/*****************************************************************************
+ *
+ *****************************************************************************/
+x3dom.Utils.isNumber = function(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+};
+
+/*****************************************************************************
+*
+*****************************************************************************/
+x3dom.Utils.createTexture2D = function(gl, doc, src, bgnd, crossOrigin, scale, genMipMaps)
+{
+ var texture = gl.createTexture();
+
+ //Create a black 4 pixel texture to prevent 'texture not complete' warning
+ var data = new Uint8Array([0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255]);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
+ if (genMipMaps) {
+ gl.generateMipmap(gl.TEXTURE_2D);
+ }
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ texture.ready = false;
+
+ if (src == null || src == '')
+ return texture;
+
+ var image = new Image();
+
+ switch(crossOrigin.toLowerCase()) {
+ case 'anonymous': {
+ image.crossOrigin = 'anonymous';
+ } break;
+ case 'use-credentials': {
+ image.crossOrigin = 'use-credentials'
+ } break;
+ case 'none': {
+ //this is needed to omit the default case, if default is none, erase this and the default case
+ } break;
+ default: {
+ if(x3dom.Utils.forbiddenBySOP(src)) {
+ image.crossOrigin = 'anonymous';
+ }
+ }
+ }
+
+ image.src = src;
+
+ doc.downloadCount++;
+
+ image.onload = function() {
+ if (scale)
+ image = x3dom.Utils.scaleImage( image );
+
+ if(bgnd == true) {
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+ }
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ //gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+ if (genMipMaps) {
+ gl.generateMipmap(gl.TEXTURE_2D);
+ }
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ if(bgnd == true) {
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
+ }
+
+ //Save image size
+ texture.width = image.width;
+ texture.height = image.height;
+ texture.ready = true;
+
+ doc.downloadCount--;
+ doc.needRender = true;
+ };
+
+ image.onerror = function() {
+ x3dom.debug.logError("[Utils|createTexture2D] Can't load Image: " + src);
+ doc.downloadCount--;
+ };
+
+ return texture;
+};
+
+/*****************************************************************************
+*
+*****************************************************************************/
+x3dom.Utils.createTextureCube = function(gl, doc, src, bgnd, crossOrigin, scale, genMipMaps)
+{
+ var texture = gl.createTexture();
+
+ var faces;
+ if (bgnd) {
+ faces = [gl.TEXTURE_CUBE_MAP_POSITIVE_Z, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_X];
+ }
+ else
+ {
+ // back, front, bottom, top, left, right
+ faces = [gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_POSITIVE_X];
+ }
+
+ texture.ready = false;
+ texture.pendingTextureLoads = -1;
+ texture.textureCubeReady = false;
+
+ var width = 0, height = 0;
+
+ for (var i=0; i<faces.length; i++) {
+ var face = faces[i];
+
+ var image = new Image();
+
+ switch(crossOrigin.toLowerCase()) {
+ case 'anonymous': {
+ image.crossOrigin = 'anonymous';
+ } break;
+ case 'use-credentials': {
+ image.crossOrigin = 'use-credentials'
+ } break;
+ case 'none': {
+ //this is needed to omit the default case, if default is none, erase this and the default case
+ } break;
+ default: {
+ if(x3dom.Utils.forbiddenBySOP(src[i])) {
+ image.crossOrigin = 'anonymous';
+ }
+ }
+ }
+
+ texture.pendingTextureLoads++;
+ doc.downloadCount++;
+
+ image.onload = (function(texture, face, image, swap) {
+ return function() {
+ if (width == 0 && height == 0) {
+ width = image.width;
+ height = image.height;
+ }
+ else if (scale && (width != image.width || height != image.height)) {
+ x3dom.debug.logWarning("[Utils|createTextureCube] Rescaling CubeMap images, which are of different size!");
+ image = x3dom.Utils.rescaleImage(image, width, height);
+ }
+
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, swap);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
+ gl.texImage2D(face, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
+
+ texture.pendingTextureLoads--;
+ doc.downloadCount--;
+
+ if (texture.pendingTextureLoads < 0) {
+ //Save image size also for cube tex
+ texture.width = width;
+ texture.height = height;
+ texture.textureCubeReady = true;
+
+ if (genMipMaps) {
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
+ gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+ }
+
+ x3dom.debug.logInfo("[Utils|createTextureCube] Loading CubeMap finished...");
+ doc.needRender = true;
+ }
+ };
+ })( texture, face, image, bgnd );
+
+ image.onerror = function()
+ {
+ doc.downloadCount--;
+
+ x3dom.debug.logError("[Utils|createTextureCube] Can't load CubeMap!");
+ };
+
+ // backUrl, frontUrl, bottomUrl, topUrl, leftUrl, rightUrl (for bgnd)
+ image.src = src[i];
+ }
+
+ return texture;
+};
+
+/*****************************************************************************
+ * Initialize framebuffer object and associated texture(s)
+ *****************************************************************************/
+x3dom.Utils.initFBO = function(gl, w, h, type, mipMap, needRenderBuf, numMrt) {
+ var tex = gl.createTexture();
+ tex.width = w;
+ tex.height = h;
+
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, type, null);
+ if (mipMap)
+ gl.generateMipmap(gl.TEXTURE_2D);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ var i, mrts = null;
+
+ if (x3dom.caps.DRAW_BUFFERS && numMrt !== undefined) {
+ mrts = [ tex ];
+
+ for (i=1; i<numMrt; i++) {
+ mrts[i] = gl.createTexture();
+ mrts[i].width = w;
+ mrts[i].height = h;
+
+ gl.bindTexture(gl.TEXTURE_2D, mrts[i]);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, type, null);
+ if (mipMap)
+ gl.generateMipmap(gl.TEXTURE_2D);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+ }
+
+ var fbo = gl.createFramebuffer();
+ var rb = null;
+
+ if (needRenderBuf) {
+ rb = gl.createRenderbuffer();
+
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ }
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ if (x3dom.caps.DRAW_BUFFERS && numMrt !== undefined) {
+ for (i=1; i<numMrt; i++) {
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, mrts[i], 0);
+ }
+ }
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb);
+
+ var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (status != gl.FRAMEBUFFER_COMPLETE) {
+ x3dom.debug.logWarning("[Utils|InitFBO] FBO-Status: " + status);
+ }
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ return {
+ fbo: fbo, rbo: rb,
+ tex: tex, texTargets: mrts,
+ width: w, height: h,
+ type: type, mipMap: mipMap
+ };
+};
+
+/*****************************************************************************
+*
+*****************************************************************************/
+x3dom.Utils.getFileName = function(url)
+{
+ var filename;
+
+ if( url.lastIndexOf("/") > -1 ) {
+ filename = url.substr( url.lastIndexOf("/") + 1 );
+ }
+ else if( url.lastIndexOf("\\") > -1 ) {
+ filename = url.substr( url.lastIndexOf("\\") + 1 );
+ }
+ else {
+ filename = url;
+ }
+
+ return filename;
+};
+
+/*****************************************************************************
+*
+*****************************************************************************/
+x3dom.Utils.findTextureByName = function(texture, name)
+{
+ for ( var i=0; i<texture.length; ++i )
+ {
+ if ( name == texture[i].samplerName )
+ return texture[i];
+ }
+ return false;
+};
+
+/*****************************************************************************
+* Rescale image to given size
+*****************************************************************************/
+x3dom.Utils.rescaleImage = function(image, width, height)
+{
+ var canvas = document.createElement("canvas");
+ canvas.width = width; canvas.height = height;
+ canvas.getContext("2d").drawImage(image,
+ 0, 0, image.width, image.height,
+ 0, 0, canvas.width, canvas.height);
+ return canvas;
+};
+
+/*****************************************************************************
+* Scale image to next best power of two
+*****************************************************************************/
+x3dom.Utils.scaleImage = function(image)
+{
+ if (!x3dom.Utils.isPowerOfTwo(image.width) || !x3dom.Utils.isPowerOfTwo(image.height)) {
+ var canvas = document.createElement("canvas");
+ canvas.width = x3dom.Utils.nextHighestPowerOfTwo(image.width);
+ canvas.height = x3dom.Utils.nextHighestPowerOfTwo(image.height);
+ var ctx = canvas.getContext("2d");
+ ctx.drawImage(image,
+ 0, 0, image.width, image.height,
+ 0, 0, canvas.width, canvas.height);
+ image = canvas;
+ }
+ return image;
+};
+
+
+/*****************************************************************************
+* Check if value is power of two
+*****************************************************************************/
+x3dom.Utils.isPowerOfTwo = function(x)
+{
+ return ((x & (x - 1)) === 0);
+};
+
+
+/*****************************************************************************
+* Return next highest power of two
+*****************************************************************************/
+x3dom.Utils.nextHighestPowerOfTwo = function(x)
+{
+ --x;
+ for (var i = 1; i < 32; i <<= 1) {
+ x = x | x >> i;
+ }
+ return (x + 1);
+};
+
+
+/*****************************************************************************
+* Return next best power of two
+*****************************************************************************/
+x3dom.Utils.nextBestPowerOfTwo = function(x)
+{
+ // use precomputed log(2.0) = 0.693147180559945
+ var log2x = Math.log(x) / 0.693147180559945;
+ return Math.pow(2, Math.round(log2x));
+};
+
+/*****************************************************************************
+* Return data type size in byte
+*****************************************************************************/
+x3dom.Utils.getDataTypeSize = function(type)
+{
+ switch(type)
+ {
+ case "Int8":
+ case "Uint8":
+ return 1;
+ case "Int16":
+ case "Uint16":
+ return 2;
+ case "Int32":
+ case "Uint32":
+ case "Float32":
+ return 4;
+ case "Float64":
+ default:
+ return 8;
+ }
+};
+
+/*****************************************************************************
+ * Return offset multiplier (Uint32 is twice as big as Uint16)
+ *****************************************************************************/
+x3dom.Utils.getOffsetMultiplier = function(indexType, gl)
+{
+ switch(indexType)
+ {
+ case gl.UNSIGNED_SHORT:
+ return 1;
+ case gl.UNSIGNED_INT:
+ return 2;
+ case gl.UNSIGNED_BYTE:
+ return 0.5;
+ default:
+ return 1;
+ }
+};
+
+/*****************************************************************************
+ * Return byte aware offset
+ *****************************************************************************/
+x3dom.Utils.getByteAwareOffset = function(offset, indexType, gl)
+{
+ switch(indexType)
+ {
+ case gl.UNSIGNED_SHORT:
+ return 2 * offset;
+ case gl.UNSIGNED_INT:
+ return 4 * offset;
+ case gl.UNSIGNED_BYTE:
+ return offset;
+ default:
+ return 2 * offset;
+ }
+};
+
+/*****************************************************************************
+* Return this.gl-Type
+*****************************************************************************/
+x3dom.Utils.getVertexAttribType = function(type, gl)
+{
+ var dataType = gl.NONE;
+
+ switch(type)
+ {
+ case "Int8":
+ dataType = gl.BYTE;
+ break;
+ case "Uint8":
+ dataType = gl.UNSIGNED_BYTE;
+ break;
+ case "Int16":
+ dataType = gl.SHORT;
+ break;
+ case "Uint16":
+ dataType = gl.UNSIGNED_SHORT;
+ break;
+ case "Int32":
+ dataType = gl.INT;
+ break;
+ case "Uint32":
+ dataType = gl.UNSIGNED_INT;
+ break;
+ case "Float32":
+ dataType = gl.FLOAT;
+ break;
+ case "Float64":
+ default:
+ x3dom.debug.logError("Can't find this.gl data type for " + type + ", getting FLOAT...");
+ dataType = gl.FLOAT;
+ break;
+ }
+
+ return dataType;
+};
+
+/*****************************************************************************
+* Return TypedArray View
+*****************************************************************************/
+x3dom.Utils.getArrayBufferView = function(type, buffer)
+{
+ var array = null;
+
+ switch(type)
+ {
+ case "Int8":
+ array = new Int8Array(buffer);
+ break;
+ case "Uint8":
+ array = new Uint8Array(buffer);
+ break;
+ case "Int16":
+ array = new Int16Array(buffer);
+ break;
+ case "Uint16":
+ array = new Uint16Array(buffer);
+ break;
+ case "Int32":
+ array = new Int32Array(buffer);
+ break;
+ case "Uint32":
+ array = new Uint32Array(buffer);
+ break;
+ case "Float32":
+ array = new Float32Array(buffer);
+ break;
+ case "Float64":
+ array = new Float64Array(buffer);
+ break;
+ default:
+ x3dom.debug.logError("Can't create typed array view of type " + type + ", trying Float32...");
+ array = new Float32Array(buffer);
+ break;
+ }
+
+ return array;
+};
+
+/*****************************************************************************
+* Checks whether a TypedArray View Type with the given name string is unsigned
+*****************************************************************************/
+x3dom.Utils.isUnsignedType = function (str)
+{
+ return (str == "Uint8" || str == "Uint16" || str == "Uint16" || str == "Uint32");
+};
+
+
+/*****************************************************************************
+* Checks for lighting
+*****************************************************************************/
+x3dom.Utils.checkDirtyLighting = function(viewarea)
+{
+ return (viewarea.getLights().length + viewarea._scene.getNavigationInfo()._vf.headlight);
+};
+
+/*****************************************************************************
+ * Checks for environment
+ *****************************************************************************/
+x3dom.Utils.checkDirtyEnvironment = function(viewarea, shaderProperties)
+{
+ var environment = viewarea._scene.getEnvironment();
+
+ return (shaderProperties.GAMMACORRECTION != environment._vf.gammaCorrectionDefault);
+}
+
+/*****************************************************************************
+* Get GL min filter
+*****************************************************************************/
+x3dom.Utils.minFilterDic = function(gl, minFilter)
+{
+ switch(minFilter.toUpperCase())
+ {
+ case "NEAREST": return gl.NEAREST;
+ case "LINEAR": return gl.LINEAR;
+ case "NEAREST_MIPMAP_NEAREST": return gl.NEAREST_MIPMAP_NEAREST;
+ case "NEAREST_MIPMAP_LINEAR": return gl.NEAREST_MIPMAP_LINEAR;
+ case "LINEAR_MIPMAP_NEAREST": return gl.LINEAR_MIPMAP_NEAREST;
+ case "LINEAR_MIPMAP_LINEAR": return gl.LINEAR_MIPMAP_LINEAR;
+ case "AVG_PIXEL": return gl.LINEAR;
+ case "AVG_PIXEL_AVG_MIPMAP": return gl.LINEAR_MIPMAP_LINEAR;
+ case "AVG_PIXEL_NEAREST_MIPMAP": return gl.LINEAR_MIPMAP_NEAREST;
+ case "DEFAULT": return gl.LINEAR_MIPMAP_LINEAR;
+ case "FASTEST": return gl.NEAREST;
+ case "NEAREST_PIXEL": return gl.NEAREST;
+ case "NEAREST_PIXEL_AVG_MIPMAP": return gl.NEAREST_MIPMAP_LINEAR;
+ case "NEAREST_PIXEL_NEAREST_MIPMAP": return gl.NEAREST_MIPMAP_NEAREST;
+ case "NICEST": return gl.LINEAR_MIPMAP_LINEAR;
+ default: return gl.LINEAR;
+ }
+};
+
+/*****************************************************************************
+* Get GL mag filter
+*****************************************************************************/
+x3dom.Utils.magFilterDic = function(gl, magFilter)
+{
+ switch(magFilter.toUpperCase())
+ {
+ case "NEAREST": return gl.NEAREST;
+ case "LINEAR": return gl.LINEAR;
+ case "AVG_PIXEL": return gl.LINEAR;
+ case "DEFAULT": return gl.LINEAR;
+ case "FASTEST": return gl.NEAREST;
+ case "NEAREST_PIXEL": return gl.NEAREST;
+ case "NICEST": return gl.LINEAR;
+ default: return gl.LINEAR;
+ }
+};
+
+/*****************************************************************************
+* Get GL boundary mode
+*****************************************************************************/
+x3dom.Utils.boundaryModesDic = function(gl, mode)
+{
+ switch(mode.toUpperCase())
+ {
+ case "CLAMP": return gl.CLAMP_TO_EDGE;
+ case "CLAMP_TO_EDGE": return gl.CLAMP_TO_EDGE;
+ case "CLAMP_TO_BOUNDARY": return gl.CLAMP_TO_EDGE;
+ case "MIRRORED_REPEAT": return gl.MIRRORED_REPEAT;
+ case "REPEAT": return gl.REPEAT;
+ default: return gl.REPEAT;
+ }
+};
+
+/*****************************************************************************
+ * Get GL primitive type
+ *****************************************************************************/
+x3dom.Utils.primTypeDic = function(gl, type)
+{
+ switch(type.toUpperCase())
+ {
+ case "POINTS": return gl.POINTS;
+ case "LINES": return gl.LINES;
+ case "LINELOOP": return gl.LINE_LOOP;
+ case "LINESTRIP": return gl.LINE_STRIP;
+ case "TRIANGLES": return gl.TRIANGLES;
+ case "TRIANGLESTRIP": return gl.TRIANGLE_STRIP;
+ case "TRIANGLEFAN": return gl.TRIANGLE_FAN;
+ default: return gl.TRIANGLES;
+ }
+};
+
+/*****************************************************************************
+* Get GL depth function
+*****************************************************************************/
+x3dom.Utils.depthFunc = function(gl, func)
+{
+ switch(func.toUpperCase())
+ {
+ case "NEVER": return gl.NEVER;
+ case "ALWAYS": return gl.ALWAYS;
+ case "LESS": return gl.LESS;
+ case "EQUAL": return gl.EQUAL;
+ case "LEQUAL": return gl.LEQUAL;
+ case "GREATER": return gl.GREATER;
+ case "GEQUAL": return gl.GEQUAL;
+ case "NOTEQUAL": return gl.NOTEQUAL;
+ default: return gl.LEQUAL;
+ }
+};
+
+/*****************************************************************************
+ * Get GL blend function
+ *****************************************************************************/
+x3dom.Utils.blendFunc = function(gl, func)
+{
+ switch(func.toLowerCase())
+ {
+ case "zero": return gl.ZERO;
+ case "one": return gl.ONE;
+ case "dst_color": return gl.DST_COLOR;
+ case "dst_alpha": return gl.DST_ALPHA;
+ case "src_color": return gl.SRC_COLOR;
+ case "src_alpha": return gl.SRC_ALPHA;
+ case "one_minus_dst_color": return gl.ONE_MINUS_DST_COLOR;
+ case "one_minus_dst_alpha": return gl.ONE_MINUS_DST_ALPHA;
+ case "one_minus_src_color": return gl.ONE_MINUS_SRC_COLOR;
+ case "one_minus_src_alpha": return gl.ONE_MINUS_SRC_ALPHA;
+ case "src_alpha_saturate": return gl.SRC_ALPHA_SATURATE;
+ case "constant_color": return gl.CONSTANT_COLOR;
+ case "constant_alpha": return gl.CONSTANT_ALPHA;
+ case "one_minus_constant_color": return gl.ONE_MINUS_CONSTANT_COLOR;
+ case "one_minus_constant_alpha": return gl.ONE_MINUS_CONSTANT_ALPHA;
+ default: return 0;
+ }
+};
+
+/*****************************************************************************
+ * Get GL blend equations
+ *****************************************************************************/
+x3dom.Utils.blendEquation = function(gl, func)
+{
+ switch(func.toLowerCase())
+ {
+ case "func_add": return gl.FUNC_ADD;
+ case "func_subtract": return gl.FUNC_SUBTRACT;
+ case "func_reverse_subtract": return gl.FUNC_REVERSE_SUBTRACT;
+ case "min": return 0; //Not supported yet
+ case "max": return 0; //Not supported yet
+ case "logic_op": return 0; //Not supported yet
+ default: return 0;
+ }
+};
+
+/*****************************************************************************
+*
+*****************************************************************************/
+x3dom.Utils.generateProperties = function (viewarea, shape)
+{
+ var property = {};
+
+ var geometry = shape._cf.geometry.node;
+ var appearance = shape._cf.appearance.node;
+ var texture = appearance ? appearance._cf.texture.node : null;
+ var material = appearance ? appearance._cf.material.node : null;
+ var environment = viewarea._scene.getEnvironment();
+
+ //Check if it's a composed shader
+ if (appearance && appearance._shader &&
+ x3dom.isa(appearance._shader, x3dom.nodeTypes.ComposedShader)) {
+
+ property.CSHADER = appearance._shader._id; //shape._objectID;
+ }
+ else if (geometry) {
+
+ property.CSHADER = -1;
+ property.SOLID = (shape.isSolid()) ? 1 : 0;
+ property.TEXT = (x3dom.isa(geometry, x3dom.nodeTypes.Text)) ? 1 : 0;
+ property.POPGEOMETRY = (x3dom.isa(geometry, x3dom.nodeTypes.PopGeometry)) ? 1 : 0;
+ property.IMAGEGEOMETRY = (x3dom.isa(geometry, x3dom.nodeTypes.ImageGeometry)) ? 1 : 0;
+ property.BINARYGEOMETRY = (x3dom.isa(geometry, x3dom.nodeTypes.BinaryGeometry)) ? 1 : 0;
+ property.IG_PRECISION = (property.IMAGEGEOMETRY) ? geometry.numCoordinateTextures() : 0;
+ property.IG_INDEXED = (property.IMAGEGEOMETRY && geometry.getIndexTexture() != null) ? 1 : 0;
+ property.POINTLINE2D = !geometry.needLighting() ? 1 : 0;
+ property.VERTEXID = (property.BINARYGEOMETRY && geometry._vf.idsPerVertex) ? 1 : 0;
+ property.IS_PARTICLE = (x3dom.isa(geometry, x3dom.nodeTypes.ParticleSet)) ? 1 : 0;
+
+ property.APPMAT = (appearance && (material || property.CSSHADER) ) ? 1 : 0;
+ property.TWOSIDEDMAT = ( property.APPMAT && x3dom.isa(material, x3dom.nodeTypes.TwoSidedMaterial)) ? 1 : 0;
+ property.SEPARATEBACKMAT = ( property.TWOSIDEDMAT && material._vf.separateBackColor) ? 1 : 0;
+ property.SHADOW = (viewarea.getLightsShadow()) ? 1 : 0;
+ property.FOG = (viewarea._scene.getFog()._vf.visibilityRange > 0) ? 1 : 0;
+ property.CSSHADER = (appearance && appearance._shader &&
+ x3dom.isa(appearance._shader, x3dom.nodeTypes.CommonSurfaceShader)) ? 1 : 0;
+ property.LIGHTS = (!property.POINTLINE2D && appearance && shape.isLit() && (material || property.CSSHADER)) ?
+ viewarea.getLights().length + (viewarea._scene.getNavigationInfo()._vf.headlight) : 0;
+ property.TEXTURED = (texture || property.TEXT) ? 1 : 0;
+ property.PIXELTEX = (texture && x3dom.isa(texture, x3dom.nodeTypes.PixelTexture)) ? 1 : 0;
+ property.TEXTRAFO = (appearance && appearance._cf.textureTransform.node) ? 1 : 0;
+ property.DIFFUSEMAP = (property.CSSHADER && appearance._shader.getDiffuseMap()) ? 1 : 0;
+ property.NORMALMAP = (property.CSSHADER && appearance._shader.getNormalMap()) ? 1 : 0;
+ property.SPECMAP = (property.CSSHADER && appearance._shader.getSpecularMap()) ? 1 : 0;
+ property.SHINMAP = (property.CSSHADER && appearance._shader.getShininessMap()) ? 1 : 0;
+ property.DISPLACEMENTMAP = (property.CSSHADER && appearance._shader.getDisplacementMap()) ? 1 : 0;
+ property.DIFFPLACEMENTMAP = (property.CSSHADER && appearance._shader.getDiffuseDisplacementMap()) ? 1 : 0;
+ property.MULTIDIFFALPMAP = (property.VERTEXID && property.CSSHADER && appearance._shader.getMultiDiffuseAlphaMap()) ? 1 : 0;
+ property.MULTIEMIAMBMAP = (property.VERTEXID && property.CSSHADER && appearance._shader.getMultiEmissiveAmbientMap()) ? 1 : 0;
+ property.MULTISPECSHINMAP = (property.VERTEXID && property.CSSHADER && appearance._shader.getMultiSpecularShininessMap()) ? 1 : 0;
+ property.MULTIVISMAP = (property.VERTEXID && property.CSSHADER && appearance._shader.getMultiVisibilityMap()) ? 1 : 0;
+ property.CUBEMAP = (texture && x3dom.isa(texture, x3dom.nodeTypes.X3DEnvironmentTextureNode)) ? 1 : 0;
+ property.BLENDING = (property.TEXT || property.CUBEMAP || (texture && texture._blending)) ? 1 : 0;
+ property.REQUIREBBOX = (geometry._vf.coordType !== undefined && geometry._vf.coordType != "Float32") ? 1 : 0;
+ property.REQUIREBBOXNOR = (geometry._vf.normalType !== undefined && geometry._vf.normalType != "Float32") ? 1 : 0;
+ property.REQUIREBBOXCOL = (geometry._vf.colorType !== undefined && geometry._vf.colorType != "Float32") ? 1 : 0;
+ property.REQUIREBBOXTEX = (geometry._vf.texCoordType !== undefined && geometry._vf.texCoordType != "Float32") ? 1 : 0;
+ property.COLCOMPONENTS = geometry._mesh._numColComponents;
+ property.NORCOMPONENTS = geometry._mesh._numNormComponents;
+ property.POSCOMPONENTS = geometry._mesh._numPosComponents;
+ property.SPHEREMAPPING = (geometry._cf.texCoord !== undefined && geometry._cf.texCoord.node !== null &&
+ geometry._cf.texCoord.node._vf.mode &&
+ geometry._cf.texCoord.node._vf.mode.toLowerCase() == "sphere") ? 1 : 0;
+ property.VERTEXCOLOR = (geometry._mesh._colors[0].length > 0 ||
+ (property.IMAGEGEOMETRY && geometry.getColorTexture()) ||
+ (property.POPGEOMETRY && geometry.hasColor()) ||
+ (geometry._vf.color !== undefined && geometry._vf.color.length > 0)) ? 1 : 0;
+ property.CLIPPLANES = shape._clipPlanes.length;
+
+ property.GAMMACORRECTION = environment._vf.gammaCorrectionDefault;
+ }
+
+ property.toIdentifier = function() {
+ var id = "";
+ for(var p in this) {
+ if(this[p] != this.toIdentifier && this[p] != this.toString) {
+ id += this[p];
+ }
+ }
+ this.id = id;
+ return id;
+ };
+
+ property.toString = function() {
+ var str = "";
+ for(var p in this) {
+ if(this[p] != this.toIdentifier && this[p] != this.toString) {
+ str += p + ": " + this[p] + ", ";
+ }
+ }
+ return str;
+ };
+
+ property.toIdentifier();
+
+ return property;
+};
+
+
+/*****************************************************************************
+* Returns "shader" such that "shader.foo = [1,2,3]" magically sets the
+* appropriate uniform
+*****************************************************************************/
+x3dom.Utils.wrapProgram = function (gl, program, shaderID)
+{
+ var shader = {
+ shaderID: shaderID,
+ program: program
+ };
+
+ shader.bind = function () {
+ gl.useProgram(program);
+ };
+
+ var loc = null;
+ var obj = null;
+ var i, glErr;
+
+ // get uniforms
+ var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
+
+ for (i=0; i < numUniforms; ++i) {
+ try {
+ obj = gl.getActiveUniform(program, i);
+ }
+ catch (eu) {
+ if (!obj) continue;
+ }
+
+ glErr = gl.getError();
+ if (glErr) {
+ x3dom.debug.logError("GL-Error (on searching uniforms): " + glErr);
+ }
+
+ loc = gl.getUniformLocation(program, obj.name);
+
+ switch (obj.type) {
+ case gl.SAMPLER_2D:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform1i(loc, val); }; })(loc));
+ break;
+ case gl.SAMPLER_CUBE:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform1i(loc, val); }; })(loc));
+ break;
+ case gl.BOOL:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform1i(loc, val); }; })(loc));
+ break;
+ case gl.FLOAT:
+ /*
+ * Passing a MFFloat type into uniform.
+ * by Sofiane Benchaa, 2012.
+ *
+ * Based on OpenGL specification.
+ * url: http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocation.xml
+ *
+ * excerpt : Except if the last part of name indicates a uniform variable array,
+ * the location of the first element of an array can be retrieved by using the name of the array,
+ * or by using the name appended by "[0]".
+ *
+ * Detecting the float array and extracting its uniform name without the brackets.
+ */
+ if (obj.name.indexOf("[0]") != -1)
+ shader.__defineSetter__(obj.name.substring(0, obj.name.length-3),
+ (function (loc) { return function (val) { gl.uniform1fv(loc, new Float32Array(val)); }; })(loc));
+ else
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform1f(loc, val); }; })(loc));
+ break;
+ case gl.FLOAT_VEC2:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform2f(loc, val[0], val[1]); }; })(loc));
+ break;
+ case gl.FLOAT_VEC3:
+ /* Passing arrays of vec3. see above.*/
+ if (obj.name.indexOf("[0]") != -1)
+ shader.__defineSetter__(obj.name.substring(0, obj.name.length-3),
+ (function (loc) { return function (val) { gl.uniform3fv(loc, new Float32Array(val)); }; })(loc));
+ else
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform3f(loc, val[0], val[1], val[2]); }; })(loc));
+ break;
+ case gl.FLOAT_VEC4:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform4f(loc, val[0], val[1], val[2], val[3]); }; })(loc));
+ break;
+ case gl.FLOAT_MAT2:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniformMatrix2fv(loc, false, new Float32Array(val)); }; })(loc));
+ break;
+ case gl.FLOAT_MAT3:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniformMatrix3fv(loc, false, new Float32Array(val)); }; })(loc));
+ break;
+ case gl.FLOAT_MAT4:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniformMatrix4fv(loc, false, new Float32Array(val)); }; })(loc));
+ break;
+ case gl.INT:
+ shader.__defineSetter__(obj.name,
+ (function (loc) { return function (val) { gl.uniform1i(loc, val); }; }) (loc));
+ break;
+ default:
+ x3dom.debug.logWarning('GLSL program variable '+obj.name+' has unknown type '+obj.type);
+ }
+ }
+
+ // get attributes
+ var numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
+
+ for (i=0; i < numAttribs; ++i) {
+ try {
+ obj = gl.getActiveAttrib(program, i);
+ }
+ catch (ea) {
+ if (!obj) continue;
+ }
+
+ glErr = gl.getError();
+ if (glErr) {
+ x3dom.debug.logError("GL-Error (on searching attributes): " + glErr);
+ }
+
+ loc = gl.getAttribLocation(program, obj.name);
+ shader[obj.name] = loc;
+ }
+
+ return shader;
+};
+
+
+/**
+ * Matches a given URI with document.location. If domain, port and protocol are the same SOP won't forbid access to the resource.
+ * @param {String} uri_string
+ * @returns {boolean}
+ */
+x3dom.Utils.forbiddenBySOP = function (uri_string) {
+
+ uri_string = uri_string.toLowerCase();
+ // scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ var Scheme_AuthorityPQF = uri_string.split('//'); //Scheme and AuthorityPathQueryFragment
+ var Scheme;
+ var AuthorityPQF;
+ var Authority;
+ var UserInfo_HostPort;
+ var HostPort;
+ var Host_Port;
+ var Port;
+ var Host;
+ var originPort = document.location.port === "" ? "80" : document.location.port;
+
+ if (Scheme_AuthorityPQF.length === 2) { // if there is '//' authority is given;
+ Scheme = Scheme_AuthorityPQF[0];
+ AuthorityPQF = Scheme_AuthorityPQF[1];
+
+ /*
+ * The authority component is preceded by a double slash ("//") and is
+ * terminated by the next slash ("/"), question mark ("?"), or number
+ * sign ("#") character, or by the end of the URI.
+ */
+ Authority = AuthorityPQF.split('/')[0].split('?')[0].split('#')[0];
+
+ //authority = [ userinfo "@" ] host [ ":" port ]
+ UserInfo_HostPort = Authority.split('@');
+ if (UserInfo_HostPort.length === 1) { //No Userinfo given
+ HostPort = UserInfo_HostPort[0];
+ } else {
+ HostPort = UserInfo_HostPort[1];
+ }
+
+ Host_Port = HostPort.split(':');
+ Host = Host_Port[0];
+ Port = Host_Port[1];
+ } // else will return false for an invalid URL or URL without authority
+
+ Port = Port || "80";
+ Host = Host || document.location.host;
+ Scheme = Scheme || document.location.protocol;
+ return !(Port === originPort && Host === document.location.host && Scheme === document.location.protocol);
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * States namespace
+ */
+x3dom.States = function (x3dElem) {
+ var that = this;
+ this.active = false;
+
+ this.viewer = document.createElement('div');
+ this.viewer.id = 'x3dom-state-viewer';
+
+ var title = document.createElement('div');
+ title.className = 'x3dom-states-head';
+ title.appendChild(document.createTextNode('x3dom'));
+
+ var subTitle = document.createElement('span');
+ subTitle.className = 'x3dom-states-head2';
+ subTitle.appendChild(document.createTextNode('stats'));
+ title.appendChild(subTitle);
+
+ this.renderMode = document.createElement('div');
+ this.renderMode.className = 'x3dom-states-rendermode-hardware';
+
+ this.measureList = document.createElement('ul');
+ this.measureList.className = 'x3dom-states-list';
+
+ this.infoList = document.createElement('ul');
+ this.infoList.className = 'x3dom-states-list';
+
+ //this.viewer.appendChild(title);
+ this.viewer.appendChild(this.renderMode);
+ this.viewer.appendChild(this.measureList);
+ this.viewer.appendChild(this.infoList);
+
+ /**
+ * Disable the context menu
+ */
+ this.disableContextMenu = function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ e.returnValue = false;
+ return false;
+ };
+
+ /**
+ * Add a seperator for thousands to the string
+ */
+ this.thousandSeperator = function (value) {
+ return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+ };
+
+ /**
+ * Return numerical value to fixed length
+ */
+ this.toFixed = function (value) {
+ var fixed = (value < 1) ? 2 : (value < 10) ? 2 : 2;
+ return value.toFixed(fixed);
+ };
+
+ /**
+ * Update the states.
+ */
+ this.update = function () {
+ if (!x3dElem.runtime && this.updateMethodID !== undefined) {
+ clearInterval(this.updateMethodID);
+ return;
+ }
+
+ var infos = x3dElem.runtime.states.infos;
+ var measurements = x3dElem.runtime.states.measurements;
+
+ var renderMode = x3dom.caps.RENDERMODE;
+
+ if ( renderMode == "HARDWARE" ) {
+ this.renderMode.innerHTML = "Hardware-Rendering";
+ this.renderMode.className = 'x3dom-states-rendermode-hardware';
+ } else if ( renderMode == "SOFTWARE" ) {
+ this.renderMode.innerHTML = "Software-Rendering";
+ this.renderMode.className = 'x3dom-states-rendermode-software';
+ }
+
+
+ //Clear measure list
+ this.measureList.innerHTML = "";
+
+ //Create list items
+ for (var m in measurements) {
+ infoItem = document.createElement('li');
+ infoItem.className = 'x3dom-states-item';
+
+ infoTitle = document.createElement('div');
+ infoTitle.className = 'x3dom-states-item-title';
+ infoTitle.appendChild(document.createTextNode(m));
+
+ infoValue = document.createElement('div');
+ infoValue.className = 'x3dom-states-item-value';
+ infoValue.appendChild(document.createTextNode(this.toFixed(measurements[m])));
+
+ infoItem.appendChild(infoTitle);
+ infoItem.appendChild(infoValue);
+
+ this.measureList.appendChild(infoItem);
+ }
+
+ //Clear info list
+ this.infoList.innerHTML = "";
+
+ //Create list items
+ for (var i in infos) {
+ var infoItem = document.createElement('li');
+ infoItem.className = 'x3dom-states-item';
+
+ var infoTitle = document.createElement('div');
+ infoTitle.className = 'x3dom-states-item-title';
+ infoTitle.appendChild(document.createTextNode(i));
+
+ var infoValue = document.createElement('div');
+ infoValue.className = 'x3dom-states-item-value';
+ infoValue.appendChild(document.createTextNode(this.thousandSeperator(infos[i])));
+
+ infoItem.appendChild(infoTitle);
+ infoItem.appendChild(infoValue);
+
+ this.infoList.appendChild(infoItem);
+ }
+ };
+
+ this.updateMethodID = window.setInterval(function () {
+ that.update();
+ }, 1000);
+
+ this.viewer.addEventListener("contextmenu", that.disableContextMenu);
+};
+
+/**
+ * Display the states
+ */
+x3dom.States.prototype.display = function (value) {
+ this.active = (value !== undefined) ? value : !this.active;
+ this.viewer.style.display = (this.active) ? "block" : "none";
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Manage all the GL-States and try to reduce the state changes
+ */
+x3dom.StateManager = function (ctx3d)
+{
+ //Our GL-Context
+ this.gl = ctx3d;
+
+ //Hold all the active states
+ this.states = [];
+
+ //Initialize States
+ this.initStates();
+};
+
+/*
+ * Initialize States
+ */
+x3dom.StateManager.prototype.initStates = function ()
+{
+ //Initialize Shader states
+ this.states['shaderID'] = null;
+
+ //Initialize Framebuffer-Operation states
+ this.states['colorMask'] = {red: null, green: null, blue: null, alpha: null};
+ this.states['depthMask'] = null;
+ this.states['stencilMask'] = null;
+
+ //Initialize Rasterization states
+ this.states['cullFace'] = null;
+ this.states['frontFace'] = null;
+ this.states['lineWidth'] = null;
+
+ //Initialize Per-Fragment-Operation states
+ this.states['blendColor'] = {red: null, green: null, blue: null, alpha: null};
+ this.states['blendEquation'] = null;
+ this.states['blendEquationSeparate'] = {modeRGB: null, modeAlpha: null};
+ this.states['blendFunc'] = {sfactor: null, dfactor: null};
+ this.states['blendFuncSeparate'] = {srcRGB: null, dstRGB: null, srcAlpha: null, dstAlpha: null};
+ this.states['depthFunc'] = null;
+
+ //Initialize View and Clip states
+ this.states['viewport'] = {x: null, y: null, width: null, height: null};
+ this.states['depthRange'] = {zNear: null, zFar: null};
+
+ //TODO more states (e.g. stencil, texture, ...)
+};
+
+/*
+ * Only bind program if different (returns true if changed)
+ */
+x3dom.StateManager.prototype.useProgram = function (shader)
+{
+ if (this.states['shaderID'] != shader.shaderID)
+ {
+ this.gl.useProgram(shader.program);
+ this.states['shaderID'] = shader.shaderID;
+ return true;
+ }
+ return false;
+};
+
+/*
+ * Unset active program for clean init state
+ */
+x3dom.StateManager.prototype.unsetProgram = function ()
+{
+ this.states['shaderID'] = null;
+};
+
+/*
+ * Enable GL capabilities
+ */
+x3dom.StateManager.prototype.enable = function (cap)
+{
+ if (this.states[cap] !== true)
+ {
+ this.gl.enable(cap);
+ this.states[cap] = true;
+ }
+};
+
+/*
+ * Disable GL capabilities
+ */
+x3dom.StateManager.prototype.disable = function (cap)
+{
+ if (this.states[cap] !== false)
+ {
+ this.gl.disable(cap);
+ this.states[cap] = false;
+ }
+};
+
+/*
+ * Enable and disable writing of frame buffer color components
+ */
+x3dom.StateManager.prototype.colorMask = function (red, green, blue, alpha)
+{
+ if (this.states['colorMask'].red != red ||
+ this.states['colorMask'].green != green ||
+ this.states['colorMask'].blue != blue ||
+ this.states['colorMask'].alpha != alpha)
+ {
+ this.gl.colorMask(red, green, blue, alpha);
+ this.states['colorMask'].red = red;
+ this.states['colorMask'].green = green;
+ this.states['colorMask'].blue = blue;
+ this.states['colorMask'].alpha = alpha;
+ }
+};
+
+/*
+ * Sets whether or not you can write to the depth buffer.
+ */
+x3dom.StateManager.prototype.depthMask = function (flag)
+{
+ if (this.states['depthMask'] != flag)
+ {
+ this.gl.depthMask(flag);
+ this.states['depthMask'] = flag;
+ }
+};
+
+/*
+ * Control the front and back writing of individual bits in the stencil planes
+ */
+x3dom.StateManager.prototype.stencilMask = function (mask)
+{
+ if (this.states['stencilMask'] != mask)
+ {
+ this.gl.stencilMask(mask);
+ this.states['stencilMask'] = mask;
+ }
+};
+
+/*
+ * Specify whether front- or back-facing facets can be culled
+ */
+x3dom.StateManager.prototype.cullFace = function (mode)
+{
+ if (this.states['cullFace'] != mode)
+ {
+ this.gl.cullFace(mode);
+ this.states['cullFace'] = mode;
+ }
+};
+
+/*
+ * Define front- and back-facing polygons
+ */
+x3dom.StateManager.prototype.frontFace = function (mode)
+{
+ if (this.states['frontFace'] != mode)
+ {
+ this.gl.frontFace(mode);
+ this.states['frontFace'] = mode;
+ }
+};
+
+/*
+ * Specify the width of rasterized lines
+ */
+x3dom.StateManager.prototype.lineWidth = function (width)
+{
+ width = (width <= 1) ? 1 : width;
+
+ if (this.states['lineWidth'] != width)
+ {
+ this.gl.lineWidth(width);
+ this.states['lineWidth'] = width;
+ }
+};
+
+/*
+ * Set the blend color
+ */
+x3dom.StateManager.prototype.blendColor = function (red, green, blue, alpha)
+{
+ if (this.states['blendColor'].red != red ||
+ this.states['blendColor'].green != green ||
+ this.states['blendColor'].blue != blue ||
+ this.states['blendColor'].alpha != alpha)
+ {
+ this.gl.blendColor(red, green, blue, alpha);
+ this.states['blendColor'].red = red;
+ this.states['blendColor'].green = green;
+ this.states['blendColor'].blue = blue;
+ this.states['blendColor'].alpha = alpha;
+ }
+};
+
+/*
+ * Specify the equation used for both the RGB blend equation and the Alpha blend equation
+ */
+x3dom.StateManager.prototype.blendEquation = function (mode)
+{
+ if (mode && this.states['blendEquation'] != mode)
+ {
+ this.gl.blendEquation(mode);
+ this.states['blendEquation'] = mode;
+ }
+};
+
+/*
+ * set the RGB blend equation and the alpha blend equation separately
+ */
+x3dom.StateManager.prototype.blendEquationSeparate = function (modeRGB, modeAlpha)
+{
+ if (this.states['blendEquationSeparate'].modeRGB != modeRGB ||
+ this.states['blendEquationSeparate'].modeAlpha != modeAlpha)
+ {
+ this.gl.blendEquationSeparate(modeRGB, modeAlpha);
+ this.states['blendEquationSeparate'].modeRGB = modeRGB;
+ this.states['blendEquationSeparate'].modeAlpha = modeAlpha;
+ }
+};
+
+/*
+ * Specify pixel arithmetic
+ */
+x3dom.StateManager.prototype.blendFunc = function (sfactor, dfactor)
+{
+ if (this.states['blendFunc'].sfactor != sfactor ||
+ this.states['blendFunc'].dfactor != dfactor)
+ {
+ this.gl.blendFunc(sfactor, dfactor);
+ this.states['blendFunc'].sfactor = sfactor;
+ this.states['blendFunc'].dfactor = dfactor;
+ }
+};
+
+/*
+ * Specify pixel arithmetic for RGB and alpha components separately
+ */
+x3dom.StateManager.prototype.blendFuncSeparate = function (srcRGB, dstRGB, srcAlpha, dstAlpha)
+{
+ if (this.states['blendFuncSeparate'].srcRGB != srcRGB ||
+ this.states['blendFuncSeparate'].dstRGB != dstRGB ||
+ this.states['blendFuncSeparate'].srcAlpha != srcAlpha ||
+ this.states['blendFuncSeparate'].dstAlpha != dstAlpha)
+ {
+ this.gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ this.states['blendFuncSeparate'].srcRGB = srcRGB;
+ this.states['blendFuncSeparate'].dstRGB = dstRGB;
+ this.states['blendFuncSeparate'].srcAlpha = srcAlpha;
+ this.states['blendFuncSeparate'].dstAlpha = dstAlpha;
+ }
+};
+
+/*
+ * Specify the value used for depth buffer comparisons
+ */
+x3dom.StateManager.prototype.depthFunc = function (func)
+{
+ if (this.states['depthFunc'] != func)
+ {
+ this.gl.depthFunc(func);
+ this.states['depthFunc'] = func;
+ }
+};
+
+/*
+ * Specify the value used for depth buffer comparisons
+ */
+x3dom.StateManager.prototype.depthRange = function (zNear, zFar)
+{
+ if (zNear < 0 || zFar < 0 || zNear > zFar)
+ {
+ return; // do noting and leave default values
+ }
+
+ zNear = (zNear > 1) ? 1 : zNear;
+ zFar = (zFar > 1) ? 1 : zFar;
+
+ if (this.states['depthRange'].zNear != zNear || this.states['depthRange'].zFar != zFar)
+ {
+ this.gl.depthRange(zNear, zFar);
+ this.states['depthRange'].zNear = zNear;
+ this.states['depthRange'].zFar = zFar;
+ }
+};
+
+/*
+ * Set the viewport
+ */
+x3dom.StateManager.prototype.viewport = function (x, y, width, height)
+{
+ if (this.states['viewport'].x != x ||
+ this.states['viewport'].y != y ||
+ this.states['viewport'].width != width ||
+ this.states['viewport'].height != height)
+ {
+ this.gl.viewport(x, y, width, height);
+ this.states['viewport'].x = x;
+ this.states['viewport'].y = y;
+ this.states['viewport'].width = width;
+ this.states['viewport'].height = height;
+ }
+};
+
+/*
+ * Bind a framebuffer to a framebuffer target
+ */
+x3dom.StateManager.prototype.bindFramebuffer = function (target, framebuffer)
+{
+ this.gl.bindFramebuffer(target, framebuffer);
+ this.initStates();
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/** used from within gfx_webgl.js */
+x3dom.BinaryContainerLoader = {
+ outOfMemory: false, // try to prevent browser crashes
+
+ checkError: function(gl) {
+ var glErr = gl.getError();
+ if (glErr) {
+ if (glErr == gl.OUT_OF_MEMORY) {
+ this.outOfMemory = true;
+ x3dom.debug.logError("GL-Error " + glErr + " on loading binary container (out of memory).");
+ console.error("WebGL: OUT_OF_MEMORY");
+ }
+ else {
+ x3dom.debug.logError("GL-Error " + glErr + " on loading binary container.");
+ }
+ }
+ }
+};
+
+
+/** setup/download binary geometry */
+x3dom.BinaryContainerLoader.setupBinGeo = function(shape, sp, gl, viewarea, currContext)
+{
+ if (this.outOfMemory) {
+ return;
+ }
+
+ var t00 = new Date().getTime();
+ var that = this;
+
+ var binGeo = shape._cf.geometry.node;
+
+ // 0 := no BG, 1 := indexed BG, -1 := non-indexed BG
+ shape._webgl.binaryGeometry = -1;
+
+ shape._webgl.internalDownloadCount = ((binGeo._vf.index.length > 0) ? 1 : 0) +
+ ((binGeo._hasStrideOffset && binGeo._vf.coord.length > 0) ? 1 : 0) +
+ ((!binGeo._hasStrideOffset && binGeo._vf.coord.length > 0) ? 1 : 0) +
+ ((!binGeo._hasStrideOffset && binGeo._vf.normal.length > 0) ? 1 : 0) +
+ ((!binGeo._hasStrideOffset && binGeo._vf.texCoord.length > 0) ? 1 : 0) +
+ ((!binGeo._hasStrideOffset && binGeo._vf.color.length > 0) ? 1 : 0);
+
+ var createTriangleSoup = (binGeo._vf.normalPerVertex == false) ||
+ ((binGeo._vf.index.length > 0) && (binGeo._vf.indexType == "Int32" ||
+ (binGeo._vf.indexType == "Uint32" && !x3dom.caps.INDEX_UINT)));
+
+ shape._webgl.makeSeparateTris = {
+ index: null,
+ coord: null,
+ normal: null,
+ texCoord: null,
+ color: null,
+
+ pushBuffer: function(name, buf) {
+ this[name] = buf;
+
+ if (--shape._webgl.internalDownloadCount == 0) {
+ if (this.coord)
+ this.createMesh();
+ shape._nameSpace.doc.needRender = true;
+ }
+ if (--shape._nameSpace.doc.downloadCount == 0)
+ shape._nameSpace.doc.needRender = true;
+ },
+
+ createMesh: function() {
+ var geoNode = binGeo;
+
+ if (geoNode._hasStrideOffset) {
+ x3dom.debug.logError(geoNode._vf.indexType +
+ " index type and per-face normals not supported for interleaved arrays.");
+ return;
+ }
+
+ for (var k=0; k<shape._webgl.primType.length; k++) {
+ if (shape._webgl.primType[k] == gl.TRIANGLE_STRIP) {
+ x3dom.debug.logError("makeSeparateTris: triangle strips not yet supported for per-face normals.");
+ return;
+ }
+ }
+
+ var attribTypeStr = geoNode._vf.coordType;
+ shape._webgl.coordType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ // remap vertex data
+ var bgCenter, bgSize, bgPrecisionMax;
+
+ if (shape._webgl.coordType != gl.FLOAT)
+ {
+ if (geoNode._mesh._numPosComponents == 4 &&
+ x3dom.Utils.isUnsignedType(geoNode._vf.coordType))
+ bgCenter = x3dom.fields.SFVec3f.copy(geoNode.getMin());
+ else
+ bgCenter = x3dom.fields.SFVec3f.copy(geoNode._vf.position);
+
+ bgSize = x3dom.fields.SFVec3f.copy(geoNode._vf.size);
+ bgPrecisionMax = geoNode.getPrecisionMax('coordType');
+ }
+ else
+ {
+ bgCenter = new x3dom.fields.SFVec3f(0, 0, 0);
+ bgSize = new x3dom.fields.SFVec3f(1, 1, 1);
+ bgPrecisionMax = 1.0;
+ }
+
+ // check types
+ var dataLen = shape._coordStrideOffset[0] / x3dom.Utils.getDataTypeSize(geoNode._vf.coordType);
+ dataLen = (dataLen == 0) ? 3 : dataLen;
+
+ x3dom.debug.logWarning("makeSeparateTris.createMesh called with coord length " + dataLen);
+
+ if (this.color && dataLen != shape._colorStrideOffset[0] / x3dom.Utils.getDataTypeSize(geoNode._vf.colorType))
+ {
+ this.color = null;
+ x3dom.debug.logWarning("Color format not supported.");
+ }
+
+ var texDataLen = this.texCoord ? (shape._texCoordStrideOffset[0] /
+ x3dom.Utils.getDataTypeSize(geoNode._vf.texCoordType)) : 0;
+
+ // set data types
+ //geoNode._vf.coordType = "Float32";
+ geoNode._vf.normalType = "Float32";
+
+ //shape._webgl.coordType = gl.FLOAT;
+ shape._webgl.normalType = gl.FLOAT;
+
+ //geoNode._mesh._numPosComponents = 3;
+ geoNode._mesh._numNormComponents = 3;
+
+ //shape._coordStrideOffset = [0, 0];
+ shape._normalStrideOffset = [0, 0];
+
+ // create non-indexed mesh
+ var posBuf = [], normBuf = [], texcBuf = [], colBuf = [];
+ var i, j, l, n = this.index ? (this.index.length - 2) : (this.coord.length / 3 - 2);
+
+ for (i=0; i<n; i+=3)
+ {
+ j = dataLen * (this.index ? this.index[i] : i);
+ var p0 = new x3dom.fields.SFVec3f(bgSize.x * this.coord[j ] / bgPrecisionMax,
+ bgSize.y * this.coord[j+1] / bgPrecisionMax,
+ bgSize.z * this.coord[j+2] / bgPrecisionMax);
+ // offset irrelevant for normal calculation
+ //p0 = bgCenter.add(p0);
+
+ posBuf.push(this.coord[j ]);
+ posBuf.push(this.coord[j+1]);
+ posBuf.push(this.coord[j+2]);
+ if (dataLen > 3) posBuf.push(this.coord[j+3]);
+
+ if (this.color) {
+ colBuf.push(this.color[j ]);
+ colBuf.push(this.color[j+1]);
+ colBuf.push(this.color[j+2]);
+ if (dataLen > 3) colBuf.push(this.color[j+3]);
+ }
+
+ if (this.texCoord) {
+ l = texDataLen * (this.index ? this.index[i] : i);
+
+ texcBuf.push(this.texCoord[l ]);
+ texcBuf.push(this.texCoord[l+1]);
+ if (texDataLen > 3) {
+ texcBuf.push(this.texCoord[l+2]);
+ texcBuf.push(this.texCoord[l+3]);
+ }
+ }
+
+ j = dataLen * (this.index ? this.index[i+1] : i+1);
+ var p1 = new x3dom.fields.SFVec3f(bgSize.x * this.coord[j ] / bgPrecisionMax,
+ bgSize.y * this.coord[j+1] / bgPrecisionMax,
+ bgSize.z * this.coord[j+2] / bgPrecisionMax);
+ //p1 = bgCenter.add(p1);
+
+ posBuf.push(this.coord[j ]);
+ posBuf.push(this.coord[j+1]);
+ posBuf.push(this.coord[j+2]);
+ if (dataLen > 3) posBuf.push(this.coord[j+3]);
+
+ if (this.color) {
+ colBuf.push(this.color[j ]);
+ colBuf.push(this.color[j+1]);
+ colBuf.push(this.color[j+2]);
+ if (dataLen > 3) colBuf.push(this.color[j+3]);
+ }
+
+ if (this.texCoord) {
+ l = texDataLen * (this.index ? this.index[i+1] : i+1);
+
+ texcBuf.push(this.texCoord[l ]);
+ texcBuf.push(this.texCoord[l+1]);
+ if (texDataLen > 3) {
+ texcBuf.push(this.texCoord[l+2]);
+ texcBuf.push(this.texCoord[l+3]);
+ }
+ }
+
+ j = dataLen * (this.index ? this.index[i+2] : i+2);
+ var p2 = new x3dom.fields.SFVec3f(bgSize.x * this.coord[j ] / bgPrecisionMax,
+ bgSize.y * this.coord[j+1] / bgPrecisionMax,
+ bgSize.z * this.coord[j+2] / bgPrecisionMax);
+ //p2 = bgCenter.add(p2);
+
+ posBuf.push(this.coord[j ]);
+ posBuf.push(this.coord[j+1]);
+ posBuf.push(this.coord[j+2]);
+ if (dataLen > 3) posBuf.push(this.coord[j+3]);
+
+ if (this.color) {
+ colBuf.push(this.color[j ]);
+ colBuf.push(this.color[j+1]);
+ colBuf.push(this.color[j+2]);
+ if (dataLen > 3) colBuf.push(this.color[j+3]);
+ }
+
+ if (this.texCoord) {
+ l = texDataLen * (this.index ? this.index[i+2] : i+2);
+
+ texcBuf.push(this.texCoord[l ]);
+ texcBuf.push(this.texCoord[l+1]);
+ if (texDataLen > 3) {
+ texcBuf.push(this.texCoord[l+2]);
+ texcBuf.push(this.texCoord[l+3]);
+ }
+ }
+
+ var a = p0.subtract(p1);
+ var b = p1.subtract(p2);
+ var norm = a.cross(b).normalize();
+
+ for (j=0; j<3; j++) {
+ normBuf.push(norm.x);
+ normBuf.push(norm.y);
+ normBuf.push(norm.z);
+ }
+ }
+
+ // coordinates
+ var buffer = gl.createBuffer();
+ shape._webgl.buffers[1] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ x3dom.Utils.getArrayBufferView(geoNode._vf.coordType, posBuf), gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.position, geoNode._mesh._numPosComponents,
+ shape._webgl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ // normals
+ buffer = gl.createBuffer();
+ shape._webgl.buffers[2] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normBuf), gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.normal, geoNode._mesh._numNormComponents,
+ shape._webgl.normalType, false,
+ shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.normal);
+
+ // tex coords
+ if (this.texCoord)
+ {
+ buffer = gl.createBuffer();
+ shape._webgl.buffers[3] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ x3dom.Utils.getArrayBufferView(geoNode._vf.texCoordType, texcBuf),
+ gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.texcoord, geoNode._mesh._numTexComponents,
+ shape._webgl.texCoordType, false,
+ shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.texcoord);
+ }
+
+ // colors
+ if (this.color)
+ {
+ buffer = gl.createBuffer();
+ shape._webgl.buffers[4] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ x3dom.Utils.getArrayBufferView(geoNode._vf.colorType, colBuf),
+ gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.color, geoNode._mesh._numColComponents,
+ shape._webgl.colorType, false,
+ shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.color);
+ }
+
+ // adjust sizes
+ geoNode._vf.vertexCount = [];
+ geoNode._vf.vertexCount[0] = posBuf.length / dataLen;
+
+ geoNode._mesh._numCoords = geoNode._vf.vertexCount[0];
+ geoNode._mesh._numFaces = geoNode._vf.vertexCount[0] / 3;
+
+ shape._webgl.primType = [];
+ shape._webgl.primType[0] = gl.TRIANGLES;
+
+ // cleanup
+ posBuf = null;
+ normBuf = null;
+ texcBuf = null;
+ colBuf = null;
+
+ this.index = null;
+ this.coord = null;
+ this.normal = null;
+ this.texCoord = null;
+ this.color = null;
+
+ that.checkError(gl);
+
+ // recreate shader
+ delete shape._webgl.shader;
+ shape._webgl.shader = currContext.cache.getDynamicShader(gl, viewarea, shape);
+ }
+ };
+
+ // index
+ if (binGeo._vf.index.length > 0)
+ {
+ var xmlhttp0 = new XMLHttpRequest();
+ xmlhttp0.open("GET", shape._nameSpace.getURL(binGeo._vf.index), true);
+ xmlhttp0.responseType = "arraybuffer";
+
+ shape._nameSpace.doc.downloadCount += 1;
+
+ xmlhttp0.send(null);
+
+ xmlhttp0.onload = function()
+ {
+ if (!shape._webgl)
+ return;
+
+ var XHR_buffer = xmlhttp0.response;
+
+ var geoNode = binGeo;
+ var attribTypeStr = geoNode._vf.indexType; //"Uint16"
+
+ var indexArray = x3dom.Utils.getArrayBufferView(attribTypeStr, XHR_buffer);
+
+ if (createTriangleSoup) {
+ shape._webgl.makeSeparateTris.pushBuffer("index", indexArray);
+ return;
+ }
+
+ var indicesBuffer = gl.createBuffer();
+ shape._webgl.buffers[0] = indicesBuffer;
+
+ if (x3dom.caps.INDEX_UINT && attribTypeStr == "Uint32") {
+ //indexArray is Uint32Array
+ shape._webgl.indexType = gl.UNSIGNED_INT;
+ }
+ else {
+ //indexArray is Uint16Array
+ shape._webgl.indexType = gl.UNSIGNED_SHORT;
+ }
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexArray, gl.STATIC_DRAW);
+
+ // Test reading Data
+ //x3dom.debug.logWarning("arraybuffer[0]="+indexArray[0]+"; n="+indexArray.length);
+
+ shape._webgl.binaryGeometry = 1; // indexed BG
+
+ if (geoNode._vf.vertexCount[0] == 0)
+ geoNode._vf.vertexCount[0] = indexArray.length;
+
+ geoNode._mesh._numFaces = 0;
+
+ for (var i=0; i<geoNode._vf.vertexCount.length; i++) {
+ if (shape._webgl.primType[i] == gl.TRIANGLE_STRIP)
+ geoNode._mesh._numFaces += geoNode._vf.vertexCount[i] - 2;
+ else
+ geoNode._mesh._numFaces += geoNode._vf.vertexCount[i] / 3;
+ }
+
+ indexArray = null;
+
+ shape._nameSpace.doc.downloadCount -= 1;
+ shape._webgl.internalDownloadCount -= 1;
+ if (shape._webgl.internalDownloadCount == 0)
+ shape._nameSpace.doc.needRender = true;
+
+ that.checkError(gl);
+
+ var t11 = new Date().getTime() - t00;
+ x3dom.debug.logInfo("XHR0/ index load time: " + t11 + " ms");
+ };
+ }
+
+ // interleaved array -- assume all attributes are given in one single array buffer
+ if (binGeo._hasStrideOffset && binGeo._vf.coord.length > 0)
+ {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open("GET", shape._nameSpace.getURL(binGeo._vf.coord), true);
+ xmlhttp.responseType = "arraybuffer";
+
+ shape._nameSpace.doc.downloadCount += 1;
+
+ xmlhttp.send(null);
+
+ xmlhttp.onload = function()
+ {
+ if (!shape._webgl)
+ return;
+
+ var XHR_buffer = xmlhttp.response;
+
+ var geoNode = binGeo;
+ var attribTypeStr = geoNode._vf.coordType;
+
+ // assume same data type for all attributes (but might be wrong)
+ shape._webgl.coordType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+ shape._webgl.normalType = shape._webgl.coordType;
+ shape._webgl.texCoordType = shape._webgl.coordType;
+ shape._webgl.colorType = shape._webgl.coordType;
+
+ var attributes = x3dom.Utils.getArrayBufferView(attribTypeStr, XHR_buffer);
+
+ // calculate number of single data packages by including stride and type size
+ var dataLen = shape._coordStrideOffset[0] / x3dom.Utils.getDataTypeSize(attribTypeStr);
+ if (dataLen)
+ geoNode._mesh._numCoords = attributes.length / dataLen;
+
+ if (geoNode._vf.index.length == 0) {
+ for (var i=0; i<geoNode._vf.vertexCount.length; i++) {
+ if (shape._webgl.primType[i] == gl.TRIANGLE_STRIP)
+ geoNode._mesh._numFaces += geoNode._vf.vertexCount[i] - 2;
+ else
+ geoNode._mesh._numFaces += geoNode._vf.vertexCount[i] / 3;
+ }
+ }
+
+ var buffer = gl.createBuffer();
+
+ shape._webgl.buffers[1] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, attributes, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.position, geoNode._mesh._numPosComponents,
+ shape._webgl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ if (geoNode._vf.normal.length > 0)
+ {
+ shape._webgl.buffers[2] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, attributes, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.normal, geoNode._mesh._numNormComponents,
+ shape._webgl.normalType, false,
+ shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.normal);
+ }
+
+ if (geoNode._vf.texCoord.length > 0)
+ {
+ console.log("YUPPIE");
+
+ shape._webgl.buffers[3] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, attributes, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.texcoord, geoNode._mesh._numTexComponents,
+ shape._webgl.texCoordType, false,
+ shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.texcoord);
+ }
+
+ if (geoNode._vf.color.length > 0)
+ {
+ shape._webgl.buffers[4] = buffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, attributes, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.color, geoNode._mesh._numColComponents,
+ shape._webgl.colorType, false,
+ shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.color);
+ }
+
+ attributes = null; // delete data block in CPU memory
+
+ shape._nameSpace.doc.downloadCount -= 1;
+ shape._webgl.internalDownloadCount -= 1;
+ if (shape._webgl.internalDownloadCount == 0)
+ shape._nameSpace.doc.needRender = true;
+
+ that.checkError(gl);
+
+ var t11 = new Date().getTime() - t00;
+ x3dom.debug.logInfo("XHR/ interleaved array load time: " + t11 + " ms");
+ };
+ }
+
+ // coord
+ if (!binGeo._hasStrideOffset && binGeo._vf.coord.length > 0)
+ {
+ var xmlhttp1 = new XMLHttpRequest();
+ xmlhttp1.open("GET", shape._nameSpace.getURL(binGeo._vf.coord), true);
+ xmlhttp1.responseType = "arraybuffer";
+
+ shape._nameSpace.doc.downloadCount += 1;
+
+ xmlhttp1.send(null);
+
+ xmlhttp1.onload = function()
+ {
+ if (!shape._webgl)
+ return;
+
+ var XHR_buffer = xmlhttp1.response;
+
+ var geoNode = binGeo;
+ var i = 0;
+
+ var attribTypeStr = geoNode._vf.coordType;
+ shape._webgl.coordType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ var vertices = x3dom.Utils.getArrayBufferView(attribTypeStr, XHR_buffer);
+
+ if (createTriangleSoup) {
+ shape._webgl.makeSeparateTris.pushBuffer("coord", vertices);
+ return;
+ }
+
+ gl.bindAttribLocation(sp.program, 0, "position");
+
+ var positionBuffer = gl.createBuffer();
+ shape._webgl.buffers[1] = positionBuffer;
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ gl.vertexAttribPointer(sp.position,
+ geoNode._mesh._numPosComponents,
+ shape._webgl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ geoNode._mesh._numCoords = vertices.length / geoNode._mesh._numPosComponents;
+
+ if (geoNode._vf.index.length == 0) {
+ for (i=0; i<geoNode._vf.vertexCount.length; i++) {
+ if (shape._webgl.primType[i] == gl.TRIANGLE_STRIP)
+ geoNode._mesh._numFaces += geoNode._vf.vertexCount[i] - 2;
+ else
+ geoNode._mesh._numFaces += geoNode._vf.vertexCount[i] / 3;
+ }
+ }
+
+ // Test reading Data
+ //x3dom.debug.logWarning("arraybuffer[0].vx="+vertices[0]);
+
+ if ((attribTypeStr == "Float32") &&
+ (shape._vf.bboxSize.x < 0 || shape._vf.bboxSize.y < 0 || shape._vf.bboxSize.z < 0))
+ {
+ var min = new x3dom.fields.SFVec3f(vertices[0],vertices[1],vertices[2]);
+ var max = new x3dom.fields.SFVec3f(vertices[0],vertices[1],vertices[2]);
+
+ for (i=3; i<vertices.length; i+=3)
+ {
+ if (min.x > vertices[i+0]) { min.x = vertices[i+0]; }
+ if (min.y > vertices[i+1]) { min.y = vertices[i+1]; }
+ if (min.z > vertices[i+2]) { min.z = vertices[i+2]; }
+
+ if (max.x < vertices[i+0]) { max.x = vertices[i+0]; }
+ if (max.y < vertices[i+1]) { max.y = vertices[i+1]; }
+ if (max.z < vertices[i+2]) { max.z = vertices[i+2]; }
+ }
+
+ // TODO; move to mesh for all cases?
+ shape._vf.bboxCenter.setValues(min.add(max).multiply(0.5));
+ shape._vf.bboxSize.setValues(max.subtract(min));
+ }
+
+ vertices = null;
+
+ shape._nameSpace.doc.downloadCount -= 1;
+ shape._webgl.internalDownloadCount -= 1;
+ if (shape._webgl.internalDownloadCount == 0)
+ shape._nameSpace.doc.needRender = true;
+
+ that.checkError(gl);
+
+ var t11 = new Date().getTime() - t00;
+ x3dom.debug.logInfo("XHR1/ coord load time: " + t11 + " ms");
+ };
+ }
+
+ // normal
+ if (!binGeo._hasStrideOffset && binGeo._vf.normal.length > 0)
+ {
+ var xmlhttp2 = new XMLHttpRequest();
+ xmlhttp2.open("GET", shape._nameSpace.getURL(binGeo._vf.normal), true);
+ xmlhttp2.responseType = "arraybuffer";
+
+ shape._nameSpace.doc.downloadCount += 1;
+
+ xmlhttp2.send(null);
+
+ xmlhttp2.onload = function()
+ {
+ if (!shape._webgl)
+ return;
+
+ var XHR_buffer = xmlhttp2.response;
+
+ var attribTypeStr = binGeo._vf.normalType;
+ shape._webgl.normalType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ var normals = x3dom.Utils.getArrayBufferView(attribTypeStr, XHR_buffer);
+
+ if (createTriangleSoup) {
+ shape._webgl.makeSeparateTris.pushBuffer("normal", normals);
+ return;
+ }
+
+ var normalBuffer = gl.createBuffer();
+ shape._webgl.buffers[2] = normalBuffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.normal,
+ binGeo._mesh._numNormComponents,
+ shape._webgl.normalType, false,
+ shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.normal);
+
+ // Test reading Data
+ //x3dom.debug.logWarning("arraybuffer[0].nx="+normals[0]);
+
+ normals = null;
+
+ shape._nameSpace.doc.downloadCount -= 1;
+ shape._webgl.internalDownloadCount -= 1;
+ if (shape._webgl.internalDownloadCount == 0)
+ shape._nameSpace.doc.needRender = true;
+
+ that.checkError(gl);
+
+ var t11 = new Date().getTime() - t00;
+ x3dom.debug.logInfo("XHR2/ normal load time: " + t11 + " ms");
+ };
+ }
+
+ // texCoord
+ if (!binGeo._hasStrideOffset && binGeo._vf.texCoord.length > 0)
+ {
+ var xmlhttp3 = new XMLHttpRequest();
+ xmlhttp3.open("GET", shape._nameSpace.getURL(binGeo._vf.texCoord), true);
+ xmlhttp3.responseType = "arraybuffer";
+
+ shape._nameSpace.doc.downloadCount += 1;
+
+ xmlhttp3.send(null);
+
+ xmlhttp3.onload = function()
+ {
+ var i, j;
+ var tmp;
+
+ if (!shape._webgl)
+ return;
+
+ var XHR_buffer = xmlhttp3.response;
+
+ var attribTypeStr = binGeo._vf.texCoordType;
+ shape._webgl.texCoordType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ var texCoords = x3dom.Utils.getArrayBufferView(attribTypeStr, XHR_buffer);
+
+ if (createTriangleSoup) {
+ shape._webgl.makeSeparateTris.pushBuffer("texCoord", texCoords);
+ return;
+ }
+
+
+ //if IDs are given in texture coordinates, interpret texcoords as ID buffer
+ if (binGeo._vf["idsPerVertex"])
+ {
+ var idBuffer = gl.createBuffer();
+
+ shape._webgl.buffers[5] = idBuffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, idBuffer);
+
+ //Create a buffer for the ids with half size of the texccoord buffer
+ var ids = x3dom.Utils.getArrayBufferView("Float32", texCoords.length/2);
+
+ //swap x and y, in order to interpret tex coords as FLOAT later on
+ for (i = 0, j= 0; i < texCoords.length; i+=2, j++)
+ {
+ ids[j] = texCoords[i+1] * 65536 + texCoords[i];
+ }
+
+ gl.bufferData(gl.ARRAY_BUFFER, ids, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.id,
+ 1,
+ gl.FLOAT, false,
+ 4, 0);
+ gl.enableVertexAttribArray(sp.id);
+ }
+ else
+ {
+ var texcBuffer = gl.createBuffer();
+ shape._webgl.buffers[3] = texcBuffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, texcBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.texcoord,
+ binGeo._mesh._numTexComponents,
+ shape._webgl.texCoordType, false,
+ shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.texcoord);
+ }
+ // Test reading Data
+ //x3dom.debug.logWarning("arraybuffer[0].tx="+texCoords[0]);
+
+ texCoords = null;
+
+ shape._nameSpace.doc.downloadCount -= 1;
+ shape._webgl.internalDownloadCount -= 1;
+ if (shape._webgl.internalDownloadCount == 0)
+ shape._nameSpace.doc.needRender = true;
+
+ that.checkError(gl);
+
+ var t11 = new Date().getTime() - t00;
+ x3dom.debug.logInfo("XHR3/ texCoord load time: " + t11 + " ms");
+ };
+ }
+
+ // color
+ if (!binGeo._hasStrideOffset && binGeo._vf.color.length > 0)
+ {
+ var xmlhttp4 = new XMLHttpRequest();
+ xmlhttp4.open("GET", shape._nameSpace.getURL(binGeo._vf.color), true);
+ xmlhttp4.responseType = "arraybuffer";
+
+ shape._nameSpace.doc.downloadCount += 1;
+
+ xmlhttp4.send(null);
+
+ xmlhttp4.onload = function()
+ {
+ if (!shape._webgl)
+ return;
+
+ var XHR_buffer = xmlhttp4.response;
+
+ var attribTypeStr = binGeo._vf.colorType;
+ shape._webgl.colorType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ var colors = x3dom.Utils.getArrayBufferView(attribTypeStr, XHR_buffer);
+
+ if (createTriangleSoup) {
+ shape._webgl.makeSeparateTris.pushBuffer("color", colors);
+ return;
+ }
+
+ var colorBuffer = gl.createBuffer();
+ shape._webgl.buffers[4] = colorBuffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.color,
+ binGeo._mesh._numColComponents,
+ shape._webgl.colorType, false,
+ shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.color);
+
+ // Test reading Data
+ //x3dom.debug.logWarning("arraybuffer[0].cx="+colors[0]);
+
+ colors = null;
+
+ shape._nameSpace.doc.downloadCount -= 1;
+ shape._webgl.internalDownloadCount -= 1;
+ if (shape._webgl.internalDownloadCount == 0)
+ shape._nameSpace.doc.needRender = true;
+
+ that.checkError(gl);
+
+ var t11 = new Date().getTime() - t00;
+ x3dom.debug.logInfo("XHR4/ color load time: " + t11 + " ms");
+ };
+ }
+ // TODO: tangent AND binormal
+};
+
+/** setup/download pop geometry */
+x3dom.BinaryContainerLoader.setupPopGeo = function(shape, sp, gl, viewarea, currContext)
+{
+ if (this.outOfMemory) {
+ return;
+ }
+
+ var popGeo = shape._cf.geometry.node;
+
+ //reserve space for vertex buffer (and index buffer if any) on the gpu
+ if (popGeo.hasIndex()) {
+ shape._webgl.popGeometry = 1;
+
+ shape._webgl.buffers[0] = gl.createBuffer();
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, shape._webgl.buffers[0]);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, popGeo.getTotalNumberOfIndices()*2, gl.STATIC_DRAW);
+
+ //this is a workaround to mimic gl_VertexID
+ shape._webgl.buffers[5] = gl.createBuffer();
+
+ var idBuffer = new Float32Array(popGeo._vf.vertexBufferSize);
+
+ (function(){ for (var i = 0; i < idBuffer.length; ++i) idBuffer[i] = i; })();
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, shape._webgl.buffers[5]);
+ gl.bufferData(gl.ARRAY_BUFFER, idBuffer, gl.STATIC_DRAW);
+ }
+ else {
+ shape._webgl.popGeometry = -1;
+ }
+
+ shape._webgl.buffers[1] = gl.createBuffer();
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, shape._webgl.buffers[1]);
+ gl.bufferData(gl.ARRAY_BUFFER, (popGeo._vf.attributeStride * popGeo._vf.vertexBufferSize), gl.STATIC_DRAW);
+
+
+ //setup general render settings
+ var attribTypeStr = popGeo._vf.coordType;
+ shape._webgl.coordType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ shape._coordStrideOffset[0] = popGeo.getAttributeStride();
+ shape._coordStrideOffset[1] = popGeo.getPositionOffset();
+
+ gl.vertexAttribPointer(sp.position, shape._cf.geometry.node._mesh._numPosComponents, shape._webgl.coordType,
+ false, shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ if (popGeo.hasNormal()) {
+ attribTypeStr = popGeo._vf.normalType;
+ shape._webgl.normalType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ shape._normalStrideOffset[0] = popGeo.getAttributeStride();
+ shape._normalStrideOffset[1] = popGeo.getNormalOffset();
+
+ shape._webgl.buffers[2] = shape._webgl.buffers[1]; //use interleaved vertex data buffer
+
+ gl.vertexAttribPointer(sp.normal, shape._cf.geometry.node._mesh._numNormComponents, shape._webgl.normalType,
+ false, shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.normal);
+ }
+ if (popGeo.hasTexCoord()) {
+ attribTypeStr = popGeo._vf.texCoordType;
+ shape._webgl.texCoordType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ shape._webgl.buffers[3] = shape._webgl.buffers[1]; //use interleaved vertex data buffer
+
+ shape._texCoordStrideOffset[0] = popGeo.getAttributeStride();
+ shape._texCoordStrideOffset[1] = popGeo.getTexCoordOffset();
+
+ gl.vertexAttribPointer(sp.texcoord, shape._cf.geometry.node._mesh._numTexComponents, shape._webgl.texCoordType,
+ false, shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.texcoord);
+ }
+ if (popGeo.hasColor()) {
+ attribTypeStr = popGeo._vf.colorType;
+ shape._webgl.colorType = x3dom.Utils.getVertexAttribType(attribTypeStr, gl);
+
+ shape._webgl.buffers[4] = shape._webgl.buffers[1]; //use interleaved vertex data buffer
+
+ shape._colorStrideOffset[0] = popGeo.getAttributeStride();
+ shape._colorStrideOffset[1] = popGeo.getColorOffset();
+
+ gl.vertexAttribPointer(sp.color, shape._cf.geometry.node._mesh._numColComponents, shape._webgl.colorType,
+ false, shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.color);
+ }
+
+ shape._webgl.currentNumIndices = 0;
+ shape._webgl.currentNumVertices = 0;
+ shape._webgl.numVerticesAtLevel = [];
+ shape._webgl.levelsAvailable = 0;
+
+ this.checkError(gl);
+
+ shape._webgl.levelLoaded = [];
+ (function() {
+ for (var i = 0; i < popGeo.getNumLevels(); ++i)
+ shape._webgl.levelLoaded.push(false);
+ })();
+
+ //download callback, used to simply upload received vertex data to the GPU
+ var uploadDataToGPU = function(data, lvl) {
+ //x3dom.debug.logInfo("PopGeometry: Received data for level " + lvl + " !\n");
+
+ shape._webgl.levelLoaded[lvl] = true;
+ shape._webgl.numVerticesAtLevel[lvl] = 0;
+
+ if (data) {
+ //perform gpu data upload
+ var indexDataLengthInBytes = 0;
+ var redrawNeeded = false;
+
+ if (popGeo.hasIndex()) {
+ indexDataLengthInBytes = popGeo.getNumIndicesByLevel(lvl)*2;
+
+ if (indexDataLengthInBytes > 0) {
+ redrawNeeded = true;
+
+ var indexDataView = new Uint8Array(data, 0, indexDataLengthInBytes);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, shape._webgl.buffers[0]);
+ //index data is always placed where it belongs, as we have to keep the order of rendering
+ (function() {
+ var indexDataOffset = 0;
+
+ for (var i = 0; i < lvl; ++i) { indexDataOffset += popGeo.getNumIndicesByLevel(i); }
+
+ gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, indexDataOffset*2, indexDataView);
+ })();
+ }
+ }
+
+ var vertexDataLengthInBytes = data.byteLength - indexDataLengthInBytes;
+
+ if (vertexDataLengthInBytes > 0) {
+ redrawNeeded = true;
+
+ var attributeDataView = new Uint8Array(data, indexDataLengthInBytes, vertexDataLengthInBytes);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, shape._webgl.buffers[1]);
+ if (!popGeo.hasIndex()) {
+ //on non-indexed rendering, vertex data is just appended, the order of vertex data packages doesn't matter
+ gl.bufferSubData(gl.ARRAY_BUFFER, shape._webgl.currentNumVertices * popGeo.getAttributeStride(),
+ attributeDataView);
+ }
+ else {
+ //on indexed rendering, vertex data is always placed where it belongs, as we have to keep the indexed order
+ gl.bufferSubData(gl.ARRAY_BUFFER,popGeo.getVertexDataBufferOffset(lvl) * popGeo.getAttributeStride(),
+ attributeDataView);
+ }
+
+ //adjust render settings: vertex data
+ shape._webgl.numVerticesAtLevel[lvl] = vertexDataLengthInBytes / popGeo.getAttributeStride();
+ shape._webgl.currentNumVertices += shape._webgl.numVerticesAtLevel[lvl];
+ }
+
+ //compute number of valid indices
+ (function() {
+ var numValidIndices = 0;
+
+ for (var i = shape._webgl.levelsAvailable; i < popGeo.getNumLevels(); ++i) {
+ if (shape._webgl.levelLoaded[i] === false) {
+ break;
+ }
+ else {
+ numValidIndices += popGeo.getNumIndicesByLevel(i);
+ ++shape._webgl.levelsAvailable;
+ }
+ }
+
+ //adjust render settings: index data
+ shape._webgl.currentNumIndices = numValidIndices;
+ })();
+
+ //here, we tell X3DOM how many faces / vertices get displayed in the stats
+ popGeo._mesh._numCoords = shape._webgl.currentNumVertices;
+ //@todo: this assumes pure TRIANGLES data
+ popGeo._mesh._numFaces = (popGeo.hasIndex() ? shape._webgl.currentNumIndices : shape._webgl.currentNumVertices) / 3;
+
+ //here, we tell X3DOM how many vertices get rendered
+ //@todo: this assumes pure TRIANGLES data
+ popGeo.adaptVertexCount(popGeo.hasIndex() ? popGeo._mesh._numFaces * 3 : popGeo._mesh._numCoords);
+ //x3dom.debug.logInfo("PopGeometry: Loaded level " + lvl + " data to gpu, model has now " +
+ // popGeo._mesh._numCoords + " vertices and " + popGeo._mesh._numFaces + " triangles, " +
+ // (new Date().getTime() - shape._webgl.downloadStartTimer) + " ms after posting download requests");
+
+ //request redraw, if necessary
+ if (redrawNeeded) {
+ shape._nameSpace.doc.needRender = true;
+ }
+ }
+ };
+
+ //post XHRs
+ var dataURLs = popGeo.getDataURLs();
+
+ var downloadCallbacks = [];
+ var priorities = [];
+
+ shape._webgl.downloadStartTimer = new Date().getTime();
+
+ //CODE WITH DL MANAGER
+ //use the DownloadManager to prioritize loading
+
+ for (var i = 0; i < dataURLs.length; ++i) {
+ shape._nameSpace.doc.downloadCount += 1;
+
+ (function(idx) {
+ downloadCallbacks.push(function(data) {
+ shape._nameSpace.doc.downloadCount -= 1;
+ return uploadDataToGPU(data, idx);
+ });
+ })(i);
+
+ priorities.push(i);
+ }
+
+ x3dom.DownloadManager.get(dataURLs, downloadCallbacks, priorities);
+ //END CODE WITH DL MANAGER
+};
+
+/** setup/download image geometry */
+x3dom.BinaryContainerLoader.setupImgGeo = function(shape, sp, gl, viewarea, currContext)
+{
+ if (this.outOfMemory) {
+ return;
+ }
+
+ var imageGeometry = shape._cf.geometry.node;
+
+ if ( imageGeometry.getIndexTexture() ) {
+ shape._webgl.imageGeometry = 1;
+ } else {
+ shape._webgl.imageGeometry = -1;
+ }
+
+ imageGeometry.unsetGeoDirty();
+
+ if (currContext.IG_PositionBuffer == null) {
+ currContext.IG_PositionBuffer = gl.createBuffer();
+ }
+
+ shape._webgl.buffers[1] = currContext.IG_PositionBuffer;
+ gl.bindBuffer(gl.ARRAY_BUFFER, currContext.IG_PositionBuffer);
+
+ var vertices = new Float32Array(shape._webgl.positions[0]);
+
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, currContext.IG_PositionBuffer);
+
+ gl.vertexAttribPointer(sp.position, imageGeometry._mesh._numPosComponents,
+ shape._webgl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ vertices = null;
+
+ this.checkError(gl);
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/**
+ * c'tor
+ */
+x3dom.DrawableCollection = function (drawableCollectionConfig) {
+ this.collection = [];
+
+ this.viewMatrix = drawableCollectionConfig.viewMatrix;
+ this.projMatrix = drawableCollectionConfig.projMatrix;
+ this.sceneMatrix = drawableCollectionConfig.sceneMatrix;
+
+ this.viewarea = drawableCollectionConfig.viewArea;
+
+ var scene = this.viewarea._scene;
+ var env = scene.getEnvironment();
+ var viewpoint = scene.getViewpoint();
+
+ this.near = viewpoint.getNear();
+ this.pixelHeightAtDistOne = viewpoint.getImgPlaneHeightAtDistOne() / this.viewarea._height;
+
+ this.context = drawableCollectionConfig.context;
+ this.gl = drawableCollectionConfig.gl;
+
+ this.viewFrustum = this.viewarea.getViewfrustum(this.sceneMatrix);
+ this.worldVol = new x3dom.fields.BoxVolume(); // helper
+
+ this.frustumCulling = drawableCollectionConfig.frustumCulling && (this.viewFrustum != null);
+ this.smallFeatureThreshold = drawableCollectionConfig.smallFeatureThreshold;
+
+ // if (lowPriorityThreshold < 1) sort all potentially visible objects according to priority
+ this.sortOpaque = (this.smallFeatureThreshold > 0 && env._lowPriorityThreshold < 1);
+ this.sortTrans = drawableCollectionConfig.sortTrans;
+
+ this.prioLevels = 10;
+ this.maxTreshold = 100;
+
+ this.sortBySortKey = false;
+ this.sortByPriority = false;
+
+ this.numberOfNodes = 0;
+
+ this.length = 0;
+};
+
+/**
+ * graphState = {
+ * boundedNode: backref to bounded node object
+ * localMatrix: mostly identity
+ * globalMatrix: current transform
+ * volume: local bbox
+ * worldVolume: global bbox
+ * center: center in eye coords
+ * coverage: currently approx. number of pixels on screen
+ * };
+ */
+x3dom.DrawableCollection.prototype.cull = function (transform, graphState, singlePath, planeMask) {
+ var node = graphState.boundedNode; // get ref to SG node
+
+ if (!node || !node._vf.render) {
+ return 0; // <0 outside, >0 inside, but can't tell in this case
+ }
+
+ var volume = node.getVolume(); // create on request
+ var MASK_SET = 63; // 2^6-1, i.e. all sides of the volume
+
+ if (this.frustumCulling && graphState.needCulling) {
+ var wvol;
+
+ if (singlePath && !graphState.worldVolume.isValid()) {
+ graphState.worldVolume.transformFrom(transform, volume);
+ wvol = graphState.worldVolume; // use opportunity to update if necessary
+ }
+ else if (planeMask < MASK_SET) {
+ this.worldVol.transformFrom(transform, volume);
+ wvol = this.worldVol;
+ }
+
+ if (planeMask < MASK_SET)
+ planeMask = this.viewFrustum.intersect(wvol, planeMask);
+ if (planeMask <= 0) {
+ return -1; // if culled return -1; 0 should never happen
+ }
+ }
+ else {
+ planeMask = MASK_SET;
+ }
+
+ graphState.coverage = -1; // if -1 then ignore value later on
+
+ // TODO: save the coverage only for drawables, which are unique (shapes can be shared!)
+ if (this.smallFeatureThreshold > 0 || node.forceUpdateCoverage()) {
+ var modelViewMat = this.viewMatrix.mult(transform);
+
+ graphState.center = modelViewMat.multMatrixPnt(volume.getCenter());
+
+ var rVec = modelViewMat.multMatrixVec(volume.getRadialVec());
+ var r = rVec.length();
+
+ var dist = Math.max(-graphState.center.z - r, this.near);
+ var projPixelLength = dist * this.pixelHeightAtDistOne;
+
+ graphState.coverage = (r * 2.0) / projPixelLength;
+
+ if (this.smallFeatureThreshold > 0 && graphState.coverage < this.smallFeatureThreshold &&
+ graphState.needCulling) {
+ return 0; // differentiate between outside and this case
+ }
+ }
+
+ // not culled, incr node cnt
+ this.numberOfNodes++;
+
+ return planeMask; // >0, inside
+};
+
+/**
+ * A drawable is basically a unique pair of a shape node and a global transformation.
+ */
+x3dom.DrawableCollection.prototype.addShape = function (shape, transform, graphState) {
+ //Create a new drawable object
+ var drawable = {};
+
+ //Set the shape
+ drawable.shape = shape;
+
+ //Set the transform
+ drawable.transform = transform;
+
+ drawable.localTransform = graphState.localMatrix;
+
+ //Set the local bounding box (reference, can be shared amongst shapes)
+ drawable.localVolume = graphState.volume;
+
+ //Set the global bbox (needs to be cloned since shape can be shared)
+ drawable.worldVolume = x3dom.fields.BoxVolume.copy(graphState.worldVolume);
+
+ //Calculate the magical object priority (though currently not very magic)
+ drawable.priority = Math.max(0, graphState.coverage);
+ //drawable.priority = this.calculatePriority(graphState);
+
+ //Get shaderID from shape
+ drawable.shaderID = shape.getShaderProperties(this.viewarea).id;
+
+ var appearance = shape._cf.appearance.node;
+
+ drawable.sortType = appearance ? appearance._vf.sortType.toLowerCase() : "opaque";
+ drawable.sortKey = appearance ? appearance._vf.sortKey : 0;
+
+ if (drawable.sortType == 'transparent') {
+ if (this.smallFeatureThreshold > 0) {
+ // TODO: center was previously set in cull, which is called first, but this
+ // might be problematic if scene is traversed in parallel and node is shared
+ // (though currently traversal is sequential, so everything is fine)
+ drawable.zPos = graphState.center.z;
+ }
+ else {
+ //Calculate the z-Pos for transparent object sorting
+ //if the center of the box is not available
+ var center = transform.multMatrixPnt(shape.getCenter());
+ center = this.viewMatrix.multMatrixPnt(center);
+ drawable.zPos = center.z;
+ }
+ }
+
+ //Look for sorting by sortKey
+ if (!this.sortBySortKey && drawable.sortKey != 0) {
+ this.sortBySortKey = true;
+ }
+
+ //Generate separate array for sortType if not exists
+ if (this.collection[drawable.sortType] === undefined) {
+ this.collection[drawable.sortType] = [];
+ }
+
+ //Push drawable to the collection
+ this.collection[drawable.sortType].push(drawable);
+ //this.collection[drawable.sortType][drawable.sortKey][drawable.priority][drawable.shaderID].push(drawable);
+
+ //Increment collection length
+ this.length++;
+
+ //Finally setup shape directly here to avoid another loop of O(n)
+ if (this.context && this.gl) {
+ this.context.setupShape(this.gl, drawable, this.viewarea);
+ }
+ //TODO: what about Flash? Shall we also setup structures here?
+};
+
+/**
+ * A drawable is basically a unique pair of a shape node and a global transformation.
+ */
+x3dom.DrawableCollection.prototype.addDrawable = function (drawable) {
+ //Calculate the magical object priority (though currently not very magic)
+ //drawable.priority = this.calculatePriority(graphState);
+
+ //Get shaderID from shape
+ drawable.shaderID = drawable.shape.getShaderProperties(this.viewarea).id;
+
+ var appearance = drawable.shape._cf.appearance.node;
+
+ drawable.sortType = appearance ? appearance._vf.sortType.toLowerCase() : "opaque";
+ drawable.sortKey = appearance ? appearance._vf.sortKey : 0;
+
+ if (drawable.sortType == 'transparent') {
+ //TODO set zPos for drawable for z-sorting
+ //Calculate the z-Pos for transparent object sorting
+ //if the center of the box is not available
+ var center = drawable.transform.multMatrixPnt(drawable.shape.getCenter());
+ center = this.viewMatrix.multMatrixPnt(center);
+ drawable.zPos = center.z;
+ }
+
+ //Look for sorting by sortKey
+ if (!this.sortBySortKey && drawable.sortKey != 0) {
+ this.sortBySortKey = true;
+ }
+
+ //Generate separate array for sortType if not exists
+ if (this.collection[drawable.sortType] === undefined) {
+ this.collection[drawable.sortType] = [];
+ }
+
+ //Push drawable to the collection
+ this.collection[drawable.sortType].push(drawable);
+ //this.collection[drawable.sortType][drawable.sortKey][drawable.priority][drawable.shaderID].push(drawable);
+
+ //Increment collection length
+ this.length++;
+
+ //Finally setup shape directly here to avoid another loop of O(n)
+ if (this.context && this.gl) {
+ this.context.setupShape(this.gl, drawable, this.viewarea);
+ }
+};
+
+
+/**
+ * Calculate the magical object priority (though currently not very magic).
+ */
+x3dom.DrawableCollection.prototype.calculatePriority = function (graphState) {
+ //Use coverage as priority
+ var priority = Math.max(0, graphState.coverage);
+
+ //Classify the priority level
+ var pl = this.prioLevels - 1; // Can this be <= 0? Then FIXME!
+ priority = Math.min( Math.round(priority / (this.maxTreshold / pl)), pl );
+
+ return priority;
+};
+
+/**
+ * Concatenate opaque and transparent drawables
+ */
+x3dom.DrawableCollection.prototype.concat = function () {
+ var opaque = (this.collection['opaque'] !== undefined) ? this.collection['opaque'] : [];
+ var transparent = (this.collection['transparent'] !== undefined) ? this.collection['transparent'] : [];
+
+ //Merge opaque and transparent drawables to a single array
+ this.collection = opaque.concat(transparent);
+};
+
+/**
+ * Get drawable for id
+ */
+x3dom.DrawableCollection.prototype.get = function (idx) {
+ return this.collection[idx];
+};
+
+/**
+ * Sort the DrawableCollection
+ */
+x3dom.DrawableCollection.prototype.sort = function () {
+ var opaque = [];
+ var transparent = [];
+ var that = this;
+
+ //Sort opaque drawables
+ if (this.collection['opaque'] !== undefined) {
+ // never call this for very big scenes, getting very slow; try binning approach
+ if (this.sortOpaque) {
+ this.collection['opaque'].sort(function (a, b) {
+ if (a.sortKey == b.sortKey || !that.sortBySortKey) {
+ //Second sort criteria (priority)
+ return b.priority - a.priority;
+ }
+ //First sort criteria (sortKey)
+ return a.sortKey - b.sortKey;
+ });
+ }
+ opaque = this.collection['opaque'];
+ }
+
+ //Sort transparent drawables
+ if (this.collection['transparent'] !== undefined) {
+ if (this.sortTrans) {
+ this.collection['transparent'].sort(function (a, b) {
+ if (a.sortKey == b.sortKey || !that.sortBySortKey) {
+ if (a.priority == b.priority || !that.sortByPriority) {
+ //Third sort criteria (zPos)
+ return a.zPos - b.zPos;
+ }
+ //Second sort criteria (priority)
+ return b.priority - a.priority;
+ }
+ //First sort criteria (sortKey)
+ return a.sortKey - b.sortKey;
+ });
+ }
+ transparent = this.collection['transparent'];
+ }
+
+ //Merge opaque and transparent drawables to a single array (slow operation)
+ this.collection = opaque.concat(transparent);
+};
+
+x3dom.DrawableCollection.prototype.forEach = function (fnc, maxPriority) {
+ //Set maximal priority
+ maxPriority = (maxPriority !== undefined) ? Math.min(maxPriority, this.prioLevels) : this.prioLevels;
+
+ //Define run variables
+ var sortKey, priority, shaderID, drawable;
+
+ //First traverse Opaque drawables
+ // TODO; FIXME; this is wrong, sortKey can also be negative!
+ for (sortKey=0; sortKey<this.collection['opaque'].length; ++sortKey)
+ {
+ if (this.collection['opaque'][sortKey] !== undefined)
+ {
+ for (priority=this.collection['opaque'][sortKey].length; priority>0; --priority)
+ {
+ if (this.collection['opaque'][sortKey][priority] !== undefined)
+ {
+ for (shaderID in this.collection['opaque'][sortKey][priority])
+ {
+ for (drawable=0; drawable<this.collection['opaque'][sortKey][priority][shaderID].length; ++drawable)
+ {
+ fnc( this.collection['opaque'][sortKey][priority][shaderID][drawable] );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Next traverse transparent drawables
+ // TODO; FIXME; this is wrong, sortKey can also be negative!
+ for (sortKey=0; sortKey<this.collection['transparent'].length; ++sortKey)
+ {
+ if (this.collection['transparent'][sortKey] !== undefined)
+ {
+ for (priority=this.collection['transparent'][sortKey].length; priority>0; --priority)
+ {
+ if (this.collection['transparent'][sortKey][priority] !== undefined)
+ {
+ for (var shaderId in this.collection['transparent'][sortKey][priority])
+ {
+ //Sort transparent drawables by z-Pos
+ this.collection['transparent'][sortKey][priority][shaderId].sort(function(a, b) {
+ return a.zPos - b.zPos
+ });
+
+ for (drawable=0; drawable<this.collection['transparent'][sortKey][priority][shaderId].length; ++drawable)
+ {
+ fnc( this.collection['transparent'][sortKey][priority][shaderId][drawable] );
+ }
+ }
+ }
+ }
+ }
+ }
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/**
+ * Moveable interface, wraps x3d bounded node with SpaceSensor-like movement functionality,
+ * therefore attaches event handlers, thus to be called earliest in document.onload method.
+ *
+ * Cleanup backrefs and listeners on delete by explicitly calling detachHandlers()
+ */
+x3dom.Moveable = function(x3domElem, boundedObj, callback, gridSize, mode) {
+ this._x3domRoot = x3domElem;
+ this._runtime = x3domElem.runtime;
+
+ // callback function for notifying changes
+ this._callback = callback;
+
+ // snap to grid of given size (0, no grid, if undefined)
+ this._gridSize = gridSize ? gridSize : 0;
+
+ this._moveable = boundedObj;
+ this._drag = false;
+
+ this._w = 0;
+ this._h = 0;
+
+ this._uPlane = null;
+ this._vPlane = null;
+ this._pPlane = null;
+
+ this._isect = null;
+
+ this._translationOffset = null;
+ this._rotationOffset = null;
+ this._scaleOffset = null;
+
+ this._lastX = 0;
+ this._lastY = 0;
+ this._buttonState = 0;
+
+ this._mode = (mode && mode.length) ? mode.toLowerCase() : "translation"; //"all";
+
+ this._firstRay = null;
+ this._matrixTrafo = null;
+
+ this._navType = "examine";
+
+ this.attachHandlers();
+};
+
+// grid size setter, for snapping
+x3dom.Moveable.prototype.setGridSize = function(gridSize) {
+ this._gridSize = gridSize;
+};
+
+// interaction mode setter, for translation and/or rotation
+x3dom.Moveable.prototype.setMode = function(mode) {
+ this._mode = mode.toLowerCase();
+};
+
+x3dom.Moveable.prototype.attachHandlers = function() {
+ // add backref to movable object (for member access and wrapping)
+ this._moveable._iMove = this;
+
+ // add backref to <x3d> element
+ if (!this._x3domRoot._iMove)
+ this._x3domRoot._iMove = [];
+ this._x3domRoot._iMove.push(this);
+
+ // mouse events
+ this._moveable.addEventListener('mousedown', this.start, false);
+ this._moveable.addEventListener('mouseover', this.over, false);
+ this._moveable.addEventListener('mouseout', this.out, false);
+
+ if (this._x3domRoot._iMove.length == 1) {
+ // more mouse events
+ this._x3domRoot.addEventListener('mouseup', this.stop, false);
+ this._x3domRoot.addEventListener('mouseout', this.stop, false);
+ this._x3domRoot.addEventListener('mousemove', this.move, true);
+
+ if (!this._runtime.canvas.disableTouch) {
+ // mozilla touch events
+ this._x3domRoot.addEventListener('MozTouchDown', this.touchStartHandlerMoz, false);
+ this._x3domRoot.addEventListener('MozTouchMove', this.touchMoveHandlerMoz, true);
+ this._x3domRoot.addEventListener('MozTouchUp', this.touchEndHandlerMoz, false);
+ // w3c / apple touch events
+ this._x3domRoot.addEventListener('touchstart', this.touchStartHandler, false);
+ this._x3domRoot.addEventListener('touchmove', this.touchMoveHandler, true);
+ this._x3domRoot.addEventListener('touchend', this.touchEndHandler, false);
+ }
+ }
+};
+
+x3dom.Moveable.prototype.detachHandlers = function() {
+ // remove backref to <x3d> element
+ var iMove = this._x3domRoot._iMove;
+ if (iMove) {
+ for (var i=0, n=iMove.length; i<n; i++) {
+ if (iMove[i] == this) {
+ iMove.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ // mouse events
+ this._moveable.removeEventListener('mousedown', this.start, false);
+ this._moveable.removeEventListener('mouseover', this.over, false);
+ this._moveable.removeEventListener('mouseout', this.out, false);
+
+ if (iMove.length == 0) {
+ // more mouse events
+ this._x3domRoot.removeEventListener('mouseup', this.stop, false);
+ this._x3domRoot.removeEventListener('mouseout', this.stop, false);
+ this._x3domRoot.removeEventListener('mousemove', this.move, true);
+
+ if (!this._runtime.canvas.disableTouch) {
+ // touch events
+ this._x3domRoot.removeEventListener('MozTouchDown', this.touchStartHandlerMoz, false);
+ this._x3domRoot.removeEventListener('MozTouchMove', this.touchMoveHandlerMoz, true);
+ this._x3domRoot.removeEventListener('MozTouchUp', this.touchEndHandlerMoz, false);
+ // mozilla version
+ this._x3domRoot.removeEventListener('touchstart', this.touchStartHandler, false);
+ this._x3domRoot.removeEventListener('touchmove', this.touchMoveHandler, true);
+ this._x3domRoot.removeEventListener('touchend', this.touchEndHandler, false);
+ }
+ }
+
+ // finally remove backref to movable object
+ if (this._moveable._iMove)
+ delete this._moveable._iMove;
+};
+
+// calculate viewing plane
+x3dom.Moveable.prototype.calcViewPlane = function(origin) {
+ // init width and height
+ this._w = this._runtime.getWidth();
+ this._h = this._runtime.getHeight();
+
+ //bottom left of viewarea
+ var ray = this._runtime.getViewingRay(0, this._h - 1);
+ var r = ray.pos.add(ray.dir);
+
+ //bottom right of viewarea
+ ray = this._runtime.getViewingRay(this._w - 1, this._h - 1);
+ var s = ray.pos.add(ray.dir);
+
+ //top left of viewarea
+ ray = this._runtime.getViewingRay(0, 0);
+ var t = ray.pos.add(ray.dir);
+
+ this._uPlane = s.subtract(r).normalize();
+ this._vPlane = t.subtract(r).normalize();
+
+ if (arguments.length === 0)
+ this._pPlane = r;
+ else
+ this._pPlane = x3dom.fields.SFVec3f.copy(origin);
+};
+
+// helper method to obtain determinant
+x3dom.Moveable.prototype.det = function(mat) {
+ return mat[0][0] * mat[1][1] * mat[2][2] + mat[0][1] * mat[1][2] * mat[2][0] +
+ mat[0][2] * mat[2][1] * mat[1][0] - mat[2][0] * mat[1][1] * mat[0][2] -
+ mat[0][0] * mat[2][1] * mat[1][2] - mat[1][0] * mat[0][1] * mat[2][2];
+};
+
+// Translation along plane parallel to viewing plane E:x=p+t*u+s*v
+x3dom.Moveable.prototype.translateXY = function(l) {
+ var track = null;
+ var z = [], n = [];
+
+ for (var i = 0; i < 3; i++) {
+ z[i] = [];
+ n[i] = [];
+
+ z[i][0] = this._uPlane.at(i);
+ n[i][0] = z[i][0];
+
+ z[i][1] = this._vPlane.at(i);
+ n[i][1] = z[i][1];
+
+ z[i][2] = (l.pos.subtract(this._pPlane)).at(i);
+ n[i][2] = -l.dir.at(i);
+ }
+
+ // get intersection line-plane with Cramer's rule
+ var s = this.det(n);
+
+ if (s !== 0) {
+ var t = this.det(z) / s;
+ track = l.pos.addScaled(l.dir, t);
+ }
+
+ if (track) {
+ if (this._isect) {
+ // calc offset from first click position
+ track = track.subtract(this._isect);
+ }
+ track = track.add(this._translationOffset);
+ }
+
+ return track;
+};
+
+// Translation along picking ray
+x3dom.Moveable.prototype.translateZ = function(l, currY) {
+ var vol = this._runtime.getSceneBBox();
+
+ var sign = (currY < this._lastY) ? 1 : -1;
+ var fact = sign * (vol.max.subtract(vol.min)).length() / 100;
+
+ this._translationOffset = this._translationOffset.addScaled(l.dir, fact);
+
+ return this._translationOffset;
+};
+
+x3dom.Moveable.prototype.rotate = function(posX, posY) {
+ var twoPi = 2 * Math.PI;
+ var alpha = ((posY - this._lastY) * twoPi) / this._w;
+ var beta = ((posX - this._lastX) * twoPi) / this._h;
+
+ var q = x3dom.fields.Quaternion.axisAngle(this._uPlane, alpha);
+ var h = q.toMatrix();
+ this._rotationOffset = h.mult(this._rotationOffset);
+
+ q = x3dom.fields.Quaternion.axisAngle(this._vPlane, beta);
+ h = q.toMatrix();
+ this._rotationOffset = h.mult(this._rotationOffset);
+
+ var mat = this._rotationOffset.mult(x3dom.fields.SFMatrix4f.scale(this._scaleOffset));
+ var rot = new x3dom.fields.Quaternion(0, 0, 1, 0);
+ rot.setValue(mat);
+
+ return rot;
+};
+
+x3dom.Moveable.prototype.over = function(event) {
+ var that = this._iMove;
+
+ that._runtime.getCanvas().style.cursor = "crosshair";
+};
+
+x3dom.Moveable.prototype.out = function(event) {
+ var that = this._iMove;
+
+ if (!that._drag)
+ that._runtime.getCanvas().style.cursor = "pointer";
+};
+
+// start object movement, switch from navigation to interaction
+x3dom.Moveable.prototype.start = function(event) {
+ var that = this._iMove;
+
+ // use mouse button to distinguish between parallel or orthogonal movement or rotation
+ switch (that._mode) {
+ case "translation":
+ that._buttonState = (event.button == 4) ? 1 : (event.button & 3);
+ break;
+ case "rotation":
+ that._buttonState = 4;
+ break;
+ case "all":
+ default:
+ that._buttonState = event.button;
+ break;
+ }
+
+ if (!that._drag && that._buttonState) {
+ that._lastX = event.layerX;
+ that._lastY = event.layerY;
+
+ that._drag = true;
+
+ // temporarily disable navigation
+ that._navType = that._runtime.navigationType();
+ that._runtime.noNav();
+
+ // calc view-aligned plane through original pick position
+ that._isect = new x3dom.fields.SFVec3f(event.worldX, event.worldY, event.worldZ);
+ that.calcViewPlane(that._isect);
+
+ that._firstRay = that._runtime.getViewingRay(event.layerX, event.layerY);
+
+ var mTrans = that._moveable.getAttribute("translation");
+ that._matrixTrafo = null;
+
+ if (mTrans) {
+ that._translationOffset = x3dom.fields.SFVec3f.parse(mTrans);
+
+ var mRot = that._moveable.getAttribute("rotation");
+ mRot = mRot ? x3dom.fields.Quaternion.parseAxisAngle(mRot) : new x3dom.fields.Quaternion(0,0,1,0);
+ that._rotationOffset = mRot.toMatrix();
+
+ var mScal = that._moveable.getAttribute("scale");
+ that._scaleOffset = mScal ? x3dom.fields.SFVec3f.parse(mScal) : new x3dom.fields.SFVec3f(1, 1, 1);
+ }
+ else {
+ mTrans = that._moveable.getAttribute("matrix");
+
+ if (mTrans) {
+ that._matrixTrafo = x3dom.fields.SFMatrix4f.parse(mTrans).transpose();
+
+ var translation = new x3dom.fields.SFVec3f(0,0,0),
+ scaleFactor = new x3dom.fields.SFVec3f(1,1,1);
+ var rotation = new x3dom.fields.Quaternion(0,0,1,0),
+ scaleOrientation = new x3dom.fields.Quaternion(0,0,1,0);
+
+ that._matrixTrafo.getTransform(translation, rotation, scaleFactor, scaleOrientation);
+
+ //that._translationOffset = that._matrixTrafo.e3();
+ that._translationOffset = translation;
+ that._rotationOffset = rotation.toMatrix();
+ that._scaleOffset = scaleFactor;
+ }
+ else {
+ that._translationOffset = new x3dom.fields.SFVec3f(0, 0, 0);
+ that._rotationOffset = new x3dom.fields.SFMatrix4f();
+ that._scaleOffset = new x3dom.fields.SFVec3f(1, 1, 1);
+ }
+ }
+
+ that._runtime.getCanvas().style.cursor = "crosshair";
+ }
+};
+
+x3dom.Moveable.prototype.move = function(event) {
+ for (var i=0, n=this._iMove.length; i<n; i++) {
+ var that = this._iMove[i];
+
+ if (that._drag) {
+ var pos = that._runtime.mousePosition(event);
+ var ray = that._runtime.getViewingRay(pos[0], pos[1]);
+
+ var track = null;
+
+ // zoom with right mouse button (2), pan with left (1)
+ if (that._buttonState == 2)
+ track = that.translateZ(that._firstRay, pos[1]);
+ else if (that._buttonState == 1)
+ track = that.translateXY(ray);
+ else // middle button: 4
+ track = that.rotate(pos[0], pos[1]);
+
+ if (track) {
+ if (that._gridSize > 0 && that._buttonState != 4) {
+ var x = that._gridSize * Math.round(track.x / that._gridSize);
+ var y = that._gridSize * Math.round(track.y / that._gridSize);
+ var z = that._gridSize * Math.round(track.z / that._gridSize);
+ track = new x3dom.fields.SFVec3f(x, y, z);
+ }
+
+ if (!that._matrixTrafo) {
+ if (that._buttonState == 4) {
+ that._moveable.setAttribute("rotation", track.toAxisAngle().toString());
+ }
+ else {
+ that._moveable.setAttribute("translation", track.toString());
+ }
+ }
+ else {
+ if (that._buttonState == 4) {
+ that._matrixTrafo.setRotate(track);
+ }
+ else {
+ that._matrixTrafo.setTranslate(track);
+ }
+ that._moveable.setAttribute("matrix", that._matrixTrafo.toGL().toString());
+ }
+
+ if (that._callback) {
+ that._callback(that._moveable, track);
+ }
+ }
+
+ that._lastX = pos[0];
+ that._lastY = pos[1];
+ }
+ }
+};
+
+// stop object movement, switch from interaction to navigation
+x3dom.Moveable.prototype.stop = function(event) {
+ for (var i=0, n=this._iMove.length; i<n; i++) {
+ var that = this._iMove[i];
+
+ if (that._drag) {
+ that._lastX = event.layerX;
+ that._lastY = event.layerY;
+
+ that._isect = null;
+ that._drag = false;
+
+ // we're done, re-enable navigation
+ var navi = that._runtime.canvas.doc._scene.getNavigationInfo();
+ navi.setType(that._navType);
+
+ that._runtime.getCanvas().style.cursor = "pointer";
+ }
+ }
+};
+
+// TODO: impl. special (multi-)touch event stuff
+// === Touch Start (W3C) ===
+x3dom.Moveable.prototype.touchStartHandler = function (evt) {
+ evt.preventDefault();
+};
+
+// === Touch Start Moz (Firefox has other touch interface) ===
+x3dom.Moveable.prototype.touchStartHandlerMoz = function (evt) {
+ evt.preventDefault();
+};
+
+// === Touch Move ===
+x3dom.Moveable.prototype.touchMoveHandler = function (evt) {
+ evt.preventDefault();
+};
+
+// === Touch Move Moz ===
+x3dom.Moveable.prototype.touchMoveHandlerMoz = function (evt) {
+ evt.preventDefault();
+};
+
+// === Touch End ===
+x3dom.Moveable.prototype.touchEndHandler = function (evt) {
+ if (this._iMove.length) {
+ var that = this._iMove[0];
+ // mouse start code is called, but not stop
+ that.stop.apply(that._x3domRoot, [evt]);
+ }
+ evt.preventDefault();
+};
+
+// === Touch End Moz ===
+x3dom.Moveable.prototype.touchEndHandlerMoz = function (evt) {
+ if (this._iMove.length) {
+ var that = this._iMove[0];
+ that.stop.apply(that._x3domRoot, [evt]);
+ }
+ evt.preventDefault();
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * The canvas object wraps the HTML canvas x3dom draws
+ * @constructs x3dom.X3DCanvas
+ * @param {Object} [x3dElement] - x3d element rendering into the canvas
+ * @param {String} [canvasIdx] - id of HTML canvas
+ */
+x3dom.X3DCanvas = function(x3dElem, canvasIdx)
+{
+ var that = this;
+
+ /**
+ * The index of the HTML canvas
+ * @member {String} _canvasIdx
+ */
+ this._canvasIdx = canvasIdx;
+
+ /**
+ * Flag if flash is ready - needed for WebKit Browser
+ * @member {Boolean} isFlashReady
+ */
+ this.isFlashReady = false;
+
+ /**
+ * The X3D Element
+ * @member {X3DElement} x3dElem
+ */
+ this.x3dElem = x3dElem;
+
+ /**
+ * The current canvas dimensions
+ * @member {Array} _current_dim
+ */
+ this._current_dim = [0, 0];
+
+ // for FPS measurements
+ this.fps_t0 = new Date().getTime();
+ this.lastTimeFPSWasTaken = 0;
+ this.framesSinceLastTime = 0;
+
+ this.doc = null;
+
+ this.lastMousePos = { x: 0, y: 0 };
+ //try to determine behavior of certain DOMNodeInsertedEvent:
+ //IE11 dispatches one event for each node in an inserted subtree, other browsers use a single event per subtree
+ x3dom.caps.DOMNodeInsertedEvent_perSubtree = !(navigator.userAgent.indexOf('MSIE') != -1 ||
+ navigator.userAgent.indexOf('Trident') != -1 );
+
+ // allow listening for (size) changes
+ x3dElem.__setAttribute = x3dElem.setAttribute;
+
+ //adds setAttribute function for width and height to the X3D element
+ x3dElem.setAttribute = function(attrName, newVal)
+ {
+ this.__setAttribute(attrName, newVal);
+
+ switch(attrName) {
+
+ case "width":
+ that.canvas.setAttribute("width", newVal);
+ if (that.doc && that.doc._viewarea) {
+ that.doc._viewarea._width = parseInt(that.canvas.getAttribute("width"), 0);
+ that.doc.needRender = true;
+ }
+ break;
+
+ case "height":
+ that.canvas.setAttribute("height", newVal);
+ if (that.doc && that.doc._viewarea) {
+ that.doc._viewarea._height = parseInt(that.canvas.getAttribute("height"), 0);
+ that.doc.needRender = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ };
+
+
+ x3dom.caps.MOBILE = (navigator.appVersion.indexOf("Mobile") > -1);
+
+ this.backend = this.x3dElem.getAttribute('backend');
+ if (this.backend)
+ this.backend = this.backend.toLowerCase();
+ else
+ this.backend = 'none';
+
+ if (this.backend == 'flash') {
+ this.backend = 'flash';
+ this.canvas = this._createFlashObject(x3dElem);
+ if (this.canvas != null) {
+ this.canvas.parent = this;
+ this.gl = this._initFlashContext(this.canvas, this.flash_renderType);
+ } else {
+ this._createInitFailedDiv(x3dElem);
+ return;
+ }
+ } else {
+ this.canvas = this._createHTMLCanvas(x3dElem);
+ this.canvas.parent = this;
+ this.gl = this._initContext( this.canvas,
+ (this.backend.search("desktop") >= 0),
+ (this.backend.search("mobile") >= 0),
+ (this.backend.search("flashie") >= 0),
+ (this.backend.search("webgl2") >= 0));
+ this.backend = 'webgl';
+ if (this.gl == null)
+ {
+ x3dom.debug.logInfo("Fallback to Flash Renderer");
+ this.backend = 'flash';
+ this.canvas = this._createFlashObject(x3dElem);
+ if (this.canvas != null) {
+ this.canvas.parent = this;
+ this.gl = this._initFlashContext(this.canvas, this.flash_renderType);
+ } else {
+ this._createInitFailedDiv(x3dElem);
+ return;
+ }
+ }
+ }
+
+ x3dom.caps.BACKEND = this.backend;
+
+ var runtimeEnabled = x3dElem.getAttribute("runtimeEnabled");
+
+ if (runtimeEnabled !== null) {
+ this.hasRuntime = (runtimeEnabled.toLowerCase() == "true");
+ } else {
+ this.hasRuntime = x3dElem.hasRuntime;
+ }
+
+ if (this.gl === null) {
+ this.hasRuntime = false;
+ }
+
+ //States only needed for the webgl backend. flash has his own.
+ if (this.backend != "flash") {
+ this.showStat = x3dElem.getAttribute("showStat");
+
+ this.stateViewer = new x3dom.States(x3dElem);
+ if (this.showStat !== null && this.showStat == "true") {
+ this.stateViewer.display(true);
+ }
+
+ this.x3dElem.appendChild(this.stateViewer.viewer);
+ }
+
+ // progress bar
+ this.showProgress = x3dElem.getAttribute("showProgress");
+ this.progressDiv = this._createProgressDiv();
+ this.progressDiv.style.display = (this.showProgress !== null && this.showProgress == "true") ? "inline" : "none";
+ this.x3dElem.appendChild(this.progressDiv);
+
+ // touch visualization
+ this.showTouchpoints = x3dElem.getAttribute("showTouchpoints");
+ this.showTouchpoints = this.showTouchpoints ? !(this.showTouchpoints.toLowerCase() == "false") : true;
+ //this.showTouchpoints = this.showTouchpoints ? (this.showTouchpoints.toLowerCase() == "true") : false;
+
+ // disable touch events
+ this.disableTouch = x3dElem.getAttribute("disableTouch");
+ this.disableTouch = this.disableTouch ? (this.disableTouch.toLowerCase() == "true") : false;
+
+
+ if (this.canvas !== null && this.gl !== null && this.hasRuntime && this.backend !== "flash") {
+ // event handler for mouse interaction
+ this.canvas.mouse_dragging = false;
+ this.canvas.mouse_button = 0;
+ this.canvas.mouse_drag_x = 0;
+ this.canvas.mouse_drag_y = 0;
+
+ this.canvas.isMulti = false; // don't interfere with multi-touch
+
+ this.canvas.oncontextmenu = function(evt) {
+ evt.preventDefault();
+ evt.stopPropagation();
+ return false;
+ };
+
+ // TODO: handle context lost events properly
+ this.canvas.addEventListener("webglcontextlost", function(event) {
+ x3dom.debug.logError("WebGL context lost");
+ event.preventDefault();
+ }, false);
+
+ this.canvas.addEventListener("webglcontextrestored", function(event) {
+ x3dom.debug.logError("recover WebGL state and resources on context lost NYI");
+ event.preventDefault();
+ }, false);
+
+
+ // Mouse Events
+ this.canvas.addEventListener('mousedown', function (evt) {
+ if(!this.isMulti) {
+ this.focus();
+ this.classList.add('x3dom-canvas-mousedown');
+
+ switch(evt.button) {
+ case 0: this.mouse_button = 1; break; //left
+ case 1: this.mouse_button = 4; break; //middle
+ case 2: this.mouse_button = 2; break; //right
+ default: this.mouse_button = 0; break;
+ }
+
+ if (evt.shiftKey) { this.mouse_button = 1; }
+ if (evt.ctrlKey) { this.mouse_button = 4; }
+ if (evt.altKey) { this.mouse_button = 2; }
+
+ var pos = this.parent.mousePosition(evt);
+ this.mouse_drag_x = pos.x;
+ this.mouse_drag_y = pos.y;
+
+ this.mouse_dragging = true;
+
+ this.parent.doc.onMousePress(that.gl, this.mouse_drag_x, this.mouse_drag_y, this.mouse_button);
+ this.parent.doc.needRender = true;
+ }
+ }, false);
+
+ this.canvas.addEventListener('mouseup', function (evt) {
+ if(!this.isMulti) {
+ var prev_mouse_button = this.mouse_button;
+ this.classList.remove('x3dom-canvas-mousedown');
+
+ this.mouse_button = 0;
+ this.mouse_dragging = false;
+
+ this.parent.doc.onMouseRelease(that.gl, this.mouse_drag_x, this.mouse_drag_y, this.mouse_button, prev_mouse_button);
+ this.parent.doc.needRender = true;
+ }
+ }, false);
+
+ this.canvas.addEventListener('mouseover', function (evt) {
+ if(!this.isMulti) {
+ this.mouse_button = 0;
+ this.mouse_dragging = false;
+
+ this.parent.doc.onMouseOver(that.gl, this.mouse_drag_x, this.mouse_drag_y, this.mouse_button);
+ this.parent.doc.needRender = true;
+ }
+ }, false);
+
+ this.canvas.addEventListener('mouseout', function (evt) {
+ if(!this.isMulti) {
+ this.mouse_button = 0;
+ this.mouse_dragging = false;
+ this.classList.remove('x3dom-canvas-mousedown');
+
+ this.parent.doc.onMouseOut(that.gl, this.mouse_drag_x, this.mouse_drag_y, this.mouse_button);
+ this.parent.doc.needRender = true;
+ }
+ }, false);
+
+ this.canvas.addEventListener('dblclick', function (evt) {
+ if(!this.isMulti) {
+ this.mouse_button = 0;
+
+ var pos = this.parent.mousePosition(evt);
+ this.mouse_drag_x = pos.x;
+ this.mouse_drag_y = pos.y;
+
+ this.mouse_dragging = false;
+
+ this.parent.doc.onDoubleClick(that.gl, this.mouse_drag_x, this.mouse_drag_y);
+ this.parent.doc.needRender = true;
+ }
+ }, false);
+
+ this.canvas.addEventListener('mousemove', function (evt) {
+ if(!this.isMulti) {
+
+ var pos = this.parent.mousePosition(evt);
+
+ if ( pos.x != that.lastMousePos.x || pos.y != that.lastMousePos.y ) {
+ that.lastMousePos = pos;
+ if (evt.shiftKey) { this.mouse_button = 1; }
+ if (evt.ctrlKey) { this.mouse_button = 4; }
+ if (evt.altKey) { this.mouse_button = 2; }
+
+ this.mouse_drag_x = pos.x;
+ this.mouse_drag_y = pos.y;
+
+ if (this.mouse_dragging) {
+ this.parent.doc.onDrag(that.gl, this.mouse_drag_x, this.mouse_drag_y, this.mouse_button);
+ }
+ else {
+ this.parent.doc.onMove(that.gl, this.mouse_drag_x, this.mouse_drag_y, this.mouse_button);
+ }
+
+ this.parent.doc.needRender = true;
+
+ // deliberately different for performance reasons
+ evt.preventDefault();
+ evt.stopPropagation();
+ }
+ }
+ }, false);
+
+ this.canvas.addEventListener('DOMMouseScroll', function (evt) {
+ if(!this.isMulti) {
+ this.focus();
+
+ var originalY = this.parent.mousePosition(evt).y;
+
+ this.mouse_drag_y += 2 * evt.detail;
+
+ this.parent.doc.onWheel(that.gl, this.mouse_drag_x, this.mouse_drag_y, originalY);
+ this.parent.doc.needRender = true;
+
+ evt.preventDefault();
+ evt.stopPropagation();
+ }
+ }, false);
+
+ this.canvas.addEventListener('mousewheel', function (evt) {
+ if(!this.isMulti) {
+ this.focus();
+
+ var originalY = this.parent.mousePosition(evt).y;
+
+ this.mouse_drag_y -= 0.1 * evt.wheelDelta;
+
+ this.parent.doc.onWheel(that.gl, this.mouse_drag_x, this.mouse_drag_y, originalY);
+ this.parent.doc.needRender = true;
+
+ evt.preventDefault();
+ evt.stopPropagation();
+ }
+ }, false);
+
+
+ // Key Events
+ this.canvas.addEventListener('keypress', function (evt) {
+ var keysEnabled = this.parent.x3dElem.getAttribute("keysEnabled");
+ if (!keysEnabled || keysEnabled.toLowerCase() == "true") {
+ this.parent.doc.onKeyPress(evt.charCode);
+ }
+ this.parent.doc.needRender = true;
+ }, true);
+
+ // in webkit special keys are only handled on key-up
+ this.canvas.addEventListener('keyup', function (evt) {
+ var keysEnabled = this.parent.x3dElem.getAttribute("keysEnabled");
+ if (!keysEnabled || keysEnabled.toLowerCase() == "true") {
+ this.parent.doc.onKeyUp(evt.keyCode);
+ }
+ this.parent.doc.needRender = true;
+ }, true);
+
+ this.canvas.addEventListener('keydown', function (evt) {
+ var keysEnabled = this.parent.x3dElem.getAttribute("keysEnabled");
+ if (!keysEnabled || keysEnabled.toLowerCase() == "true") {
+ this.parent.doc.onKeyDown(evt.keyCode);
+ }
+ this.parent.doc.needRender = true;
+ }, true);
+
+
+ // Multitouch Events
+ var touches =
+ {
+ numTouches : 0,
+
+ firstTouchTime: new Date().getTime(),
+ firstTouchPoint: new x3dom.fields.SFVec2f(0,0),
+
+ lastPos : new x3dom.fields.SFVec2f(),
+ lastDrag : new x3dom.fields.SFVec2f(),
+
+ lastMiddle : new x3dom.fields.SFVec2f(),
+ lastSquareDistance : 0,
+ lastAngle : 0,
+ lastLayer : [],
+
+ examineNavType: 1,
+
+ calcAngle : function(vector)
+ {
+ var rotation = vector.normalize().dot(new x3dom.fields.SFVec2f(1,0));
+ rotation = Math.acos(rotation);
+
+ if(vector.y < 0)
+ rotation = Math.PI + (Math.PI - rotation);
+
+ return rotation;
+ },
+
+ disableTouch: this.disableTouch,
+ // set a marker in HTML so we can track the position of the finger visually
+ visMarker: this.showTouchpoints,
+ visMarkerBag: [],
+
+ visualizeTouches: function(evt)
+ {
+ if (!this.visMarker)
+ return;
+
+ var touchBag = [];
+ var marker = null;
+
+ for (var i=0; i<evt.touches.length; i++) {
+ var id = evt.touches[i].identifier || evt.touches[i].streamId;
+ if (!id) id = 0;
+
+ var index = this.visMarkerBag.indexOf(id);
+
+ if (index >= 0) {
+ marker = document.getElementById("visMarker" + id);
+
+ marker.style.left = (evt.touches[i].pageX) + "px";
+ marker.style.top = (evt.touches[i].pageY) + "px";
+ }
+ else {
+ marker = document.createElement("div");
+
+ marker.appendChild(document.createTextNode("#" + id));
+ marker.id = "visMarker" + id;
+ marker.className = "x3dom-touch-marker";
+ document.body.appendChild(marker);
+
+ index = this.visMarkerBag.length;
+ this.visMarkerBag[index] = id;
+ }
+
+ touchBag.push(id);
+ }
+
+ for (var j=this.visMarkerBag.length-1; j>=0; j--) {
+ var oldId = this.visMarkerBag[j];
+
+ if (touchBag.indexOf(oldId) < 0) {
+ this.visMarkerBag.splice(j, 1);
+ marker = document.getElementById("visMarker" + oldId);
+ document.body.removeChild(marker);
+ }
+ }
+ }
+ };
+
+ // Mozilla Touches (seems obsolete now...)
+ var mozilla_ids = [];
+
+ var mozilla_touches =
+ {
+ touches : [],
+ preventDefault : function() {}
+ };
+
+ // === Touch Start ===
+ var touchStartHandler = function(evt, doc)
+ {
+ this.isMulti = true;
+ evt.preventDefault();
+ touches.visualizeTouches(evt);
+
+ this.focus();
+
+ if (doc == null)
+ doc = this.parent.doc;
+
+ var navi = doc._scene.getNavigationInfo();
+
+ switch(navi.getType()) {
+ case "examine":
+ touches.examineNavType = 1;
+ break;
+ case "turntable":
+ touches.examineNavType = 2;
+ break;
+ default:
+ touches.examineNavType = 0;
+ break;
+ }
+
+ touches.lastLayer = [];
+
+ var i, pos;
+ for(i = 0; i < evt.touches.length; i++) {
+ pos = this.parent.mousePosition(evt.touches[i]);
+ touches.lastLayer.push([evt.touches[i].identifier, new x3dom.fields.SFVec2f(pos.x,pos.y)]);
+ }
+
+ if(touches.numTouches < 1 && evt.touches.length == 1) {
+
+ touches.numTouches = 1;
+ touches.lastDrag = new x3dom.fields.SFVec2f(evt.touches[0].screenX, evt.touches[0].screenY);
+ }
+ else if(touches.numTouches < 2 && evt.touches.length >= 2) {
+
+ touches.numTouches = 2;
+
+ var touch0 = new x3dom.fields.SFVec2f(evt.touches[0].screenX, evt.touches[0].screenY);
+ var touch1 = new x3dom.fields.SFVec2f(evt.touches[1].screenX, evt.touches[1].screenY);
+
+ var distance = touch1.subtract(touch0);
+ var middle = distance.multiply(0.5).add(touch0);
+ var squareDistance = distance.dot(distance);
+
+ touches.lastMiddle = middle;
+ touches.lastSquareDistance = squareDistance;
+ touches.lastAngle = touches.calcAngle(distance);
+
+ touches.lastPos = this.parent.mousePosition(evt.touches[0]);
+ }
+
+ // update scene bbox
+ doc._scene.updateVolume();
+
+ if (touches.examineNavType == 1) {
+ for(i = 0; i < evt.touches.length; i++) {
+ pos = this.parent.mousePosition(evt.touches[i]);
+ doc.onPick(that.gl, pos.x, pos.y);
+ doc._viewarea.prepareEvents(pos.x, pos.y, 1, "onmousedown");
+ doc._viewarea._pickingInfo.lastClickObj = doc._viewarea._pickingInfo.pickObj;
+ }
+ }
+ else if (evt.touches.length) {
+ pos = this.parent.mousePosition(evt.touches[0]);
+ doc.onMousePress(that.gl, pos.x, pos.y, 1); // 1 means left mouse button
+ }
+
+ doc.needRender = true;
+ };
+
+ var touchStartHandlerMoz = function(evt)
+ {
+ this.isMulti = true;
+ evt.preventDefault();
+
+ var new_id = true;
+ for(var i=0; i<mozilla_ids.length; ++i)
+ if(mozilla_ids[i] == evt.streamId)
+ new_id = false;
+
+ if(new_id == true) {
+ evt.identifier = evt.streamId;
+ mozilla_ids.push(evt.streamId);
+ mozilla_touches.touches.push(evt);
+ }
+ touchStartHandler(mozilla_touches, this.parent.doc);
+ };
+
+ // === Touch Move ===
+ var touchMoveHandler = function(evt, doc)
+ {
+ evt.preventDefault();
+ touches.visualizeTouches(evt);
+
+ if (doc == null)
+ doc = this.parent.doc;
+
+ var pos = null;
+ var rotMatrix = null;
+
+ var touch0, touch1, distance, middle, squareDistance, deltaMiddle, deltaZoom, deltaMove;
+
+ if (touches.examineNavType == 1) {
+ /*
+ if (doc._scene._vf.doPickPass && doc._scene._vf.pickMode.toLowerCase() !== "box") {
+ for(var i = 0; i < evt.touches.length; i++) {
+ pos = this.parent.mousePosition(evt.touches[i]);
+ doc.onPick(that.gl, pos.x, pos.y);
+
+ doc._viewarea.handleMoveEvt(pos.x, pos.y, 1);
+ }
+ }
+ */
+
+ // one finger: x/y rotation
+ if(evt.touches.length == 1) {
+ var currentDrag = new x3dom.fields.SFVec2f(evt.touches[0].screenX, evt.touches[0].screenY);
+
+ var deltaDrag = currentDrag.subtract(touches.lastDrag);
+ touches.lastDrag = currentDrag;
+
+ var mx = x3dom.fields.SFMatrix4f.rotationY(deltaDrag.x / 100);
+ var my = x3dom.fields.SFMatrix4f.rotationX(deltaDrag.y / 100);
+ rotMatrix = mx.mult(my);
+
+ doc.onMoveView(that.gl, null, rotMatrix);
+ }
+ // two fingers: scale, translation, rotation around view (z) axis
+ else if(evt.touches.length >= 2) {
+ touch0 = new x3dom.fields.SFVec2f(evt.touches[0].screenX, evt.touches[0].screenY);
+ touch1 = new x3dom.fields.SFVec2f(evt.touches[1].screenX, evt.touches[1].screenY);
+
+ distance = touch1.subtract(touch0);
+ middle = distance.multiply(0.5).add(touch0);
+ squareDistance = distance.dot(distance);
+
+ deltaMiddle = middle.subtract(touches.lastMiddle);
+ deltaZoom = squareDistance - touches.lastSquareDistance;
+
+ deltaMove = new x3dom.fields.SFVec3f(
+ deltaMiddle.x / screen.width, -deltaMiddle.y / screen.height,
+ deltaZoom / (screen.width * screen.height * 0.2));
+
+ var rotation = touches.calcAngle(distance);
+ var angleDelta = touches.lastAngle - rotation;
+ touches.lastAngle = rotation;
+
+ rotMatrix = x3dom.fields.SFMatrix4f.rotationZ(angleDelta);
+
+ touches.lastMiddle = middle;
+ touches.lastSquareDistance = squareDistance;
+
+ doc.onMoveView(that.gl, deltaMove, rotMatrix);
+ }
+ }
+ else if (evt.touches.length) {
+ if (touches.examineNavType == 2 && evt.touches.length >= 2) {
+ touch0 = new x3dom.fields.SFVec2f(evt.touches[0].screenX, evt.touches[0].screenY);
+ touch1 = new x3dom.fields.SFVec2f(evt.touches[1].screenX, evt.touches[1].screenY);
+
+ distance = touch1.subtract(touch0);
+ squareDistance = distance.dot(distance);
+ deltaZoom = (squareDistance - touches.lastSquareDistance) / (0.1 * (screen.width + screen.height));
+
+ touches.lastPos.y += deltaZoom;
+ touches.lastSquareDistance = squareDistance;
+
+ doc.onDrag(that.gl, touches.lastPos.x, touches.lastPos.y, 2);
+ }
+ else {
+ pos = this.parent.mousePosition(evt.touches[0]);
+
+ doc.onDrag(that.gl, pos.x, pos.y, 1);
+ }
+ }
+
+ doc.needRender = true;
+ };
+
+ var touchMoveHandlerMoz = function(evt)
+ {
+ evt.preventDefault();
+
+ for(var i=0; i<mozilla_ids.length; ++i)
+ if(mozilla_ids[i] == evt.streamId)
+ mozilla_touches.touches[i] = evt;
+
+ touchMoveHandler(mozilla_touches, this.parent.doc);
+ };
+
+ // === Touch end ===
+ var touchEndHandler = function(evt, doc)
+ {
+ this.isMulti = false;
+ evt.preventDefault();
+ touches.visualizeTouches(evt);
+
+ if (doc == null)
+ doc = this.parent.doc;
+
+ doc._viewarea._isMoving = false;
+
+ // reinit first finger for rotation
+ if (touches.numTouches == 2 && evt.touches.length == 1)
+ touches.lastDrag = new x3dom.fields.SFVec2f(evt.touches[0].screenX, evt.touches[0].screenY);
+
+ var dblClick = false;
+
+ if (evt.touches.length < 2) {
+ if (touches.numTouches == 1)
+ dblClick = true;
+ touches.numTouches = evt.touches.length;
+ }
+
+ if (touches.examineNavType == 1) {
+ for(var i = 0; i < touches.lastLayer.length; i++) {
+ var pos = touches.lastLayer[i][1];
+
+ doc.onPick(that.gl, pos.x, pos.y);
+
+ if (doc._scene._vf.pickMode.toLowerCase() !== "box") {
+ doc._viewarea.prepareEvents(pos.x, pos.y, 1, "onmouseup");
+ doc._viewarea._pickingInfo.lastClickObj = doc._viewarea._pickingInfo.pickObj;
+
+ // click means that mousedown _and_ mouseup were detected on same element
+ if (doc._viewarea._pickingInfo.pickObj &&
+ doc._viewarea._pickingInfo.pickObj ===
+ doc._viewarea._pickingInfo.lastClickObj) {
+
+ doc._viewarea.prepareEvents(pos.x, pos.y, 1, "onclick");
+ }
+ }
+ else {
+ var line = doc._viewarea.calcViewRay(pos.x, pos.y);
+ var isect = doc._scene.doIntersect(line);
+ var obj = line.hitObject;
+
+ if (isect && obj) {
+ doc._viewarea._pick.setValues(line.hitPoint);
+ doc._viewarea.checkEvents(obj, pos.x, pos.y, 1, "onclick");
+
+ x3dom.debug.logInfo("Hit '" + obj._xmlNode.localName + "/ " +
+ obj._DEF + "' at pos " + doc._viewarea._pick);
+ }
+ }
+ }
+
+ if (dblClick) {
+ var now = new Date().getTime();
+ var dist = touches.firstTouchPoint.subtract(touches.lastDrag).length();
+
+ if (dist < 18 && now - touches.firstTouchTime < 180)
+ doc.onDoubleClick(that.gl, 0, 0);
+
+ touches.firstTouchTime = now;
+ touches.firstTouchPoint = touches.lastDrag;
+ }
+ }
+ else if (touches.lastLayer.length) {
+ pos = touches.lastLayer[0][1];
+ doc.onMouseRelease(that.gl, pos.x, pos.y, 0, 1);
+ }
+
+ doc.needRender = true;
+ };
+
+ var touchEndHandlerMoz = function(evt)
+ {
+ this.isMulti = false;
+ evt.preventDefault();
+
+ var remove_index = -1;
+ for(var i=0; i<mozilla_ids.length; ++i)
+ if(mozilla_ids[i] == evt.streamId)
+ remove_index = i;
+
+ if(remove_index != -1)
+ {
+ mozilla_ids.splice(remove_index, 1);
+ mozilla_touches.touches.splice(remove_index, 1);
+ }
+
+ touchEndHandler(mozilla_touches, this.parent.doc);
+ };
+
+ if (!this.disableTouch)
+ {
+ // mozilla touch events (TODO: seem to be obsolete now, completely remove all code if no one complains!)
+ // However, touch in general seems to be broken if this flag is not set: dom.w3c_touch_events.enabled;10
+ //this.canvas.addEventListener('MozTouchDown', touchStartHandlerMoz, true);
+ //this.canvas.addEventListener('MozTouchMove', touchMoveHandlerMoz, true);
+ //this.canvas.addEventListener('MozTouchUp', touchEndHandlerMoz, true);
+
+ // w3c / apple touch events (in Chrome via chrome://flags)
+ this.canvas.addEventListener('touchstart', touchStartHandler, true);
+ this.canvas.addEventListener('touchmove', touchMoveHandler, true);
+ this.canvas.addEventListener('touchend', touchEndHandler, true);
+ }
+ }
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Creates the WebGL context and returns it
+ * @returns {WebGLContext} gl
+ * @param {HTMLCanvas} canvas
+ * @param {Boolean} forbidMobileShaders - no mobile shaders allowed
+ * @param {Boolean} forceMobileShaders - force mobile shaders
+ * @param {Boolean} forceFlashForIE - force flash backend for internet explorer
+ * @param {Boolean} tryWebGL2 - try to retrieve a WebGL2 context
+ */
+x3dom.X3DCanvas.prototype._initContext = function(canvas, forbidMobileShaders, forceMobileShaders, forceFlashForIE, tryWebGL2)
+{
+ x3dom.debug.logInfo("Initializing X3DCanvas for [" + canvas.id + "]");
+ var gl = x3dom.gfx_webgl(canvas, forbidMobileShaders, forceMobileShaders, tryWebGL2, this.x3dElem);
+
+ if (!gl)
+ {
+ x3dom.debug.logError("No 3D context found...");
+ this.x3dElem.removeChild(canvas);
+ return null;
+ }
+ else
+ {
+ var webglVersion = parseFloat(x3dom.caps.VERSION.match(/\d+\.\d+/)[0]);
+ if (webglVersion < 1.0) {
+ console.log(forceFlashForIE);
+ if (forceFlashForIE) {
+ x3dom.debug.logError("No valid 3D context found...");
+ this.x3dElem.removeChild(canvas);
+ return null;
+ } else {
+ x3dom.debug.logError("WebGL version " + x3dom.caps.VERSION +
+ " lacks important WebGL/GLSL features needed for shadows, special vertex attribute types, etc.!");
+ }
+ }
+ }
+
+ return gl;
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Creates the WebGL context and returns it
+ * @returns {WebGLContext} gl
+ * @param {HTMLCanvas} canvas - the HTMLCanvas
+ * @param {Object} renderType - the renderType for the Flash backend
+ */
+x3dom.X3DCanvas.prototype._initFlashContext = function(canvas, renderType) {
+ x3dom.debug.logInfo("Initializing X3DObject for [" + canvas.id + "]");
+ return x3dom.gfx_flash(canvas, renderType);
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Creates a param node and adds it to the target node's children
+ * @param {String} node - the target node
+ * @param {String} name - the name for the parameter
+ * @param {String} value - the value for the parameter
+ */
+x3dom.X3DCanvas.prototype.appendParam = function(node, name, value) {
+ var param = document.createElement('param');
+ param.setAttribute('name', name);
+ param.setAttribute('value', value);
+ node.appendChild( param );
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Tests if a file exists
+ * @returns {Boolean}
+ * @param {String} url - the url to be tested
+ */
+x3dom.X3DCanvas.prototype._fileExists = function(url) {
+ var xhr = new XMLHttpRequest();
+ try {
+ xhr.open("HEAD", url, false);
+ xhr.send(null);
+ return (xhr.status != 404);
+ } catch(e) { return true; }
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Detects if flash is available
+ * @returns {Boolean}
+ * @param {String} required - required version
+ * @param {String} max - maximal compatible version
+ */
+x3dom.X3DCanvas.prototype._detectFlash = function(required, max)
+{
+ var required_version = required;
+ var max_version = max;
+ var available_version = 0;
+
+ /* this section is for NS, Mozilla, Firefox and similar Browsers */
+ if(typeof(navigator.plugins["Shockwave Flash"]) == "object")
+ {
+ var description = navigator.plugins["Shockwave Flash"].description;
+ available_version = description.substr(16, (description.indexOf(".", 16) - 16));
+ }
+ else if(typeof(ActiveXObject) == "function") {
+ for(var i = 10; i < (max_version + 1); i ++) {
+ try {
+ if(typeof(new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + i)) == "object") {
+ available_version = i+1;
+ }
+ }
+ catch(error){}
+ }
+ }
+
+ return [available_version, required_version];
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Creates a div to inform the user that the initialization failed
+ * @param {String} x3dElem - the X3D element
+ */
+x3dom.X3DCanvas.prototype._createInitFailedDiv = function(x3dElem) {
+ var div = document.createElement('div');
+ div.setAttribute("id", "x3dom-create-init-failed");
+ div.style.width = x3dElem.getAttribute("width");
+ div.style.height = x3dElem.getAttribute("height");
+ div.style.backgroundColor = "#C00";
+ div.style.color = "#FFF";
+ div.style.fontSize = "20px";
+ div.style.fontWidth = "bold";
+ div.style.padding = "10px 10px 10px 10px";
+ div.style.display = "inline-block";
+ div.style.fontFamily = "Helvetica";
+ div.style.textAlign = "center";
+
+ div.appendChild(document.createTextNode('Your Browser does not support X3DOM'));
+ div.appendChild(document.createElement('br'));
+ div.appendChild(document.createTextNode('Read more about Browser support on:'));
+ div.appendChild(document.createElement('br'));
+
+ var link = document.createElement('a');
+ link.setAttribute('href', 'http://www.x3dom.org/?page_id=9');
+ link.appendChild( document.createTextNode('X3DOM | Browser Support'));
+ div.appendChild(link);
+
+ // check if "altImg" is specified on x3d element and if so use it as background
+ var altImg = x3dElem.getAttribute("altImg") || null;
+ if (altImg) {
+ var altImgObj = new Image();
+ altImgObj.src = altImg;
+ div.style.backgroundImage = "url("+altImg+")";
+ div.style.backgroundRepeat = "no-repeat";
+ div.style.backgroundPosition = "50% 50%";
+ }
+
+ x3dElem.appendChild(div);
+
+ x3dom.debug.logError("Your Browser does not support X3DOM!");
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Creates the flash object used as render target
+ * @returns {Object} - the flash object
+ * @param {HTMLNode} x3dElem - the X3D root node
+ */
+x3dom.X3DCanvas.prototype._createFlashObject = function (x3dElem) {
+
+ var result = this._detectFlash(11, 11);
+
+ if (!result[0] || result[0] < result[1]) {
+ return null;
+ } else {
+
+ x3dom.debug.logInfo("Creating FlashObject for (X)3D element...");
+
+ //Get X3D-Element ID
+ var id = this.x3dElem.getAttribute("id");
+ if (id !== null) {
+ id = "x3dom-" + id + "-object";
+ } else {
+ var index = new Date().getTime();
+ id = "x3dom-" + index + "-object";
+ }
+
+ //Get SWFPath
+ var swf_path = this.x3dElem.getAttribute("swfpath");
+ if (swf_path === null) {
+ swf_path = "x3dom.swf";
+ }
+
+ if (!this._fileExists(swf_path)) {
+ var version;
+
+ //No version info or a dev string?
+ if (x3dom.versionInfo === undefined || x3dom.versionInfo.version.indexOf('dev') != -1) //use dev version
+ {
+ version = "dev";
+ }
+ //Stable version?
+ else
+ {
+ version = x3dom.versionInfo.version;
+
+ //If version ends with ".0" (modification number), remove this part from path to download folder
+ var modification = version.substr(version.length-1);
+ if(modification == 0) {
+ version = version.substr(0, 3);
+ }
+ }
+
+ swf_path = "http://www.x3dom.org/download/" + version + "/x3dom.swf";
+
+ x3dom.debug.logWarning("Can't find local x3dom.swf (" + version + "). X3DOM now using the online version from x3dom.org." +
+ "The online version needs a <a href='http://examples.x3dom.org/crossdomain.xml'>crossdomain.xml</a> " +
+ "file in the root directory of your domain to access textures");
+ }
+
+ //Get width from x3d-Element or set default
+ var width = this.x3dElem.getAttribute("width");
+ var idx = -1;
+ if (width == null) {
+ width = 550;
+ } else {
+ idx = width.indexOf("px");
+ if (idx != -1) {
+ width = width.substr(0, idx);
+ }
+ }
+ //Get height from x3d-Element or set default
+ var height = this.x3dElem.getAttribute("height");
+ if (height == null) {
+ height = 400;
+ } else {
+ idx = height.indexOf("px");
+ if (idx != -1) {
+ height = height.substr(0, idx);
+ }
+ }
+
+ //Get flash render type
+ var renderType = this.x3dElem.getAttribute("flashrenderer");
+ if (renderType == null) {
+ this.flash_renderType = "forward";
+ } else {
+ this.flash_renderType = "deferred";
+ }
+
+ var obj = document.createElement('object');
+ obj.setAttribute('width', '100%');
+ obj.setAttribute('height', '100%');
+ obj.setAttribute('id', id);
+
+ //Check for xhtml
+ if (!document.doctype || document.doctype && document.doctype.publicId && document.doctype.publicId.search(/DTD XHTML/i) != -1) {
+ x3dom.debug.logWarning("Flash backend doesn't like XHTML, please use HTML5!");
+ obj.setAttribute('style', 'width:' + width + 'px; height:' + height + 'px;');
+ } else {
+ if (x3dElem.getAttribute('style') == null) {
+ x3dElem.setAttribute('style', 'width:' + width + 'px; height:' + height + 'px;');
+ }
+ }
+
+ this.appendParam(obj, 'menu', 'false');
+ this.appendParam(obj, 'quality', 'high');
+ this.appendParam(obj, 'wmode', 'direct');
+ this.appendParam(obj, 'allowScriptAccess', 'always');
+ this.appendParam(obj, 'flashvars', 'canvasIdx=' + this._canvasIdx + '&renderType=' + this.flash_renderType);
+ this.appendParam(obj, 'movie', swf_path);
+
+ if (navigator.appName == "Microsoft Internet Explorer") {
+ x3dElem.appendChild(obj);
+ obj.setAttribute('classid', 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000');
+ } else {
+ obj.setAttribute('type', 'application/x-shockwave-flash');
+ obj.setAttribute('data', swf_path);
+ x3dElem.appendChild(obj);
+ }
+
+ return obj;
+ }
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Creates the HTML canvas used as render target
+ * @returns {HTMLCanvas} - the created canvas
+ * @param {HTMLNode} x3dElem - the X3D root node
+ */
+x3dom.X3DCanvas.prototype._createHTMLCanvas = function(x3dElem)
+{
+ x3dom.debug.logInfo("Creating canvas for (X)3D element...");
+ var canvas = document.createElement('canvas');
+ canvas.setAttribute("class", "x3dom-canvas");
+
+ // check if user wants to style the X3D element
+ var userStyle = x3dElem.getAttribute("style");
+ if (userStyle) {
+ x3dom.debug.logInfo("Inline X3D styles detected");
+ }
+
+ // check if user wants to attach events to the X3D element
+ var evtArr = [
+ "onmousedown",
+ "onmousemove",
+ "onmouseout",
+ "onmouseover",
+ "onmouseup",
+ "onclick",
+ "ondblclick",
+ "onkeydown",
+ "onkeypress",
+ "onkeyup",
+
+ // w3c touch: http://www.w3.org/TR/2011/WD-touch-events-20110505/
+ "ontouchstart",
+ "ontouchmove",
+ "ontouchend",
+ "ontouchcancel",
+ "ontouchleave",
+ "ontouchenter",
+
+ // mozilla touch
+ //"onMozTouchDown",
+ //"onMozTouchMove",
+ //"onMozTouchUp",
+
+ // drag and drop, requires 'draggable' source property set true (usually of an img)
+ "ondragstart",
+ "ondrop",
+ "ondragover"
+ ];
+
+ // TODO; handle attribute event handlers dynamically during runtime
+ //this step is necessary because of some weird behavior in some browsers:
+ //we need a canvas element on startup to make every callback (e.g., 'onmousemove') work,
+ //which was previously set for the canvas' outer elements
+ for (var i=0; i < evtArr.length; i++)
+ {
+ var evtName = evtArr[i];
+ var userEvt = x3dElem.getAttribute(evtName);
+ if (userEvt) {
+ x3dom.debug.logInfo(evtName +", "+ userEvt);
+
+ canvas.setAttribute(evtName, userEvt);
+
+ //remove the event attribute from the X3D element to prevent duplicate callback invocation
+ x3dElem.removeAttribute(evtName);
+ }
+ }
+
+ var userProp = x3dElem.getAttribute("draggable");
+ if (userProp) {
+ x3dom.debug.logInfo("draggable=" + userProp);
+ canvas.setAttribute("draggable", userProp);
+ }
+
+ // workaround since one cannot find out which handlers are registered
+ if (!x3dElem.__addEventListener && !x3dElem.__removeEventListener)
+ {
+ x3dElem.__addEventListener = x3dElem.addEventListener;
+ x3dElem.__removeEventListener = x3dElem.removeEventListener;
+
+ // helpers to propagate the element's listeners
+ x3dElem.addEventListener = function(type, func, phase) {
+ var j, found = false;
+ for (j=0; j < evtArr.length && !found; j++) {
+ if (evtArr[j] === type) {
+ found = true;
+ }
+ }
+
+ if (found) {
+ x3dom.debug.logInfo('addEventListener for div.on' + type);
+ canvas.addEventListener(type, func, phase);
+ } else {
+ x3dom.debug.logInfo('addEventListener for X3D.on' + type);
+ this.__addEventListener(type, func, phase);
+ }
+ };
+
+ x3dElem.removeEventListener = function(type, func, phase) {
+ var j, found = false;
+ for (j=0; j<evtArr.length && !found; j++) {
+ if (evtArr[j] === type) {
+ found = true;
+ }
+ }
+
+ if (found) {
+ x3dom.debug.logInfo('removeEventListener for div.on' + type);
+ canvas.removeEventListener(type, func, phase);
+ } else {
+ x3dom.debug.logInfo('removeEventListener for X3D.on' + type);
+ this.__removeEventListener(type, func, phase);
+ }
+ };
+ }
+
+ x3dElem.appendChild(canvas);
+
+ // If the X3D element has an id attribute, append "_canvas"
+ // to it and and use that as the id for the canvas
+ var id = x3dElem.getAttribute("id");
+ if (id !== null) {
+ canvas.id = "x3dom-" + id + "-canvas";
+ } else {
+ // If the X3D element does not have an id... do what?
+ // For now check the date for creating a (hopefully) unique id
+ var index = new Date().getTime();
+ canvas.id = "x3dom-" + index + "-canvas";
+ }
+
+ // Apply the width and height of the X3D element to the canvas
+ var w, h;
+
+ if ((w = x3dElem.getAttribute("width")) !== null) {
+ //Attention: pbuffer dim is _not_ derived from style attribs!
+ if (w.indexOf("%") >= 0) {
+ x3dom.debug.logWarning("The width attribute is to be specified in pixels not in percent.");
+ }
+ canvas.style.width = w;
+ canvas.setAttribute("width", w);
+ }
+
+ if ((h = x3dElem.getAttribute("height")) !== null) {
+ //Attention: pbuffer dim is _not_ derived from style attribs!
+ if (h.indexOf("%") >= 0) {
+ x3dom.debug.logWarning("The height attribute is to be specified in pixels not in percent.");
+ }
+ canvas.style.height = h;
+ canvas.setAttribute("height", h);
+ }
+
+ // http://snook.ca/archives/accessibility_and_usability/elements_focusable_with_tabindex
+ canvas.setAttribute("tabindex", "0");
+ // canvas.focus(); ???why - it is necessary - makes touch events break???
+
+ return canvas;
+};
+
+/**
+ * Watches for a resize of the canvas and sets the current dimensions
+ */
+x3dom.X3DCanvas.prototype._watchForResize = function() {
+
+ var new_dim = [
+ parseInt(x3dom.getStyle(this.canvas, "width")),
+ parseInt(x3dom.getStyle(this.canvas, "height"))
+ ];
+
+ if ((this._current_dim[0] != new_dim[0]) || (this._current_dim[1] != new_dim[1])) {
+ this._current_dim = new_dim;
+ this.x3dElem.setAttribute("width", new_dim[0]+"px");
+ this.x3dElem.setAttribute("height", new_dim[1]+"px");
+ }
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Creates the div for progression visualization
+ */
+x3dom.X3DCanvas.prototype._createProgressDiv = function() {
+ var progressDiv = document.createElement('div');
+ progressDiv.setAttribute("class", "x3dom-progress");
+
+ var _text = document.createElement('strong');
+ _text.appendChild(document.createTextNode('Loading...'));
+ progressDiv.appendChild(_text);
+
+ var _inner = document.createElement('span');
+ _inner.setAttribute('style', "width: 25%;");
+ _inner.appendChild(document.createTextNode(' ')); // this needs to be a protected whitespace
+ progressDiv.appendChild(_inner);
+
+ progressDiv.oncontextmenu = progressDiv.onmousedown = function(evt) {
+ evt.preventDefault();
+ evt.stopPropagation();
+ return false;
+ };
+ return progressDiv;
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/** Helper that converts a point from node coordinates to page coordinates
+ FIXME: does NOT work when x3dom.css is not included so that x3d element is not floating
+ */
+x3dom.X3DCanvas.prototype.mousePosition = function(evt)
+{
+ var x = 0, y = 0;
+
+ if ( "getBoundingClientRect" in document.documentElement ) {
+ var elem = evt.target.offsetParent; // should be x3dElem
+ var box = elem.getBoundingClientRect();
+
+ var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
+ var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+
+ var compStyle = document.defaultView.getComputedStyle(elem, null);
+
+ var paddingLeft = parseFloat(compStyle.getPropertyValue('padding-left'));
+ var borderLeftWidth = parseFloat(compStyle.getPropertyValue('border-left-width'));
+
+ var paddingTop = parseFloat(compStyle.getPropertyValue('padding-top'));
+ var borderTopWidth = parseFloat(compStyle.getPropertyValue('border-top-width'));
+
+ x = Math.round(evt.pageX - (box.left + paddingLeft + borderLeftWidth + scrollLeft));
+ y = Math.round(evt.pageY - (box.top + paddingTop + borderTopWidth + scrollTop));
+ }
+ else {
+ x3dom.debug.logError('NO getBoundingClientRect');
+ }
+
+ return new x3dom.fields.SFVec2f(x, y);
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/** Is called in the main loop after every frame
+ */
+x3dom.X3DCanvas.prototype.tick = function()
+{
+ var runtime = this.x3dElem.runtime;
+ var d = new Date().getTime();
+ var diff = d - this.lastTimeFPSWasTaken;
+
+ var fps = 1000.0 / (d - this.fps_t0);
+ this.fps_t0 = d;
+
+ // update routes and stuff
+ this.doc.advanceTime(d / 1000.0);
+ var animD = new Date().getTime() - d;
+
+ if (this.doc.needRender) {
+ // calc average frames per second
+ if (diff >= 1000) {
+ runtime.fps = this.framesSinceLastTime / (diff / 1000.0);
+ runtime.addMeasurement('FPS', runtime.fps);
+
+ this.framesSinceLastTime = 0;
+ this.lastTimeFPSWasTaken = d;
+ }
+ this.framesSinceLastTime++;
+
+ runtime.addMeasurement('ANIM', animD);
+
+ if (runtime.isReady == false) {
+ runtime.ready();
+ runtime.isReady = true;
+ }
+
+ runtime.enterFrame();
+
+ if (this.backend == 'flash') {
+ if (this.isFlashReady) {
+ this.canvas.setFPS({fps: fps});
+
+ this.doc.needRender = false;
+ this.doc.render(this.gl);
+ }
+ }
+ else {
+ // picking might require another pass
+ this.doc.needRender = false;
+ this.doc.render(this.gl);
+
+ if (!this.doc._scene._vf.doPickPass)
+ runtime.removeMeasurement('PICKING');
+ }
+
+ runtime.exitFrame();
+ }
+
+ if (this.progressDiv) {
+ if (this.doc.downloadCount > 0) {
+ runtime.addInfo("#LOADS:", this.doc.downloadCount);
+ } else {
+ runtime.removeInfo("#LOADS:");
+ }
+
+ if (this.doc.properties.getProperty("showProgress") !== 'false') {
+ if (this.progressDiv) {
+ this.progressDiv.childNodes[0].textContent = 'Loading: ' + (+this.doc.downloadCount);
+ if (this.doc.downloadCount > 0) {
+ this.progressDiv.style.display = 'inline';
+ } else {
+ this.progressDiv.style.display = 'none';
+ }
+ }
+ } else {
+ this.progressDiv.style.display = 'none';
+ }
+ }
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/** Loads the given @p uri.
+ * @param uri can be a uri or an X3D node
+ * @param sceneElemPos
+ * @param settings properties
+ */
+x3dom.X3DCanvas.prototype.load = function(uri, sceneElemPos, settings) {
+ this.doc = new x3dom.X3DDocument(this.canvas, this.gl, settings);
+ var x3dCanvas = this;
+
+ this.doc.onload = function () {
+ //x3dom.debug.logInfo("loaded '" + uri + "'");
+
+ if (x3dCanvas.hasRuntime) {
+
+ // requestAnimationFrame https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/common/webgl-utils.js
+ (function mainloop(){
+ if (x3dCanvas.doc && x3dCanvas.x3dElem.runtime) {
+ x3dCanvas._watchForResize();
+ x3dCanvas.tick();
+ window.requestAnimFrame(mainloop, x3dCanvas);
+ }
+ })();
+
+ } else {
+ x3dCanvas.tick();
+ }
+ };
+
+ this.x3dElem.render = function() {
+ if (x3dCanvas.hasRuntime) {
+ x3dCanvas.doc.needRender = true;
+ } else {
+ x3dCanvas.doc.render(x3dCanvas.gl);
+ }
+ };
+
+ this.x3dElem.context = x3dCanvas.gl.ctx3d;
+
+ this.doc.onerror = function () {
+ alert('Failed to load X3D document');
+ };
+
+ this.doc.load(uri, sceneElemPos);
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/**
+ * Class: x3dom.runtime
+ *
+ * Runtime proxy object to get and set runtime parameters. This object
+ * is attached to each X3D element and can be used in the following manner:
+ *
+ * > var e = document.getElementById('the_x3delement');
+ * > e.runtime.showAll();
+ * > e.runtime.resetView();
+ * > ...
+ */
+
+// Global runtime
+/**
+ * Namespace container for Runtime module
+ * @namespace x3dom.runtime
+ */
+x3dom.runtime = {};
+
+/** c'tor */
+x3dom.Runtime = function(doc, canvas) {
+ this.doc = doc;
+ this.canvas = canvas;
+
+ this.config = {};
+ this.isReady = false;
+
+ this.fps = 0;
+
+ this.states = { measurements: [], infos: [] };
+};
+
+
+x3dom.Runtime.prototype.addMeasurement = function (title, value) {
+ this.states.measurements[title] = value;
+};
+
+x3dom.Runtime.prototype.removeMeasurement = function (title) {
+ if (this.states.measurements[title]) {
+ delete this.states.measurements[title];
+ }
+};
+
+x3dom.Runtime.prototype.addInfo = function (title, value) {
+ this.states.infos[title] = value;
+};
+
+x3dom.Runtime.prototype.removeInfo = function (title) {
+ delete this.states.infos[title];
+};
+
+
+x3dom.Runtime.prototype.initialize = function(doc, canvas) {
+ this.doc = doc;
+ this.canvas = canvas;
+
+ // place to hold configuration data, i.e. flash backend path, etc.
+ // format and structure needs to be decided.
+ this.config = {};
+ this.isReady = false;
+
+ this.fps = 0;
+};
+
+
+/**
+ * APIFunction: noBackendFound
+ *
+ * This method is called once the system initialized and is not ready to
+ * render the first time because there is no backend found. By default this
+ * method noop. You can however override it with your own implementation.
+ *
+ * > x3dom.runtime.noBackendFound = function() {
+ * > alert("Dingel Dingel Ding Dong...");
+ * > }
+ *
+ * It is important to create this override before the document onLoad event has
+ * fired. Therefore putting it directly under the inclusion of x3dom.js is the
+ * preferred way to ensure overloading of this function.
+ */
+x3dom.Runtime.prototype.noBackendFound = function() {
+ x3dom.debug.logInfo('No backend found. Unable to render.');
+};
+
+/**
+ * APIFunction: ready
+ *
+ * This method is called once the system initialized and is ready to render
+ * the first time. It is therefore possible to execute custom
+ * action by overriding this method in your code:
+ *
+ * > x3dom.runtime.ready = function() {
+ * > alert("About to render something the first time");
+ * > }
+ *
+ * It is important to create this override before the document onLoad event has fired.
+ * Therefore putting it directly under the inclusion of x3dom.js is the preferred
+ * way to ensure overloading of this function.
+ *
+ * Parameters:
+ * element - The x3d element this handler is acting upon
+ */
+x3dom.Runtime.prototype.ready = function() {
+ x3dom.debug.logInfo('System ready.');
+};
+
+/**
+ * APIFunction: enterFrame
+ *
+ * This method is called just before the next frame is
+ * rendered. It is therefore possible to execute custom
+ * action by overriding this method in your code:
+ *
+ * > var element = document.getElementById('my_element');
+ * > element.runtime.enterFrame = function() {
+ * alert('hello custom enter frame');
+ * };
+ *
+ * If you have more than one X3D element in your HTML
+ * During initialization, just after ready() executed and before the very first frame
+ * is rendered, only the global override of this method works. If you need to execute
+ * code before the first frame renders, it is therefore best to use the ready()
+ * function instead.
+ *
+ * Parameters:
+ * element - The x3d element this handler is acting upon
+ */
+x3dom.Runtime.prototype.enterFrame = function() {
+ //x3dom.debug.logInfo('Render frame imminent');
+ // to be overwritten by user
+};
+
+/**
+ * APIFunction: exitFrame
+ *
+ * This method is called just after the current frame was
+ * rendered. It is therefore possible to execute custom
+ * action by overriding this method in your code:
+ *
+ * > var element = document.getElementById('my_element');
+ * > element.runtime.exitFrame = function() {
+ * alert('hello custom exit frame');
+ * };
+ *
+ * Parameters:
+ * element - The x3d element this handler is acting upon
+ */
+x3dom.Runtime.prototype.exitFrame = function() {
+ //x3dom.debug.logInfo('Render frame finished');
+ // to be overwritten by user
+};
+
+/**
+ * APIFunction: triggerRedraw
+ *
+ * triggers a redraw of the scene
+ *
+ */
+x3dom.Runtime.prototype.triggerRedraw = function() {
+ this.canvas.doc.needRender = true;
+};
+
+/**
+ * APIFunction: getActiveBindable
+ *
+ * Returns the currently active bindable DOM element of the given type.
+ * typeName must be a valid Bindable node (e.g. Viewpoint, Background, etc.).
+ *
+ * For example:
+ *
+ * > var element, bindable;
+ * > element = document.getElementById('the_x3delement');
+ * > bindable = element.runtime.getActiveBindable('background');
+ * > bindable.setAttribute('bind', 'false');
+ *
+ * Parameters:
+ * typeName - Bindable type name
+ *
+ * Returns:
+ * The active DOM element
+ */
+x3dom.Runtime.prototype.getActiveBindable = function(typeName) {
+ var stacks;
+ var i, current, result;
+ var type;
+
+ stacks = this.canvas.doc._bindableBag._stacks;
+ result = [];
+
+ type = x3dom.nodeTypesLC[typeName.toLowerCase()];
+
+ if (!type) {
+ x3dom.debug.logError('No node of type "' + typeName + '" found.');
+ return null;
+ }
+
+ for (i=0; i < stacks.length; i++) {
+ current = stacks[i].getActive();
+ if (current._xmlNode !== undefined && x3dom.isa(current, type) ) {
+ result.push(current);
+ }
+ }
+ return result[0] ? result[0]._xmlNode : null;
+};
+
+/**
+ * APIFunction: nextView
+ *
+ * Navigates tho the next viewpoint
+ *
+ */
+x3dom.Runtime.prototype.nextView = function() {
+ var stack = this.canvas.doc._scene.getViewpoint()._stack;
+ if (stack) {
+ stack.switchTo('next');
+ } else {
+ x3dom.debug.logError('No valid ViewBindable stack.');
+ }
+};
+
+/**
+ * APIFunction: prevView
+ *
+ * Navigates tho the previous viewpoint
+ *
+ */
+x3dom.Runtime.prototype.prevView = function() {
+ var stack = this.canvas.doc._scene.getViewpoint()._stack;
+ if (stack) {
+ stack.switchTo('prev');
+ } else {
+ x3dom.debug.logError('No valid ViewBindable stack.');
+ }
+};
+
+/**
+ * Function: viewpoint
+ *
+ * Returns the current viewpoint.
+ *
+ * Returns:
+ * The viewpoint
+ */
+x3dom.Runtime.prototype.viewpoint = function() {
+ return this.canvas.doc._scene.getViewpoint();
+};
+
+/**
+ * Function: viewMatrix
+ *
+ * Returns the current view matrix.
+ *
+ * Returns:
+ * Matrix object
+ */
+x3dom.Runtime.prototype.viewMatrix = function() {
+ return this.canvas.doc._viewarea.getViewMatrix();
+};
+
+/**
+ * Function: projectionMatrix
+ *
+ * Returns the current projection matrix.
+ *
+ * Returns:
+ * Matrix object
+ */
+x3dom.Runtime.prototype.projectionMatrix = function() {
+ return this.canvas.doc._viewarea.getProjectionMatrix();
+};
+
+/**
+ * Function: getWorldToCameraCoordinatesMatrix
+ *
+ * Returns the current world to camera coordinates matrix.
+ *
+ * Returns:
+ * Matrix object
+ */
+x3dom.Runtime.prototype.getWorldToCameraCoordinatesMatrix = function() {
+ return this.canvas.doc._viewarea.getWCtoCCMatrix();
+};
+
+/**
+ * Function: getCameraToWorldCoordinatesMatrix
+ *
+ * Returns the current camera to world coordinates matrix.
+ *
+ * Returns:
+ * Matrix object
+ */
+x3dom.Runtime.prototype.getCameraToWorldCoordinatesMatrix = function() {
+ return this.canvas.doc._viewarea.getCCtoWCMatrix();
+};
+
+/**
+ * Function: getViewingRay
+ *
+ * Returns the viewing ray for a given (x, y) position.
+ *
+ * Returns:
+ * Ray object
+ */
+x3dom.Runtime.prototype.getViewingRay = function(x, y) {
+ return this.canvas.doc._viewarea.calcViewRay(x, y);
+};
+
+/**
+ * Function: shootRay
+ *
+ * Returns pickPosition, pickNormal, and pickObject for a given (x, y) position.
+ *
+ * Returns:
+ * {pickPosition, pickNormal, pickObject}
+ */
+x3dom.Runtime.prototype.shootRay = function(x, y) {
+ var doc = this.canvas.doc;
+ var info = doc._viewarea._pickingInfo;
+
+ doc.onPick(this.canvas.gl, x, y);
+
+ return {
+ pickPosition: info.pickObj ? info.pickPos : null,
+ pickNormal: info.pickObj ? info.pickNorm : null,
+ pickObject: info.pickObj ? info.pickObj._xmlNode : null
+ };
+};
+
+/**
+ * Function: getWidth
+ *
+ * Returns the width of the canvas element.
+ */
+x3dom.Runtime.prototype.getWidth = function() {
+ return this.canvas.doc._viewarea._width;
+};
+
+/**
+ * Function: getHeight
+ *
+ * Returns the width of the canvas element.
+ */
+x3dom.Runtime.prototype.getHeight = function() {
+ return this.canvas.doc._viewarea._height;
+};
+
+/**
+ * Function: mousePosition
+ *
+ * Returns the 2d canvas layer position [x, y] for a given mouse event, i.e.,
+ * the mouse cursor's x and y positions relative to the canvas (x3d) element.
+ */
+x3dom.Runtime.prototype.mousePosition = function(event) {
+ var pos = this.canvas.mousePosition(event);
+
+ return [pos.x, pos.y];
+};
+
+/**
+ * Function: calcCanvasPos
+ *
+ * Returns the 2d screen position [cx, cy] for a given point [wx, wy, wz] in world coordinates.
+ */
+x3dom.Runtime.prototype.calcCanvasPos = function(wx, wy, wz) {
+ var pnt = new x3dom.fields.SFVec3f(wx, wy, wz);
+
+ var mat = this.canvas.doc._viewarea.getWCtoCCMatrix();
+ var pos = mat.multFullMatrixPnt(pnt);
+
+ var w = this.canvas.doc._viewarea._width;
+ var h = this.canvas.doc._viewarea._height;
+
+ var x = Math.round((pos.x + 1) * (w - 1) / 2);
+ var y = Math.round((h - 1) * (1 - pos.y) / 2);
+
+ return [x, y];
+};
+
+/**
+ * Function: calcPagePos
+ *
+ * Returns the 2d page (returns the mouse coordinates relative to the document) position [cx, cy]
+ * for a given point [wx, wy, wz] in world coordinates.
+ */
+x3dom.Runtime.prototype.calcPagePos = function(wx, wy, wz) {
+ var elem = this.canvas.canvas.offsetParent;
+
+ if (!elem) {
+ x3dom.debug.logError("Can't calc page pos without offsetParent.");
+ return [0, 0];
+ }
+
+ var canvasPos = elem.getBoundingClientRect();
+ var mousePos = this.calcCanvasPos(wx, wy, wz);
+
+ var scrollLeft = window.pageXOffset || document.body.scrollLeft;
+ var scrollTop = window.pageYOffset || document.body.scrollTop;
+
+ var compStyle = document.defaultView.getComputedStyle(elem, null);
+
+ var paddingLeft = parseFloat(compStyle.getPropertyValue('padding-left'));
+ var borderLeftWidth = parseFloat(compStyle.getPropertyValue('border-left-width'));
+
+ var paddingTop = parseFloat(compStyle.getPropertyValue('padding-top'));
+ var borderTopWidth = parseFloat(compStyle.getPropertyValue('border-top-width'));
+
+ var x = canvasPos.left + paddingLeft + borderLeftWidth + scrollLeft + mousePos[0];
+ var y = canvasPos.top + paddingTop + borderTopWidth + scrollTop + mousePos[1];
+
+ return [x, y];
+};
+
+/**
+ * Function: calcClientPos
+ *
+ * Returns the 2d client (returns the mouse coordinates relative to the window) position [cx, cy]
+ * for a given point [wx, wy, wz] in world coordinates.
+ */
+x3dom.Runtime.prototype.calcClientPos = function(wx, wy, wz) {
+ var elem = this.canvas.canvas.offsetParent;
+
+ if (!elem) {
+ x3dom.debug.logError("Can't calc client pos without offsetParent.");
+ return [0, 0];
+ }
+
+ var canvasPos = elem.getBoundingClientRect();
+ var mousePos = this.calcCanvasPos(wx, wy, wz);
+
+ var compStyle = document.defaultView.getComputedStyle(elem, null);
+
+ var paddingLeft = parseFloat(compStyle.getPropertyValue('padding-left'));
+ var borderLeftWidth = parseFloat(compStyle.getPropertyValue('border-left-width'));
+
+ var paddingTop = parseFloat(compStyle.getPropertyValue('padding-top'));
+ var borderTopWidth = parseFloat(compStyle.getPropertyValue('border-top-width'));
+
+ var x = canvasPos.left + paddingLeft + borderLeftWidth + mousePos[0];
+ var y = canvasPos.top + paddingTop + borderTopWidth + mousePos[1];
+
+ return [x, y];
+};
+
+/**
+ * Function: getScreenshot
+ *
+ * Returns a Base64 encoded png image consisting of the current rendering.
+ *
+ * Returns:
+ * The Base64 encoded PNG image string
+ */
+x3dom.Runtime.prototype.getScreenshot = function() {
+ var url = "";
+ var backend = this.canvas.backend;
+ var canvas = this.canvas.canvas;
+
+ if(canvas) {
+ if(backend == "flash") {
+ url = canvas.getScreenshot();
+ }
+ else {
+ // first flip along y axis
+ var canvas2d = document.createElement("canvas");
+ canvas2d.width = canvas.width;
+ canvas2d.height = canvas.height;
+
+ var ctx = canvas2d.getContext("2d");
+ ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
+ ctx.scale(1, -1);
+ ctx.translate(0, -canvas.height);
+
+ url = canvas2d.toDataURL();
+ }
+ }
+
+ return url;
+};
+
+/**
+ * Function: getCanvas
+ *
+ * Returns the internal canvas element (only valid for WebGL backend)
+ *
+ * Returns:
+ * The internal canvas element
+ */
+x3dom.Runtime.prototype.getCanvas = function() {
+ return this.canvas.canvas;
+};
+
+/**
+ * Function: lightMatrix
+ *
+ * Returns the current light matrix.
+ *
+ * Returns:
+ * The light matrix
+ */
+x3dom.Runtime.prototype.lightMatrix = function() {
+ this.canvas.doc._viewarea.getLightMatrix();
+};
+
+/**
+ * APIFunction: resetView
+ *
+ * Resets the view to initial.
+ *
+ */
+x3dom.Runtime.prototype.resetView = function() {
+ this.canvas.doc._viewarea.resetView();
+};
+
+/**
+ * Function: lightView
+ *
+ * Navigates to the first light, if any.
+ *
+ * Returns:
+ * True if navigation was possible, false otherwise.
+ */
+x3dom.Runtime.prototype.lightView = function() {
+ if (this.canvas.doc._nodeBag.lights.length > 0) {
+ this.canvas.doc._viewarea.animateTo(this.canvas.doc._viewarea.getLightMatrix()[0],
+ this.canvas.doc._scene.getViewpoint());
+ return true;
+ } else {
+ x3dom.debug.logInfo("No lights to navigate to.");
+ return false;
+ }
+};
+
+/**
+ * APIFunction: uprightView
+ *
+ * Navigates to upright view
+ *
+ */
+x3dom.Runtime.prototype.uprightView = function() {
+ this.canvas.doc._viewarea.uprightView();
+};
+
+/**
+ * APIFunction: fitAll
+ *
+ * Zooms so that all objects are fully visible. Without change the actual Viewpoint orientation
+ *
+ * Parameter:
+ * updateCenterOfRotation - a boolean value that specifies if the new center of rotation is set
+ *
+ */
+x3dom.Runtime.prototype.fitAll = function(updateCenterOfRotation)
+{
+ if (updateCenterOfRotation === undefined) {
+ updateCenterOfRotation = true;
+ }
+
+ var scene = this.canvas.doc._scene;
+ scene.updateVolume();
+
+ this.canvas.doc._viewarea.fit(scene._lastMin, scene._lastMax, updateCenterOfRotation);
+};
+
+/**
+ * APIFunction: fitObject
+ *
+ * Zooms so that a given object are fully visible. Without change the actual Viewpoint orientation
+ *
+ * Parameter:
+ * updateCenterOfRotation - a boolean value that specifies if the new center of rotation is set
+ *
+ */
+x3dom.Runtime.prototype.fitObject = function(obj, updateCenterOfRotation)
+{
+ if (obj && obj._x3domNode)
+ {
+ if (updateCenterOfRotation === undefined) {
+ updateCenterOfRotation = true;
+ }
+
+ var min = x3dom.fields.SFVec3f.MAX();
+ var max = x3dom.fields.SFVec3f.MIN();
+
+ var vol = obj._x3domNode.getVolume();
+ vol.getBounds(min, max);
+
+ var mat = obj._x3domNode.getCurrentTransform();
+
+ min = mat.multMatrixPnt(min);
+ max = mat.multMatrixPnt(max);
+
+ //TODO: revise separation of "getVolume" and "getCurrentTransform"
+ // for the transform nodes - currently, both "overlap" because
+ // both include the transform's own matrix
+ // but which is what you usually expect from both methods...
+ if (x3dom.isa(obj._x3domNode, x3dom.nodeTypes.X3DTransformNode))
+ {
+ var invMat = obj._x3domNode._trafo.inverse();
+ min = invMat.multMatrixPnt(min);
+ max = invMat.multMatrixPnt(max);
+ }
+
+ this.canvas.doc._viewarea.fit(min, max, updateCenterOfRotation);
+ }
+};
+
+/**
+ * APIFunction: showAll
+ *
+ * Zooms so that all objects are fully visible.
+ *
+ * Parameter:
+ * axis - the axis as string: posX, negX, posY, negY, posZ, negZ
+ *
+ */
+x3dom.Runtime.prototype.showAll = function(axis) {
+ this.canvas.doc._viewarea.showAll(axis);
+};
+
+/**
+ * APIFunction: showObject
+ *
+ * Zooms so that a given object is fully visible in the middle of the screen.
+ *
+ * Parameter:
+ * obj - the scene-graph element on which to focus
+ */
+x3dom.Runtime.prototype.showObject = function(obj)
+{
+ if (obj && obj._x3domNode)
+ {
+ var min = x3dom.fields.SFVec3f.MAX();
+ var max = x3dom.fields.SFVec3f.MIN();
+
+ var vol = obj._x3domNode.getVolume();
+ vol.getBounds(min, max);
+
+ var mat = obj._x3domNode.getCurrentTransform();
+
+ min = mat.multMatrixPnt(min);
+ max = mat.multMatrixPnt(max);
+
+ var viewarea = this.canvas.doc._viewarea;
+
+ // assume FOV_smaller as camera's fovMode
+ var focalLen = (viewarea._width < viewarea._height) ?
+ viewarea._width : viewarea._height;
+
+ var n0 = new x3dom.fields.SFVec3f(0, 0, 1); // facingDir
+ var viewpoint = this.canvas.doc._scene.getViewpoint();
+ var fov = viewpoint.getFieldOfView() / 2.0;
+ var ta = Math.tan(fov);
+
+ if (Math.abs(ta) > x3dom.fields.Eps) {
+ focalLen /= ta;
+ }
+
+ var w = viewarea._width - 1;
+ var h = viewarea._height - 1;
+
+ var frame = 0.25;
+ var minScreenPos = new x3dom.fields.SFVec2f(frame * w, frame * h);
+
+ frame = 0.75;
+ var maxScreenPos = new x3dom.fields.SFVec2f(frame * w, frame * h);
+
+ var dia2 = max.subtract(min).multiply(0.5); // half diameter
+ var rw = dia2.length(); // approx radius
+
+ var pc = min.add(dia2); // center in wc
+ var vc = maxScreenPos.subtract(minScreenPos).multiply(0.5);
+
+ var rs = 1.5 * vc.length();
+ vc = vc.add(minScreenPos);
+
+ var dist = 1.0;
+ if (rs > x3dom.fields.Eps) {
+ dist = (rw / rs) * Math.sqrt(vc.x*vc.x + vc.y*vc.y + focalLen*focalLen);
+ }
+
+ n0 = mat.multMatrixVec(n0).normalize();
+ n0 = n0.multiply(dist);
+ var p0 = pc.add(n0);
+
+ var qDir = x3dom.fields.Quaternion.rotateFromTo(new x3dom.fields.SFVec3f(0, 0, 1), n0);
+ var R = qDir.toMatrix();
+
+ var T = x3dom.fields.SFMatrix4f.translation(p0.negate());
+ var M = x3dom.fields.SFMatrix4f.translation(p0);
+
+ M = M.mult(R).mult(T).mult(M);
+ var viewmat = M.inverse();
+
+ viewarea.animateTo(viewmat, viewpoint);
+ }
+};
+
+/**
+ * APIMethod getCenter
+ *
+ * Returns the center of a X3DShapeNode or X3DGeometryNode.
+ *
+ * Parameters:
+ * domNode: the node for which its center shall be returned
+ *
+ * Returns:
+ * Node center (or null if no Shape or Geometry)
+ */
+x3dom.Runtime.prototype.getCenter = function(domNode) {
+ if (domNode && domNode._x3domNode &&
+ (this.isA(domNode, "X3DShapeNode") || this.isA(domNode, "X3DGeometryNode")))
+ {
+ return domNode._x3domNode.getCenter();
+ }
+
+ return null;
+};
+
+/**
+ * APIMethod getCurrentTransform
+ *
+ * Returns the current to world transformation of a node.
+ *
+ * Parameters:
+ * domNode: the node for which its transformation shall be returned
+ *
+ * Returns:
+ * Transformation matrix (or null no valid node is given)
+ */
+x3dom.Runtime.prototype.getCurrentTransform = function(domNode) {
+ if (domNode && domNode._x3domNode)
+ {
+ return domNode._x3domNode.getCurrentTransform();
+ }
+
+ return null;
+};
+
+/**
+ * APIMethod getBBox
+ *
+ * Returns the bounding box of a node.
+ *
+ * Parameters:
+ * domNode: the node for which its volume shall be returned
+ *
+ * Returns:
+ * The min and max positions of the node's bounding box.
+ */
+x3dom.Runtime.prototype.getBBox = function(domNode) {
+ if (domNode && domNode._x3domNode && this.isA(domNode, "X3DBoundedObject"))
+ {
+ var vol = domNode._x3domNode.getVolume();
+
+ return {
+ min: x3dom.fields.SFVec3f.copy(vol.min),
+ max: x3dom.fields.SFVec3f.copy(vol.max)
+ }
+ }
+
+ return null;
+};
+
+/**
+ * APIMethod getSceneBBox
+ *
+ * Returns the bounding box of the scene.
+ *
+ * Returns:
+ * The min and max positions of the scene's bounding box.
+ */
+x3dom.Runtime.prototype.getSceneBBox = function() {
+ var scene = this.canvas.doc._scene;
+ scene.updateVolume();
+
+ return {
+ min: x3dom.fields.SFVec3f.copy(scene._lastMin),
+ max: x3dom.fields.SFVec3f.copy(scene._lastMax)
+ }
+};
+
+/**
+ * APIFunction: debug
+ *
+ * Displays or hides the debug window. If parameter is omitted,
+ * the current visibility status is returned.
+ *
+ * Parameter:
+ * show - true to show debug window, false to hide
+ *
+ * Returns:
+ * Current visibility status of debug window (true=visible, false=hidden)
+ */
+x3dom.Runtime.prototype.debug = function(show) {
+ var doc = this.canvas.doc;
+ if (doc._viewarea._visDbgBuf === undefined)
+ doc._viewarea._visDbgBuf = (doc._x3dElem.getAttribute("showLog") === 'true');
+
+ if (arguments.length > 0) {
+ if (show === true) {
+ doc._viewarea._visDbgBuf = true;
+ x3dom.debug.logContainer.style.display = "block";
+ }
+ else {
+ doc._viewarea._visDbgBuf = false;
+ x3dom.debug.logContainer.style.display = "none";
+ }
+ }
+ else {
+ doc._viewarea._visDbgBuf = !doc._viewarea._visDbgBuf;
+ x3dom.debug.logContainer.style.display = (doc._viewarea._visDbgBuf == true) ? "block" : "none";
+ }
+ doc.needRender = true;
+
+ return doc._viewarea._visDbgBuf;
+};
+
+/**
+ * APIFunction: navigationType
+ *
+ * Readout of the currently active navigation.
+ *
+ * Returns:
+ * A string representing the active navigation type
+ */
+x3dom.Runtime.prototype.navigationType = function() {
+ return this.canvas.doc._scene.getNavigationInfo().getType();
+};
+
+/**
+ * APIFunction: noNav
+ *
+ * Switches to noNav mode
+ */
+x3dom.Runtime.prototype.noNav = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("none");
+};
+
+/**
+ * APIFunction: examine
+ *
+ * Switches to examine mode
+ */
+x3dom.Runtime.prototype.examine = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("examine");
+};
+
+/**
+ * APIFunction: turnTable
+ *
+ * Switches to turnTable mode
+ */
+x3dom.Runtime.prototype.turnTable = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("turntable");
+};
+
+/**
+ * APIFunction: fly
+ *
+ * Switches to fly mode
+ */
+x3dom.Runtime.prototype.fly = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("fly");
+};
+
+/**
+ * APIFunction: freeFly
+ *
+ * Switches to freeFly mode
+ */
+x3dom.Runtime.prototype.freeFly = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("freefly");
+};
+
+/**
+ * APIFunction: lookAt
+ *
+ * Switches to lookAt mode
+ */
+x3dom.Runtime.prototype.lookAt = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("lookat");
+};
+/**
+ * APIFunction: lookAround
+ *
+ * Switches to lookAround mode
+ */
+x3dom.Runtime.prototype.lookAround = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("lookaround");
+};
+
+/**
+ * APIFunction: walk
+ *
+ * Switches to walk mode
+ */
+x3dom.Runtime.prototype.walk = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("walk");
+};
+
+/**
+ * APIFunction: game
+ *
+ * Switches to game mode
+ */
+x3dom.Runtime.prototype.game = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("game");
+};
+
+/**
+ * APIFunction: helicopter
+ *
+ * Switches to helicopter mode
+ */
+x3dom.Runtime.prototype.helicopter = function() {
+ this.canvas.doc._scene.getNavigationInfo().setType("helicopter");
+};
+
+/**
+ * Function: resetExamin
+ *
+ * Resets all variables required by examine mode to init state
+ */
+ x3dom.Runtime.prototype.resetExamin = function() {
+ var viewarea = this.canvas.doc._viewarea;
+ viewarea._rotMat = x3dom.fields.SFMatrix4f.identity();
+ viewarea._transMat = x3dom.fields.SFMatrix4f.identity();
+ viewarea._movement = new x3dom.fields.SFVec3f(0, 0, 0);
+ viewarea._needNavigationMatrixUpdate = true;
+ this.canvas.doc.needRender = true;
+ };
+
+/**
+ * Function: togglePoints
+ *
+ * Toggles points attribute
+ */
+x3dom.Runtime.prototype.togglePoints = function(lines) {
+ var doc = this.canvas.doc;
+ var mod = (lines === true) ? 3 : 2;
+
+ doc._viewarea._points = ++doc._viewarea._points % mod;
+ doc.needRender = true;
+
+ return doc._viewarea._points;
+};
+
+/**
+ * Function: pickRect
+ *
+ * Returns an array of all shape elements that are within the picked rectangle
+ * defined by (x1, y1) and (x2, y2) in canvas coordinates
+ */
+x3dom.Runtime.prototype.pickRect = function(x1, y1, x2, y2) {
+ return this.canvas.doc.onPickRect(this.canvas.gl, x1, y1, x2, y2);
+};
+
+/**
+ * Function: pickMode
+ *
+ * Get the current pickMode intersect type
+ *
+ * Parameters:
+ * internal - true/false. If given return the internal representation.
+ * Only use for debugging.
+ *
+ * Returns:
+ * The current intersect type value suitable to use with changePickMode
+ * If parameter is, given, provide with internal representation.
+ */
+x3dom.Runtime.prototype.pickMode = function(options) {
+ if (options && options.internal === true) {
+ return this.canvas.doc._scene._vf.pickMode;
+ }
+ return this.canvas.doc._scene._vf.pickMode.toLowerCase();
+};
+
+/**
+ * Function: changePickMode
+ *
+ * Alter the value of intersect type. Can be one of: box, idBuf, idBuf24, idBufId, color, texCoord.
+ * Other values are ignored.
+ *
+ * Parameters:
+ * type - The new intersect type: box, idBuf, idBuf24, idBufId, color, texCoord
+ *
+ * Returns:
+ * true if the type has been changed, false otherwise
+ */
+x3dom.Runtime.prototype.changePickMode = function(type) {
+ // pick type one of : box, idBuf, idBuf24, idBufId, color, texCoord
+ type = type.toLowerCase();
+
+ switch(type) {
+ case 'idbuf': type = 'idBuf'; break;
+ case 'idbuf24': type = 'idBuf24'; break;
+ case 'idbufid': type = 'idBufId'; break;
+ case 'texcoord': type = 'texCoord'; break;
+ case 'color': type = 'color'; break;
+ case 'box': type = 'box'; break;
+ default:
+ x3dom.debug.logWarning("Switch pickMode to "+ type + ' unknown intersect type');
+ type = undefined;
+ }
+
+ if (type !== undefined) {
+ this.canvas.doc._scene._vf.pickMode = type;
+ x3dom.debug.logInfo("Switched pickMode to '" + type + "'.");
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ * APIFunction: speed
+ *
+ * Get the current speed value. If parameter is given the new speed value is set.
+ *
+ * Parameters:
+ * newSpeed - The new speed value (optional)
+ *
+ * Returns:
+ * The current speed value
+ */
+x3dom.Runtime.prototype.speed = function(newSpeed) {
+ var navi = this.canvas.doc._scene.getNavigationInfo();
+ if (newSpeed) {
+ navi._vf.speed = newSpeed;
+ x3dom.debug.logInfo("Changed navigation speed to " + navi._vf.speed);
+ }
+ return navi._vf.speed;
+};
+
+/**
+ * APIFunction: statistics
+ *
+ * Get or set statistics info. If parameter is omitted, this method
+ * only returns the the visibility status of the statistics info overlay.
+ *
+ * Parameters:
+ * mode - true or false. To enable or disable the statistics info
+ *
+ * Returns:
+ * The current visibility of the statistics info (true = visible, false = invisible)
+ */
+x3dom.Runtime.prototype.statistics = function(mode) {
+ var states = this.canvas.stateViewer;
+ if (states) {
+ this.canvas.doc.needRender = true;
+ if (mode === true) {
+ states.display(mode);
+ return true;
+ }
+ else if (mode === false) {
+ states.display(mode);
+ return false;
+ }
+ else {
+ states.display(!states.active);
+ // if no parameter is given return current status (false = not visible, true = visible)
+ return states.active;
+ }
+ }
+ return false;
+};
+
+/**
+ * Function: processIndicator
+ *
+ * Enable or disable the process indicator. If parameter is omitted, this method
+ * only returns the the visibility status of the progress bar overlay.
+ *
+ * Parameters:
+ * mode - true or false. To enable or disable the progress indicator
+ *
+ * Returns:
+ * The current visibility of the progress indicator info (true = visible, false = invisible)
+ */
+x3dom.Runtime.prototype.processIndicator = function(mode) {
+ var processDiv = this.canvas.progressDiv;
+ if (processDiv) {
+ if (mode === true) {
+ processDiv.style.display = 'inline';
+ return true;
+ }
+ else if (mode === false) {
+ processDiv.style.display = 'none';
+ return false;
+ }
+
+ // if no parameter is given return current status (false = not visible, true = visible)
+ return processDiv.style.display != 'none'
+ }
+ return false;
+};
+
+/** Get properties */
+x3dom.Runtime.prototype.properties = function() {
+ return this.canvas.doc.properties;
+};
+
+/** Get current backend name */
+x3dom.Runtime.prototype.backendName = function() {
+ return this.canvas.backend;
+};
+
+/** Get current framerate */
+x3dom.Runtime.prototype.getFPS = function() {
+ return this.fps;
+};
+
+
+/**
+ * APIMethod isA
+ *
+ * Test a DOM node object against a node type string. This method
+ * can be used to determine the "type" of a DOM node.
+ *
+ * Parameters:
+ * domNode: the node to test for
+ * nodeType: node name to test domNode against
+ *
+ * Returns:
+ * True or false
+ */
+x3dom.Runtime.prototype.isA = function(domNode, nodeType) {
+ var inherits = false;
+
+ if (nodeType && domNode && domNode._x3domNode) {
+ if (nodeType === "") {
+ nodeType = "X3DNode";
+ }
+ inherits = x3dom.isa(domNode._x3domNode,
+ x3dom.nodeTypesLC[nodeType.toLowerCase()]);
+ }
+
+ return inherits;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+x3dom.detectActiveX = function() {
+ var isInstalled = false;
+
+ if (window.ActiveXObject) {
+ var control = null;
+
+ try {
+ control = new ActiveXObject('AVALONATX.InstantPluginATXCtrl.1');
+ } catch (e) {
+ }
+
+ if (control) {
+ isInstalled = true;
+ }
+ }
+
+ return isInstalled;
+};
+
+x3dom.rerouteSetAttribute = function(node, browser) {
+ // save old setAttribute method
+ node._setAttribute = node.setAttribute;
+ node.setAttribute = function(name, value) {
+ var id = node.getAttribute("_x3domNode");
+ var anode = browser.findNode(id);
+
+ if (anode)
+ return anode.parseField(name, value);
+ else
+ return 0;
+ };
+
+ for(var i=0; i < node.childNodes.length; i++) {
+ var child = node.childNodes[i];
+ x3dom.rerouteSetAttribute(child, browser);
+ }
+};
+
+x3dom.insertActiveX = function(x3d) {
+
+ if (typeof x3dom.atxCtrlCounter == 'undefined') {
+ x3dom.atxCtrlCounter = 0;
+ }
+
+ var height = x3d.getAttribute("height");
+ var width = x3d.getAttribute("width");
+
+ var parent = x3d.parentNode;
+
+ var divelem = document.createElement("div");
+ divelem.setAttribute("id", "x3dplaceholder");
+
+ var inserted = parent.insertBefore(divelem, x3d);
+
+ // hide x3d div
+ var hiddenx3d = document.createElement("div");
+ hiddenx3d.style.display = "none";
+ parent.appendChild(hiddenx3d);
+ parent.removeChild(x3d);
+ hiddenx3d.appendChild(x3d);
+
+ var atx = document.createElement("object");
+
+ var containerName = "Avalon" + x3dom.atxCtrlCounter;
+ x3dom.atxCtrlCounter++;
+
+ atx.setAttribute("id", containerName);
+ atx.setAttribute("classid", "CLSID:F3254BA0-99FF-4D14-BD81-EDA9873A471E");
+ atx.setAttribute("width", width ? width : "500");
+ atx.setAttribute("height", height ? height : "500");
+
+ inserted.appendChild(atx);
+
+ var atxctrl = document.getElementById(containerName);
+ var browser = atxctrl.getBrowser();
+ var scene = browser.importDocument(x3d);
+ browser.replaceWorld(scene);
+
+ // add backtrack method to get browser from x3d node instead of the ctrl
+ x3d.getBrowser = function() {
+ return atxctrl.getBrowser();
+ };
+
+ x3dom.rerouteSetAttribute(x3d, browser);
+};
+
+// holds the UserAgent feature
+x3dom.userAgentFeature = {
+ supportsDOMAttrModified: false
+};
+
+
+(function loadX3DOM() {
+ "use strict";
+
+ var onload = function() {
+ var i,j; // counters
+
+ // Search all X3D elements in the page
+ var x3ds_unfiltered = document.getElementsByTagName('X3D');
+ var x3ds = [];
+
+ // check if element already has been processed
+ for (i=0; i < x3ds_unfiltered.length; i++) {
+ if (x3ds_unfiltered[i].hasRuntime === undefined)
+ x3ds.push(x3ds_unfiltered[i]);
+ }
+
+ // ~~ Components and params {{{ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ var params;
+ var settings = new x3dom.Properties(); // stores the stuff in <param>
+ var validParams = array_to_object([
+ 'showLog',
+ 'showStat',
+ 'showProgress',
+ 'PrimitiveQuality',
+ 'components',
+ 'loadpath',
+ 'disableDoubleClick',
+ 'backend',
+ 'altImg',
+ 'flashrenderer',
+ 'swfpath',
+ 'runtimeEnabled',
+ 'keysEnabled',
+ 'showTouchpoints',
+ 'disableTouch',
+ 'maxActiveDownloads'
+ ]);
+ var components, prefix;
+ var showLoggingConsole = false;
+
+ // for each X3D element
+ for (i=0; i < x3ds.length; i++) {
+
+ // default parameters
+ settings.setProperty("showLog", x3ds[i].getAttribute("showLog") || 'false');
+ settings.setProperty("showStat", x3ds[i].getAttribute("showStat") || 'false');
+ settings.setProperty("showProgress", x3ds[i].getAttribute("showProgress") || 'true');
+ settings.setProperty("PrimitiveQuality", x3ds[i].getAttribute("PrimitiveQuality") || 'High');
+
+ // for each param element inside the X3D element
+ // add settings to properties object
+ params = x3ds[i].getElementsByTagName('PARAM');
+ for (j=0; j < params.length; j++) {
+ if (params[j].getAttribute('name') in validParams) {
+ settings.setProperty(params[j].getAttribute('name'), params[j].getAttribute('value'));
+ } else {
+ //x3dom.debug.logError("Unknown parameter: " + params[j].getAttribute('name'));
+ }
+ }
+
+ // enable log
+ if (settings.getProperty('showLog') === 'true') {
+ showLoggingConsole = true;
+ }
+
+ if (typeof X3DOM_SECURITY_OFF != 'undefined' && X3DOM_SECURITY_OFF === true) {
+ // load components from params or default to x3d attribute
+ components = settings.getProperty('components', x3ds[i].getAttribute("components"));
+ if (components) {
+ prefix = settings.getProperty('loadpath', x3ds[i].getAttribute("loadpath"));
+ components = components.trim().split(',');
+ for (j=0; j < components.length; j++) {
+ x3dom.loadJS(components[j] + ".js", prefix);
+ }
+ }
+
+ // src=foo.x3d adding inline node, not a good idea, but...
+ if (x3ds[i].getAttribute("src")) {
+ var _scene = document.createElement("scene");
+ var _inl = document.createElement("Inline");
+ _inl.setAttribute("url", x3ds[i].getAttribute("src"));
+ _scene.appendChild(_inl);
+ x3ds[i].appendChild(_scene);
+ }
+ }
+ }
+ // }}}
+
+ if (showLoggingConsole == true) {
+ x3dom.debug.activate(true);
+ } else {
+ x3dom.debug.activate(false);
+ }
+
+ // Convert the collection into a simple array (is this necessary?)
+ x3ds = Array.map(x3ds, function (n) {
+ n.hasRuntime = true;
+ return n;
+ });
+
+ var w3sg = document.getElementsByTagName('webSG'); // THINKABOUTME: shall we still support exp. WebSG?!
+
+ for (i=0; i<w3sg.length; i++) {
+ w3sg[i].hasRuntime = false;
+ x3ds.push(w3sg[i]);
+ }
+
+ if (x3dom.versionInfo !== undefined) {
+ x3dom.debug.logInfo("X3DOM version " + x3dom.versionInfo.version + ", " +
+ "Revison <a href='https://github.com/x3dom/x3dom/tree/"+ x3dom.versionInfo.revision +"'>"
+ + x3dom.versionInfo.revision + "</a>, " +
+ "Date " + x3dom.versionInfo.date);
+ }
+
+ x3dom.debug.logInfo("Found " + (x3ds.length - w3sg.length) + " X3D and " +
+ w3sg.length + " (experimental) WebSG nodes...");
+
+ // Create a HTML canvas for every X3D scene and wrap it with
+ // an X3D canvas and load the content
+ var x3d_element;
+ var x3dcanvas;
+ var altDiv, altP, aLnk, altImg;
+ var t0, t1;
+
+ for (i=0; i < x3ds.length; i++)
+ {
+ x3d_element = x3ds[i];
+
+ // http://www.howtocreate.co.uk/wrongWithIE/?chapter=navigator.plugins
+ if (x3dom.detectActiveX()) {
+ x3dom.insertActiveX(x3d_element);
+ continue;
+ }
+
+ x3dcanvas = new x3dom.X3DCanvas(x3d_element, x3dom.canvases.length);
+
+ x3dom.canvases.push(x3dcanvas);
+
+ if (x3dcanvas.gl === null) {
+
+ altDiv = document.createElement("div");
+ altDiv.setAttribute("class", "x3dom-nox3d");
+ altDiv.setAttribute("id", "x3dom-nox3d");
+
+ altP = document.createElement("p");
+ altP.appendChild(document.createTextNode("WebGL is not yet supported in your browser. "));
+ aLnk = document.createElement("a");
+ aLnk.setAttribute("href","http://www.x3dom.org/?page_id=9");
+ aLnk.appendChild(document.createTextNode("Follow link for a list of supported browsers... "));
+
+ altDiv.appendChild(altP);
+ altDiv.appendChild(aLnk);
+
+ x3dcanvas.x3dElem.appendChild(altDiv);
+
+ // remove the stats div (it's not added when WebGL doesn't work)
+ if (x3dcanvas.stateViewer) {
+ x3d_element.removeChild(x3dcanvas.stateViewer.viewer);
+ }
+
+ continue;
+ }
+
+ t0 = new Date().getTime();
+
+ x3ds[i].runtime = new x3dom.Runtime(x3ds[i], x3dcanvas);
+ x3ds[i].runtime.initialize(x3ds[i], x3dcanvas);
+
+ if (x3dom.runtime.ready) {
+ x3ds[i].runtime.ready = x3dom.runtime.ready;
+ }
+
+ // no backend found method system wide call
+ if (x3dcanvas.backend == '') {
+ x3dom.runtime.noBackendFound();
+ }
+
+ x3dcanvas.load(x3ds[i], i, settings);
+
+ // show or hide statistics based on param/x3d attribute settings
+ if (settings.getProperty('showStat') === 'true') {
+ x3ds[i].runtime.statistics(true);
+ } else {
+ x3ds[i].runtime.statistics(false);
+ }
+
+ if (settings.getProperty('showProgress') === 'true') {
+ if (settings.getProperty('showProgress') === 'bar'){
+ x3dcanvas.progressDiv.setAttribute("class", "x3dom-progress bar");
+ }
+ x3ds[i].runtime.processIndicator(true);
+ } else {
+ x3ds[i].runtime.processIndicator(false);
+ }
+
+ t1 = new Date().getTime() - t0;
+ x3dom.debug.logInfo("Time for setup and init of GL element no. " + i + ": " + t1 + " ms.");
+ }
+
+ var ready = (function(eventType) {
+ var evt = null;
+
+ if (document.createEvent) {
+ evt = document.createEvent("Events");
+ evt.initEvent(eventType, true, true);
+ document.dispatchEvent(evt);
+ } else if (document.createEventObject) {
+ evt = document.createEventObject();
+ // http://stackoverflow.com/questions/1874866/how-to-fire-onload-event-on-document-in-ie
+ document.body.fireEvent('on' + eventType, evt);
+ }
+ })('load');
+ };
+
+ var onunload = function() {
+ if (x3dom.canvases) {
+ for (var i=0; i<x3dom.canvases.length; i++) {
+ x3dom.canvases[i].doc.shutdown(x3dom.canvases[i].gl);
+ }
+ x3dom.canvases = [];
+ }
+ };
+
+ /** Initializes an <x3d> root element that was added after document load. */
+ x3dom.reload = function() {
+ onload();
+ };
+
+ /* FIX PROBLEM IN CHROME - HACK - searching for better solution !!! */
+ if (navigator.userAgent.indexOf("Chrome") != -1) {
+ document.__getElementsByTagName = document.getElementsByTagName;
+
+ document.getElementsByTagName = function(tag) {
+ var obj = [];
+ var elems = this.__getElementsByTagName("*");
+
+ if(tag =="*"){
+ obj = elems;
+ } else {
+ tag = tag.toUpperCase();
+ for (var i = 0; i < elems.length; i++) {
+ var tagName = elems[i].tagName.toUpperCase();
+ if (tagName === tag) {
+ obj.push(elems[i]);
+ }
+ }
+ }
+
+ return obj;
+ };
+
+ document.__getElementById = document.getElementById;
+ document.getElementById = function(id) {
+ var obj = this.__getElementById(id);
+
+ if (!obj) {
+ var elems = this.__getElementsByTagName("*");
+ for (var i=0; i<elems.length && !obj; i++) {
+ if (elems[i].getAttribute("id") === id) {
+ obj = elems[i];
+ }
+ }
+ }
+ return obj;
+ };
+
+ } else { /* END OF HACK */
+ document.__getElementById = document.getElementById;
+ document.getElementById = function(id) {
+ var obj = this.__getElementById(id);
+
+ if (!obj) {
+ var elems = this.getElementsByTagName("*");
+ for (var i=0; i<elems.length && !obj; i++) {
+ if (elems[i].getAttribute("id") === id) {
+ obj = elems[i];
+ }
+ }
+ }
+ return obj;
+ };
+ }
+
+ if (window.addEventListener) {
+ window.addEventListener('load', onload, false);
+ window.addEventListener('unload', onunload, false);
+ window.addEventListener('reload', onunload, false);
+ } else if (window.attachEvent) {
+ window.attachEvent('onload', onload);
+ window.attachEvent('onunload', onunload);
+ window.attachEvent('onreload', onunload);
+ }
+
+ // Initialize if we were loaded after 'DOMContentLoaded' already fired.
+ // This can happen if the script was loaded by other means.
+ if (document.readyState === "complete") {
+ window.setTimeout( function() { onload(); }, 20 );
+ }
+})();
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+x3dom.Cache = function () {
+ this.textures = [];
+ this.shaders = [];
+};
+
+/**
+ * Returns a Texture 2D
+ */
+x3dom.Cache.prototype.getTexture2D = function (gl, doc, url, bgnd, crossOrigin, scale, genMipMaps) {
+ var textureIdentifier = url;
+
+ if (this.textures[textureIdentifier] === undefined) {
+ this.textures[textureIdentifier] = x3dom.Utils.createTexture2D(
+ gl, doc, url, bgnd, crossOrigin, scale, genMipMaps);
+ }
+
+ return this.textures[textureIdentifier];
+};
+
+/**
+ * Returns a Texture 2D
+ */
+x3dom.Cache.prototype.getTexture2DByDEF = function (gl, nameSpace, def) {
+ var textureIdentifier = nameSpace.name + "_" + def;
+
+ if (this.textures[textureIdentifier] === undefined) {
+ this.textures[textureIdentifier] = gl.createTexture();
+ }
+
+ return this.textures[textureIdentifier];
+};
+
+/**
+ * Returns a Cube Texture
+ */
+x3dom.Cache.prototype.getTextureCube = function (gl, doc, url, bgnd, crossOrigin, scale, genMipMaps) {
+ var textureIdentifier = "";
+
+ for (var i = 0; i < url.length; ++i) {
+ textureIdentifier += url[i] + "|";
+ }
+
+ if (this.textures[textureIdentifier] === undefined) {
+ this.textures[textureIdentifier] = x3dom.Utils.createTextureCube(
+ gl, doc, url, bgnd, crossOrigin, scale, genMipMaps);
+ }
+
+ return this.textures[textureIdentifier];
+};
+
+/**
+ * Returns one of the default shader programs
+ */
+x3dom.Cache.prototype.getShader = function (gl, shaderIdentifier) {
+ var program = null;
+
+ //Check if shader is in cache
+ if (this.shaders[shaderIdentifier] === undefined) {
+ //Choose shader based on identifier
+ switch (shaderIdentifier) {
+ case x3dom.shader.PICKING:
+ program = new x3dom.shader.PickingShader(gl);
+ break;
+ case x3dom.shader.PICKING_24:
+ program = new x3dom.shader.Picking24Shader(gl);
+ break;
+ case x3dom.shader.PICKING_ID:
+ program = new x3dom.shader.PickingIdShader(gl);
+ break;
+ case x3dom.shader.PICKING_COLOR:
+ program = new x3dom.shader.PickingColorShader(gl);
+ break;
+ case x3dom.shader.PICKING_TEXCOORD:
+ program = new x3dom.shader.PickingTexcoordShader(gl);
+ break;
+ case x3dom.shader.FRONTGROUND_TEXTURE:
+ program = new x3dom.shader.FrontgroundTextureShader(gl);
+ break;
+ case x3dom.shader.BACKGROUND_TEXTURE:
+ program = new x3dom.shader.BackgroundTextureShader(gl);
+ break;
+ case x3dom.shader.BACKGROUND_SKYTEXTURE:
+ program = new x3dom.shader.BackgroundSkyTextureShader(gl);
+ break;
+ case x3dom.shader.BACKGROUND_CUBETEXTURE:
+ program = new x3dom.shader.BackgroundCubeTextureShader(gl);
+ break;
+ case x3dom.shader.SHADOW:
+ program = new x3dom.shader.ShadowShader(gl);
+ break;
+ case x3dom.shader.BLUR:
+ program = new x3dom.shader.BlurShader(gl);
+ break;
+ case x3dom.shader.DEPTH:
+ //program = new x3dom.shader.DepthShader(gl);
+ break;
+ case x3dom.shader.NORMAL:
+ program = new x3dom.shader.NormalShader(gl);
+ break;
+ case x3dom.shader.TEXTURE_REFINEMENT:
+ program = new x3dom.shader.TextureRefinementShader(gl);
+ break;
+ default:
+ break;
+ }
+
+ if (program)
+ this.shaders[shaderIdentifier] = x3dom.Utils.wrapProgram(gl, program, shaderIdentifier);
+ else
+ x3dom.debug.logError("Couldn't create shader: " + shaderIdentifier);
+ }
+
+ return this.shaders[shaderIdentifier];
+};
+
+/**
+ * Returns a dynamic generated shader program by viewarea and shape
+ */
+x3dom.Cache.prototype.getDynamicShader = function (gl, viewarea, shape) {
+ //Generate Properties
+ var properties = x3dom.Utils.generateProperties(viewarea, shape);
+
+ var shaderID = properties.id;
+
+ if (this.shaders[shaderID] === undefined) {
+ var program;
+ if (properties.CSHADER != -1) {
+ program = new x3dom.shader.ComposedShader(gl, shape);
+ } else {
+ program = (x3dom.caps.MOBILE && !properties.CSSHADER) ?
+ new x3dom.shader.DynamicMobileShader(gl, properties) :
+ new x3dom.shader.DynamicShader(gl, properties);
+ }
+ this.shaders[shaderID] = x3dom.Utils.wrapProgram(gl, program, shaderID);
+ }
+
+ return this.shaders[shaderID];
+};
+
+/**
+ * Returns a dynamic generated shader program by properties
+ */
+x3dom.Cache.prototype.getShaderByProperties = function (gl, shape, properties, pickMode) {
+
+ //Get shaderID
+ var shaderID = properties.id;
+
+ if(pickMode != undefined || pickMode != null) {
+ shaderID += pickMode;
+ }
+
+ if (this.shaders[shaderID] === undefined)
+ {
+ var program;
+ if (properties.CSHADER != -1) {
+ program = new x3dom.shader.ComposedShader(gl, shape);
+ } else if(pickMode != undefined || pickMode != null) {
+ program = new x3dom.shader.DynamicShaderPicking(gl, properties, pickMode);
+ } else {
+ program = (x3dom.caps.MOBILE && !properties.CSSHADER) ? new x3dom.shader.DynamicMobileShader(gl, properties) :
+ new x3dom.shader.DynamicShader(gl, properties);
+ }
+ this.shaders[shaderID] = x3dom.Utils.wrapProgram(gl, program, shaderID);
+ }
+
+ return this.shaders[shaderID];
+};
+
+/**
+ * Returns the dynamically created shadow rendering shader
+ */
+x3dom.Cache.prototype.getShadowRenderingShader = function (gl, shadowedLights) {
+ var ID = "shadow";
+ for (var i = 0; i < shadowedLights.length; i++) {
+ if (x3dom.isa(shadowedLights[i], x3dom.nodeTypes.SpotLight))
+ ID += "S";
+ else if (x3dom.isa(shadowedLights[i], x3dom.nodeTypes.PointLight))
+ ID += "P";
+ else
+ ID += "D";
+ }
+
+ if (this.shaders[ID] === undefined) {
+ var program = new x3dom.shader.ShadowRenderingShader(gl, shadowedLights);
+ this.shaders[ID] = x3dom.Utils.wrapProgram(gl, program, ID);
+ }
+ return this.shaders[ID];
+};
+
+/**
+ * Release texture and shader resources
+ */
+x3dom.Cache.prototype.Release = function (gl) {
+ for (var texture in this.textures) {
+ gl.deleteTexture(this.textures[texture]);
+ }
+ this.textures = [];
+
+ for (var shaderId in this.shaders) {
+ var shader = this.shaders[shaderId];
+ var glShaders = gl.getAttachedShaders(shader.program);
+ for (var i=0; i<glShaders.length; ++i) {
+ gl.detachShader(shader.program, glShaders[i]);
+ gl.deleteShader(glShaders[i]);
+ }
+ gl.deleteProgram(shader.program)
+ }
+ this.shaders = [];
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+function startDashVideo(recurl, texturediv) {
+ var vars = function () {
+ var vars = {};
+ var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
+ vars[key] = value;
+ });
+ return vars;
+ },
+ url = recurl,
+ video,
+ context,
+ player;
+
+ if (vars && vars.hasOwnProperty("url")) {
+ url = vars.url;
+ }
+
+ video = document.querySelector(texturediv);
+ context = new Dash.di.DashContext();
+ player = new MediaPlayer(context);
+
+ player.startup();
+
+ player.attachView(video);
+ player.setAutoPlay(false);
+
+ player.attachSource(url);
+}
+
+
+/**
+ * Texture
+ */
+x3dom.Texture = function (gl, doc, cache, node) {
+ this.gl = gl;
+ this.doc = doc;
+ this.cache = cache;
+ this.node = node;
+
+ this.samplerName = "diffuseMap";
+ this.type = gl.TEXTURE_2D;
+ this.format = gl.RGBA;
+ this.magFilter = gl.LINEAR;
+ this.minFilter = gl.LINEAR;
+ this.wrapS = gl.REPEAT;
+ this.wrapT = gl.REPEAT;
+ this.genMipMaps = false;
+ this.texture = null;
+ this.ready = false;
+
+ this.dashtexture = false;
+
+ var tex = this.node;
+ var suffix = "mpd";
+
+ this.node._x3domTexture = this;
+
+ if (x3dom.isa(tex, x3dom.nodeTypes.MovieTexture)) {
+ // for dash we are lazy and check only the first url
+ if (tex._vf.url[0].indexOf(suffix, tex._vf.url[0].length - suffix.length) !== -1) {
+ this.dashtexture = true;
+ // we need to initially place the script for the dash player once in the document,
+ // but insert this additional script only, if really needed and Dash is requested!
+ var js = document.getElementById("AdditionalDashVideoScript");
+ if (!js) {
+ js = document.createElement("script");
+ js.setAttribute("type", "text/javascript");
+ js.setAttribute("src", x3dom.Texture.dashVideoScriptFile);
+ js.setAttribute("id", "AdditionalDashVideoScript");
+ js.onload = function() {
+ var texObj;
+ while ( (texObj = x3dom.Texture.loadDashVideos.pop()) ) {
+ x3dom.Texture.textNum++;
+ texObj.update();
+ }
+ js.ready = true;
+ };
+ document.getElementsByTagName('head')[0].appendChild(js);
+ }
+ if (js.ready === true) {
+ // count dash players and add this number to the class name for future reference
+ // (append in id too, for play, pause etc)
+ x3dom.Texture.textNum++;
+ // update can be directly called as script is already loaded
+ this.update();
+ }
+ else {
+ // push to stack and process later when script has loaded
+ x3dom.Texture.loadDashVideos.push(this);
+ }
+ }
+ }
+
+ if (!this.dashtexture) {
+ this.update();
+ }
+};
+
+x3dom.Texture.dashVideoScriptFile = "dash.all.js";
+x3dom.Texture.loadDashVideos = [];
+x3dom.Texture.textNum = 0;
+x3dom.Texture.clampFontSize = false;
+
+
+x3dom.Texture.prototype.update = function()
+{
+ if ( x3dom.isa(this.node, x3dom.nodeTypes.Text) )
+ {
+ this.updateText();
+ }
+ else
+ {
+ this.updateTexture();
+ }
+};
+
+x3dom.Texture.prototype.setPixel = function(x, y, pixel, update)
+{
+ var gl = this.gl;
+
+ var pixels = new Uint8Array(pixel);
+
+ gl.bindTexture(this.type, this.texture);
+
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
+
+ gl.texSubImage2D(this.type, 0, x, y, 1, 1, this.format, gl.UNSIGNED_BYTE, pixels);
+
+ gl.bindTexture(this.type, null);
+
+ if(update) {
+ this.doc.needRender = true;
+ }
+};
+
+x3dom.Texture.prototype.updateTexture = function()
+{
+ var gl = this.gl;
+ var doc = this.doc;
+ var tex = this.node;
+
+ //Set sampler
+ this.samplerName = tex._type;
+
+ //Set texture type
+ if ( x3dom.isa(tex, x3dom.nodeTypes.X3DEnvironmentTextureNode) ) {
+ this.type = gl.TEXTURE_CUBE_MAP;
+ } else {
+ this.type = gl.TEXTURE_2D;
+ }
+
+ //Set texture format
+ if (x3dom.isa(tex, x3dom.nodeTypes.PixelTexture)) {
+ switch (tex._vf.image.comp)
+ {
+ case 1: this.format = gl.LUMINANCE; break;
+ case 2: this.format = gl.LUMINANCE_ALPHA; break;
+ case 3: this.format = gl.RGB; break;
+ case 4: this.format = gl.RGBA; break;
+ }
+ } else {
+ this.format = gl.RGBA;
+ }
+
+ //Set texture min, mag, wrapS and wrapT
+ if (tex._cf.textureProperties.node !== null) {
+ var texProp = tex._cf.textureProperties.node;
+
+ this.wrapS = x3dom.Utils.boundaryModesDic(gl, texProp._vf.boundaryModeS);
+ this.wrapT = x3dom.Utils.boundaryModesDic(gl, texProp._vf.boundaryModeT);
+
+ this.minFilter = x3dom.Utils.minFilterDic(gl, texProp._vf.minificationFilter);
+ this.magFilter = x3dom.Utils.magFilterDic(gl, texProp._vf.magnificationFilter);
+
+ if (texProp._vf.generateMipMaps === true) {
+ this.genMipMaps = true;
+
+ if (this.minFilter == gl.NEAREST) {
+ this.minFilter = gl.NEAREST_MIPMAP_NEAREST;
+ } else if (this.minFilter == gl.LINEAR) {
+ this.minFilter = gl.LINEAR_MIPMAP_LINEAR;
+ }
+
+ if (this.texture && (this.texture.ready || this.texture.textureCubeReady)) {
+ gl.bindTexture(this.type, this.texture);
+ gl.generateMipmap(this.type);
+ gl.bindTexture(this.type, null);
+ }
+ } else {
+ this.genMipMaps = false;
+
+ if ( (this.minFilter == gl.LINEAR_MIPMAP_LINEAR) ||
+ (this.minFilter == gl.LINEAR_MIPMAP_NEAREST) ) {
+ this.minFilter = gl.LINEAR;
+ } else if ( (this.minFilter == gl.NEAREST_MIPMAP_LINEAR) ||
+ (this.minFilter == gl.NEAREST_MIPMAP_NEAREST) ) {
+ this.minFilter = gl.NEAREST;
+ }
+ }
+ } else {
+ if (tex._vf.repeatS == false) {
+ this.wrapS = gl.CLAMP_TO_EDGE;
+ }
+ else
+ {
+ this.wrapS = gl.REPEAT;
+ }
+ if (tex._vf.repeatT == false) {
+ this.wrapT = gl.CLAMP_TO_EDGE;
+ }
+ else
+ {
+ this.wrapT = gl.REPEAT;
+ }
+
+ if (this.samplerName == "displacementMap" ||
+ this.samplerName == "multiDiffuseAlphaMap" ||
+ this.samplerName == "multiVisibilityMap" ||
+ this.samplerName == "multiEmissiveAmbientMap" ||
+ this.samplerName == "multiSpecularShininessMap")
+ {
+ this.wrapS = gl.CLAMP_TO_EDGE;
+ this.wrapT = gl.CLAMP_TO_EDGE;
+ this.minFilter = gl.NEAREST;
+ this.magFilter = gl.NEAREST;
+ }
+ }
+
+ //Looking for child texture
+ var childTex = (tex._video && tex._needPerFrameUpdate === true);
+
+ //Set texture
+ if (tex._isCanvas && tex._canvas)
+ {
+ if (this.texture == null) {
+ this.texture = gl.createTexture()
+ }
+ this.texture.width = tex._canvas.width;
+ this.texture.height = tex._canvas.height;
+ this.texture.ready = true;
+
+ gl.bindTexture(this.type, this.texture);
+ gl.texImage2D(this.type, 0, this.format, this.format, gl.UNSIGNED_BYTE, tex._canvas);
+ if (this.genMipMaps) {
+ gl.generateMipmap(this.type);
+ }
+ gl.bindTexture(this.type, null);
+ }
+ else if (x3dom.isa(tex, x3dom.nodeTypes.RenderedTexture))
+ {
+ if (tex._webgl && tex._webgl.fbo) {
+ this.texture = tex._webgl.fbo.tex;
+ }
+ else {
+ this.texture = null;
+ x3dom.debug.logError("Try updating RenderedTexture without FBO initialized!");
+ }
+ if (this.texture) {
+ this.texture.ready = true;
+ }
+ }
+ else if (x3dom.isa(tex, x3dom.nodeTypes.PixelTexture))
+ {
+ if (this.texture == null) {
+ if (this.node._DEF) {
+ this.texture = this.cache.getTexture2DByDEF(gl, this.node._nameSpace, this.node._DEF);
+ } else {
+ this.texture = gl.createTexture();
+ }
+ }
+ this.texture.width = tex._vf.image.width;
+ this.texture.height = tex._vf.image.height;
+ this.texture.ready = true;
+
+ var pixelArr = tex._vf.image.array;//.toGL();
+ var pixelArrfont_size = tex._vf.image.width * tex._vf.image.height * tex._vf.image.comp;
+
+ if (pixelArr.length < pixelArrfont_size)
+ {
+ pixelArr = tex._vf.image.toGL();
+
+ while (pixelArr.length < pixelArrfont_size) {
+ pixelArr.push(0);
+ }
+ }
+
+ var pixels = new Uint8Array(pixelArr);
+
+ gl.bindTexture(this.type, this.texture);
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
+ gl.texImage2D(this.type, 0, this.format,
+ tex._vf.image.width, tex._vf.image.height, 0,
+ this.format, gl.UNSIGNED_BYTE, pixels);
+ if (this.genMipMaps) {
+ gl.generateMipmap(this.type);
+ }
+ gl.bindTexture(this.type, null);
+ }
+ else if (x3dom.isa(tex, x3dom.nodeTypes.MovieTexture) || childTex)
+ {
+ var that = this;
+ var p = document.getElementsByTagName('body')[0];
+
+ if (this.texture == null) {
+ this.texture = gl.createTexture();
+ }
+
+ if (this.dashtexture) {
+ var element_vid = document.createElement('div');
+ element_vid.setAttribute('class', 'dash-video-player' + x3dom.Texture.textNum);
+ tex._video = document.createElement('video');
+ tex._video.setAttribute('preload', 'auto');
+ tex._video.setAttribute('muted', 'muted');
+
+ var scriptToRun = document.createElement('script');
+ scriptToRun.setAttribute('type', 'text/javascript');
+ scriptToRun.innerHTML = 'startDashVideo("' + tex._vf.url[0] +
+ '",".dash-video-player' + x3dom.Texture.textNum + ' video")';
+ element_vid.appendChild(scriptToRun);
+ element_vid.appendChild(tex._video);
+ p.appendChild(element_vid);
+ tex._video.style.visibility = "hidden";
+ tex._video.style.display = "none";
+ }
+ else {
+ if (!childTex) {
+ tex._video = document.createElement('video');
+ tex._video.setAttribute('preload', 'auto');
+ tex._video.setAttribute('muted', 'muted');
+ p.appendChild(tex._video);
+ tex._video.style.visibility = "hidden";
+ tex._video.style.display = "none";
+ }
+ for (var i = 0; i < tex._vf.url.length; i++) {
+ var videoUrl = tex._nameSpace.getURL(tex._vf.url[i]);
+ x3dom.debug.logInfo('Adding video file: ' + videoUrl);
+ var src = document.createElement('source');
+ src.setAttribute('src', videoUrl);
+ tex._video.appendChild(src);
+ }
+ }
+
+ var updateMovie = function()
+ {
+ gl.bindTexture(that.type, that.texture);
+ gl.texImage2D(that.type, 0, that.format, that.format, gl.UNSIGNED_BYTE, tex._video);
+ if (that.genMipMaps) {
+ gl.generateMipmap(that.type);
+ }
+ gl.bindTexture(that.type, null);
+ that.texture.ready = true;
+ doc.needRender = true;
+ };
+
+ var startVideo = function()
+ {
+ tex._video.play();
+ tex._intervalID = setInterval(updateMovie, 16);
+ };
+
+ var videoDone = function()
+ {
+ clearInterval(tex._intervalID);
+ if (tex._vf.loop === true)
+ {
+ tex._video.play();
+ tex._intervalID = setInterval(updateMovie, 16);
+ }
+ };
+
+ // Start listening for the canplaythrough event, so we do not
+ // start playing the video until we can do so without stuttering
+ tex._video.addEventListener("canplaythrough", startVideo, true);
+
+ // Start listening for the ended event, so we can stop the
+ // texture update when the video is finished playing
+ tex._video.addEventListener("ended", videoDone, true);
+ }
+ else if (x3dom.isa(tex, x3dom.nodeTypes.X3DEnvironmentTextureNode))
+ {
+ this.texture = this.cache.getTextureCube(gl, doc, tex.getTexUrl(), false,
+ tex._vf.crossOrigin, tex._vf.scale, this.genMipMaps);
+ }
+ else
+ {
+ this.texture = this.cache.getTexture2D(gl, doc, tex._nameSpace.getURL(tex._vf.url[0]),
+ false, tex._vf.crossOrigin, tex._vf.scale, this.genMipMaps);
+ }
+};
+
+x3dom.Texture.prototype.updateText = function()
+{
+ var gl = this.gl;
+
+ this.wrapS = gl.CLAMP_TO_EDGE;
+ this.wrapT = gl.CLAMP_TO_EDGE;
+
+ var fontStyleNode = this.node._cf.fontStyle.node;
+
+ var font_family = 'serif';
+ var font_style = 'normal';
+ var font_justify = 'left';
+ var font_size = 1.0;
+ var font_spacing = 1.0;
+ var font_horizontal = true;
+ var font_language = "";
+
+ if ( fontStyleNode !== null )
+ {
+ var fonts = fontStyleNode._vf.family.toString();
+
+ // clean attribute values and split in array
+ fonts = fonts.trim().replace(/\'/g,'').replace(/\,/, ' ');
+ fonts = fonts.split(" ");
+
+ font_family = Array.map(fonts, function(s) {
+ if (s == 'SANS') { return 'sans-serif'; }
+ else if (s == 'SERIF') { return 'serif'; }
+ else if (s == 'TYPEWRITER') { return 'monospace'; }
+ else { return ''+s+''; } //'Verdana'
+ }).join(",");
+
+ font_style = fontStyleNode._vf.style.toString().replace(/\'/g,'');
+ switch (font_style.toUpperCase()) {
+ case 'PLAIN': font_style = 'normal'; break;
+ case 'BOLD': font_style = 'bold'; break;
+ case 'ITALIC': font_style = 'italic'; break;
+ case 'BOLDITALIC': font_style = 'italic bold'; break;
+ default: font_style = 'normal';
+ }
+
+ var leftToRight = fontStyleNode._vf.leftToRight ? 'ltr' : 'rtl';
+ var topToBottom = fontStyleNode._vf.topToBottom;
+
+ // TODO: make it possible to use multiple values
+ font_justify = fontStyleNode._vf.justify[0].toString().replace(/\'/g,'');
+
+ switch (font_justify.toUpperCase()) {
+ case 'BEGIN': font_justify = 'left'; break;
+ case 'END': font_justify = 'right'; break;
+ case 'FIRST': font_justify = 'left'; break; // not clear what to do with this one
+ case 'MIDDLE': font_justify = 'center'; break;
+ default: font_justify = 'left'; break;
+ }
+
+ font_size = fontStyleNode._vf.size;
+ font_spacing = fontStyleNode._vf.spacing;
+ font_horizontal = fontStyleNode._vf.horizontal;
+ font_language = fontStyleNode._vf.language;
+
+ if (font_size < 0.1) font_size = 0.1;
+ if(x3dom.Texture.clampFontSize && font_size > 2.3)
+ {
+ font_size = 2.3;
+ }
+ }
+
+ var textX, textY;
+ var paragraph = this.node._vf.string;
+ var text_canvas = document.createElement('canvas');
+ text_canvas.dir = leftToRight;
+ var textHeight = font_size * 42; // pixel size relative to local coordinate system
+ var textAlignment = font_justify;
+
+ // needed to make webfonts work
+ document.body.appendChild(text_canvas);
+
+ var text_ctx = text_canvas.getContext('2d');
+
+ // calculate font font_size in px
+ text_ctx.font = font_style + " " + textHeight + "px " + font_family;
+
+ var maxWidth = text_ctx.measureText(paragraph[0]).width;
+ var i;
+
+ // calculate maxWidth
+ for(i = 1; i < paragraph.length; i++) {
+ if(text_ctx.measureText(paragraph[i]).width > maxWidth)
+ maxWidth = text_ctx.measureText(paragraph[i]).width;
+ }
+ var canvas_scale = 1.1; //needed for some fonts that are higher than the textHeight
+ text_canvas.width = maxWidth * canvas_scale;
+ text_canvas.height = textHeight * paragraph.length * canvas_scale;
+
+ switch(textAlignment) {
+ case "left": textX = 0; break;
+ case "center": textX = text_canvas.width/2; break;
+ case "right": textX = text_canvas.width; break;
+ }
+
+ var txtW = text_canvas.width;
+ var txtH = text_canvas.height;
+
+ text_ctx.fillStyle = 'rgba(0,0,0,0)';
+ text_ctx.fillRect(0, 0, text_ctx.canvas.width, text_ctx.canvas.height);
+
+ // write white text with black border
+ text_ctx.fillStyle = 'white';
+ text_ctx.lineWidth = 2.5;
+ text_ctx.strokeStyle = 'grey';
+ text_ctx.textBaseline = 'top';
+
+ text_ctx.font = font_style + " " + textHeight + "px " + font_family;
+ text_ctx.textAlign = textAlignment;
+
+ // create the multiline text
+ for(i = 0; i < paragraph.length; i++) {
+ textY = i*textHeight;
+ text_ctx.fillText(paragraph[i], textX, textY);
+ }
+
+ if( this.texture === null )
+ {
+ this.texture = gl.createTexture();
+ }
+
+ gl.bindTexture(this.type, this.texture);
+ gl.texImage2D(this.type, 0, this.format, this.format, gl.UNSIGNED_BYTE, text_canvas);
+ gl.bindTexture(this.type, null);
+
+ //remove canvas after Texture creation
+ document.body.removeChild(text_canvas);
+
+ var w = txtW / 100.0;
+ var h = txtH / 100.0;
+
+ this.node._mesh._positions[0] = [-w,-h+.4,0, w,-h+.4,0, w,h+.4,0, -w,h+.4,0];
+
+ this.node.invalidateVolume();
+ Array.forEach(this.node._parentNodes, function (node) {
+ node.setAllDirty();
+ });
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+// ### X3DDocument ###
+x3dom.X3DDocument = function(canvas, ctx, settings) {
+ this.canvas = canvas; // The <canvas> elem
+ this.ctx = ctx; // WebGL context object, AKA gl
+ this.properties = settings; // showStat, showLog, etc.
+ this.needRender = true; // Trigger redraw if true
+ this._x3dElem = null; // Backref to <X3D> root element (set on parsing)
+ this._scene = null; // Scene root element
+ this._viewarea = null; // Viewport, handles rendering and interaction
+ this.downloadCount = 0; // Counter for objects to be loaded
+
+ // bag for pro-active (or multi-core-like) elements
+ this._nodeBag = {
+ timer: [], // TimeSensor (tick)
+ lights: [], // Light
+ clipPlanes: [], // ClipPlane
+ followers: [], // X3DFollowerNode
+ trans: [], // X3DTransformNode (for listening to CSS changes)
+ renderTextures: [], // RenderedTexture
+ viewarea: [], // Viewport (for updating camera navigation)
+ affectedPointingSensors: [] // all X3DPointingDeviceSensor currently activated (i.e., used for interaction),
+ // this list is maintained for efficient update / deactivation
+ };
+
+ this.onload = function () {};
+ this.onerror = function () {};
+};
+
+x3dom.X3DDocument.prototype.load = function (uri, sceneElemPos) {
+ // Load uri. Get sceneDoc, list of sub-URIs.
+ // For each URI, get docs[uri] = whatever, extend list of sub-URIs.
+
+ var uri_docs = {};
+ var queued_uris = [uri];
+ var doc = this;
+
+ function next_step() {
+ // TODO: detect circular inclusions
+ // TODO: download in parallel where possible
+
+ if (queued_uris.length === 0) {
+ // All done
+ doc._setup(uri_docs[uri], uri_docs, sceneElemPos);
+ doc.onload();
+ return;
+ }
+ var next_uri = queued_uris.shift();
+
+ if ( x3dom.isX3DElement(next_uri) &&
+ (next_uri.localName.toLowerCase() === 'x3d' || next_uri.localName.toLowerCase() === 'websg') )
+ {
+ // Special case, when passed an X3D node instead of a URI string
+ uri_docs[next_uri] = next_uri;
+ doc._x3dElem = next_uri;
+ next_step();
+ }
+ }
+
+ next_step();
+};
+
+x3dom.findScene = function(x3dElem) {
+ var sceneElems = [];
+
+ for (var i=0; i<x3dElem.childNodes.length; i++) {
+ var sceneElem = x3dElem.childNodes[i];
+
+ if (sceneElem && sceneElem.localName && sceneElem.localName.toLowerCase() === "scene") {
+ sceneElems.push(sceneElem);
+ }
+ }
+
+ if (sceneElems.length > 1) {
+ x3dom.debug.logError("X3D element has more than one Scene child (has " +
+ x3dElem.childNodes.length + ").");
+ }
+ else {
+ return sceneElems[0];
+ }
+ return null;
+};
+
+
+x3dom.X3DDocument.prototype._setup = function (sceneDoc, uriDocs, sceneElemPos) {
+ var doc = this;
+
+ function cleanNodeBag(bag, node) {
+ for (var i=0, n=bag.length; i<n; i++) {
+ if (bag[i] === node) {
+ bag.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ function removeX3DOMBackendGraph(domNode) {
+ var children = domNode.childNodes;
+
+ for (var i=0, n=children.length; i<n; i++) {
+ removeX3DOMBackendGraph(children[i]);
+ }
+
+ if (domNode._x3domNode) {
+ var node = domNode._x3domNode;
+ var nameSpace = node._nameSpace;
+
+ if (x3dom.isa(node, x3dom.nodeTypes.X3DShapeNode)) {
+ if (node._cleanupGLObjects) {
+ node._cleanupGLObjects(true);
+ // TODO: more cleanups, e.g. texture/shader cache?
+ }
+ if (x3dom.nodeTypes.Shape.idMap.nodeID[node._objectID]) {
+ delete x3dom.nodeTypes.Shape.idMap.nodeID[node._objectID];
+ }
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.TimeSensor)) {
+ cleanNodeBag(doc._nodeBag.timer, node);
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.X3DLightNode)) {
+ cleanNodeBag(doc._nodeBag.lights, node);
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.X3DFollowerNode)) {
+ cleanNodeBag(doc._nodeBag.followers, node);
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.X3DTransformNode)) {
+ cleanNodeBag(doc._nodeBag.trans, node);
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.RenderedTexture)) {
+ cleanNodeBag(doc._nodeBag.renderTextures, node);
+ if (node._cleanupGLObjects) {
+ node._cleanupGLObjects();
+ }
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.X3DPointingDeviceSensorNode)) {
+ cleanNodeBag(doc._nodeBag.affectedPointingSensors, node);
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.Texture)) {
+ node.shutdown(); // general texture might have video
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.AudioClip)) {
+ node.shutdown();
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.X3DBindableNode)) {
+ var stack = node._stack;
+ if (stack) {
+ node.bind(false);
+ cleanNodeBag(stack._bindBag, node);
+ }
+ // Background may have geometry
+ if (node._cleanupGLObjects) {
+ node._cleanupGLObjects();
+ }
+ }
+ else if (x3dom.isa(node, x3dom.nodeTypes.Scene)) {
+ if (node._webgl) {
+ node._webgl = null;
+ // TODO; explicitly delete all gl objects
+ }
+ }
+
+ //do not remove node from namespace if it was only "USE"d
+ if (nameSpace && ! domNode.getAttribute('use'))
+ {
+ nameSpace.removeNode(node._DEF);
+ }
+ node._xmlNode = null;
+
+ delete domNode._x3domNode;
+ }
+ }
+
+ // Test capturing DOM mutation events on the X3D subscene
+ var domEventListener = {
+ onAttrModified: function(e) {
+ if ('_x3domNode' in e.target) {
+ var attrToString = {
+ 1: "MODIFICATION",
+ 2: "ADDITION",
+ 3: "REMOVAL"
+ };
+ //x3dom.debug.logInfo("MUTATION: " + e.attrName + ", " + e.type + ", attrChange=" + attrToString[e.attrChange]);
+ e.target._x3domNode.updateField(e.attrName, e.newValue);
+ doc.needRender = true;
+ }
+ },
+
+ onNodeRemoved: function(e) {
+ var domNode = e.target;
+ if (!domNode)
+ return;
+
+ if ('_x3domNode' in domNode.parentNode && '_x3domNode' in domNode) {
+ var parent = domNode.parentNode._x3domNode;
+ var child = domNode._x3domNode;
+
+ if (parent && child) {
+ parent.removeChild(child);
+ parent.nodeChanged();
+
+ removeX3DOMBackendGraph(domNode);
+
+ if (doc._viewarea && doc._viewarea._scene) {
+ doc._viewarea._scene.nodeChanged();
+ doc._viewarea._scene.updateVolume();
+ doc.needRender = true;
+ }
+ }
+ }
+ else if (domNode.localName && domNode.localName.toUpperCase() == "ROUTE" && domNode._nodeNameSpace) {
+ var fromNode = domNode._nodeNameSpace.defMap[domNode.getAttribute('fromNode')];
+ var toNode = domNode._nodeNameSpace.defMap[domNode.getAttribute('toNode')];
+
+ if (fromNode && toNode) {
+ fromNode.removeRoute(domNode.getAttribute('fromField'), toNode, domNode.getAttribute('toField'));
+ }
+ }
+ else if (domNode.localName && domNode.localName.toUpperCase() == "X3D") {
+ var runtime = domNode.runtime;
+
+ if (runtime && runtime.canvas && runtime.canvas.doc && runtime.canvas.doc._scene) {
+ var sceneNode = runtime.canvas.doc._scene._xmlNode;
+
+ removeX3DOMBackendGraph(sceneNode);
+
+ // also clear corresponding X3DCanvas element
+ for (var i=0; i<x3dom.canvases.length; i++) {
+ if (x3dom.canvases[i] === runtime.canvas) {
+ x3dom.canvases[i].doc.shutdown(x3dom.canvases[i].gl);
+ x3dom.canvases.splice(i, 1);
+ break;
+ }
+ }
+
+ runtime.canvas.doc._scene = null;
+ runtime.canvas.doc._viewarea = null;
+ runtime.canvas.doc = null;
+ runtime.canvas = null;
+ runtime = null;
+
+ domNode.context = null;
+ domNode.runtime = null;
+ }
+ }
+ },
+
+ onNodeInserted: function(e) {
+ var child = e.target;
+ var parentNode = child.parentNode;
+
+ // only act on x3dom nodes, ignore regular HTML
+ if ('_x3domNode' in parentNode) {
+ if (parentNode.tagName && parentNode.tagName.toLowerCase() == 'inline' ||
+ parentNode.tagName.toLowerCase() == 'multipart') {
+ // do nothing
+ }
+ else {
+ var parent = parentNode._x3domNode;
+
+ if (parent && parent._nameSpace && (child instanceof Element)) {
+
+ if (x3dom.caps.DOMNodeInsertedEvent_perSubtree)
+ {
+ removeX3DOMBackendGraph(child); // not really necessary...
+ }
+
+ var newNode = parent._nameSpace.setupTree(child);
+
+ parent.addChild(newNode, child.getAttribute("containerField"));
+ parent.nodeChanged();
+
+ var grandParentNode = parentNode.parentNode;
+ if (grandParentNode && grandParentNode._x3domNode)
+ grandParentNode._x3domNode.nodeChanged();
+
+ if (doc._viewarea && doc._viewarea._scene) {
+ doc._viewarea._scene.nodeChanged();
+ doc._viewarea._scene.updateVolume();
+ doc.needRender = true;
+ }
+ }
+ else {
+ x3dom.debug.logWarning("No _nameSpace in onNodeInserted");
+ }
+ }
+ }
+ }
+ };
+
+ //sceneDoc.addEventListener('DOMCharacterDataModified', domEventListener.onAttrModified, true);
+ sceneDoc.addEventListener('DOMNodeRemoved', domEventListener.onNodeRemoved, true);
+ sceneDoc.addEventListener('DOMNodeInserted', domEventListener.onNodeInserted, true);
+ if ( (x3dom.userAgentFeature.supportsDOMAttrModified === true ) ) {
+ sceneDoc.addEventListener('DOMAttrModified', domEventListener.onAttrModified, true);
+ }
+
+ // sceneDoc is the X3D element here...
+ var sceneElem = x3dom.findScene(sceneDoc);
+
+ // create and add BindableBag that holds all bindable stacks
+ this._bindableBag = new x3dom.BindableBag(this);
+
+ // create and add the NodeNameSpace
+ var nameSpace = new x3dom.NodeNameSpace("scene", doc);
+
+ var scene = nameSpace.setupTree(sceneElem);
+
+ // link scene
+ this._scene = scene;
+ this._bindableBag.setRefNode(scene);
+
+ // create view
+ this._viewarea = new x3dom.Viewarea (this, scene);
+
+ this._viewarea._width = this.canvas.width;
+ this._viewarea._height = this.canvas.height;
+};
+
+x3dom.X3DDocument.prototype.advanceTime = function (t) {
+ var i = 0;
+
+ if (this._nodeBag.timer.length) {
+ for (i=0; i < this._nodeBag.timer.length; i++)
+ { this.needRender |= this._nodeBag.timer[i].tick(t); }
+ }
+ if (this._nodeBag.followers.length) {
+ for (i=0; i < this._nodeBag.followers.length; i++)
+ { this.needRender |= this._nodeBag.followers[i].tick(t); }
+ }
+ // just a temporary tricker solution to update the CSS transforms
+ if (this._nodeBag.trans.length) {
+ for (i=0; i < this._nodeBag.trans.length; i++)
+ { this.needRender |= this._nodeBag.trans[i].tick(t); }
+ }
+ if (this._nodeBag.viewarea.length) {
+ for (i=0; i < this._nodeBag.viewarea.length; i++)
+ { this.needRender |= this._nodeBag.viewarea[i].tick(t); }
+ }
+};
+
+x3dom.X3DDocument.prototype.render = function (ctx) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ ctx.renderScene(this._viewarea);
+};
+
+x3dom.X3DDocument.prototype.onPick = function (ctx, x, y) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ ctx.pickValue(this._viewarea, x, y, 1);
+};
+
+x3dom.X3DDocument.prototype.onPickRect = function (ctx, x1, y1, x2, y2) {
+ if (!ctx || !this._viewarea) {
+ return [];
+ }
+
+ return ctx.pickRect(this._viewarea, x1, y1, x2, y2);
+};
+
+x3dom.X3DDocument.prototype.onMove = function (ctx, x, y, buttonState) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ if (this._viewarea._scene._vf.doPickPass)
+ ctx.pickValue(this._viewarea, x, y, buttonState);
+ this._viewarea.onMove(x, y, buttonState);
+};
+
+x3dom.X3DDocument.prototype.onMoveView = function (ctx, translation, rotation) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ this._viewarea.onMoveView(translation, rotation);
+};
+
+x3dom.X3DDocument.prototype.onDrag = function (ctx, x, y, buttonState) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ if (this._viewarea._scene._vf.doPickPass)
+ ctx.pickValue(this._viewarea, x, y, buttonState);
+ this._viewarea.onDrag(x, y, buttonState);
+};
+
+x3dom.X3DDocument.prototype.onWheel = function (ctx, x, y, originalY) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ if (this._viewarea._scene._vf.doPickPass)
+ ctx.pickValue(this._viewarea, x, originalY, 0);
+ this._viewarea.onDrag(x, y, 2);
+};
+
+x3dom.X3DDocument.prototype.onMousePress = function (ctx, x, y, buttonState) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ // update volume only on click since expensive!
+ this._viewarea._scene.updateVolume();
+
+ ctx.pickValue(this._viewarea, x, y, buttonState);
+ this._viewarea.onMousePress(x, y, buttonState);
+};
+
+x3dom.X3DDocument.prototype.onMouseRelease = function (ctx, x, y, buttonState, prevButton) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ var button = (prevButton << 8) | buttonState; // for shadowObjectIdChanged
+ ctx.pickValue(this._viewarea, x, y, button);
+ this._viewarea.onMouseRelease(x, y, buttonState, prevButton);
+};
+
+x3dom.X3DDocument.prototype.onMouseOver = function (ctx, x, y, buttonState) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ ctx.pickValue(this._viewarea, x, y, buttonState);
+ this._viewarea.onMouseOver(x, y, buttonState);
+};
+
+x3dom.X3DDocument.prototype.onMouseOut = function (ctx, x, y, buttonState) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ ctx.pickValue(this._viewarea, x, y, buttonState);
+ this._viewarea.onMouseOut(x, y, buttonState);
+};
+
+x3dom.X3DDocument.prototype.onDoubleClick = function (ctx, x, y) {
+ if (!ctx || !this._viewarea) {
+ return;
+ }
+
+ this._viewarea.onDoubleClick(x, y);
+};
+
+
+x3dom.X3DDocument.prototype.onKeyDown = function(keyCode)
+{
+ //x3dom.debug.logInfo("pressed key " + keyCode);
+ switch (keyCode) {
+ case 37: /* left */
+ this._viewarea.strafeLeft();
+ break;
+ case 38: /* up */
+ this._viewarea.moveFwd();
+ break;
+ case 39: /* right */
+ this._viewarea.strafeRight();
+ break;
+ case 40: /* down */
+ this._viewarea.moveBwd();
+ break;
+ default:
+ }
+};
+
+x3dom.X3DDocument.prototype.onKeyUp = function(keyCode)
+{
+ //x3dom.debug.logInfo("released key " + keyCode);
+ var stack = null;
+
+ switch (keyCode) {
+ case 13: /* return */
+ x3dom.toggleFullScreen();
+ break;
+ case 27: /* ESC */
+ window.history.back(); // emulate good old ESC key
+ break;
+ case 33: /* page up */
+ stack = this._scene.getViewpoint()._stack;
+
+ if (stack) {
+ stack.switchTo('next');
+ }
+ else {
+ x3dom.debug.logError ('No valid ViewBindable stack.');
+ }
+ break;
+ case 34: /* page down */
+ stack = this._scene.getViewpoint()._stack;
+
+ if (stack) {
+ stack.switchTo('prev');
+ }
+ else {
+ x3dom.debug.logError ('No valid ViewBindable stack.');
+ }
+ break;
+ case 37: /* left */
+ break;
+ case 38: /* up */
+ break;
+ case 39: /* right */
+ break;
+ case 40: /* down */
+ break;
+ default:
+ }
+};
+
+x3dom.X3DDocument.prototype.onKeyPress = function(charCode)
+{
+ //x3dom.debug.logInfo("pressed key " + charCode);
+ var nav = this._scene.getNavigationInfo();
+ var env = this._scene.getEnvironment();
+
+ switch (charCode)
+ {
+ case 32: /* space */
+ var states = this.canvas.parent.stateViewer;
+ if (states) {
+ states.display();
+ }
+ x3dom.debug.logInfo("a: show all | d: show helper buffers | s: small feature culling | t: light view | " +
+ "m: toggle render mode | c: frustum culling | p: intersect type | r: reset view | \n" +
+ "e: examine mode | f: fly mode | y: freefly mode | w: walk mode | h: helicopter mode | " +
+ "l: lookAt mode | o: lookaround | g: game mode | n: turntable | u: upright position | \n" +
+ "v: print viewpoint info | pageUp: next view | pageDown: prev. view | " +
+ "+: increase speed | -: decrease speed ");
+ break;
+ case 43: /* + (incr. speed) */
+ nav._vf.speed = 2 * nav._vf.speed;
+ x3dom.debug.logInfo("Changed navigation speed to " + nav._vf.speed);
+ break;
+ case 45: /* - (decr. speed) */
+ nav._vf.speed = 0.5 * nav._vf.speed;
+ x3dom.debug.logInfo("Changed navigation speed to " + nav._vf.speed);
+ break;
+ case 51: /* 3 (decr pg error tol) */
+ x3dom.nodeTypes.PopGeometry.ErrorToleranceFactor += 0.5;
+ x3dom.debug.logInfo("Changed POP error tolerance to " + x3dom.nodeTypes.PopGeometry.ErrorToleranceFactor);
+ break;
+ case 52: /* 4 (incr pg error tol) */
+ x3dom.nodeTypes.PopGeometry.ErrorToleranceFactor -= 0.5;
+ x3dom.debug.logInfo("Changed POP error tolerance to " + x3dom.nodeTypes.PopGeometry.ErrorToleranceFactor);
+ break;
+ case 54: /* 6 (incr height) */
+ nav._vf.typeParams[1] += 1.0;
+ nav._heliUpdated = false;
+ x3dom.debug.logInfo("Changed helicopter height to " + nav._vf.typeParams[1]);
+ break;
+ case 55: /* 7 (decr height) */
+ nav._vf.typeParams[1] -= 1.0;
+ nav._heliUpdated = false;
+ x3dom.debug.logInfo("Changed helicopter height to " + nav._vf.typeParams[1]);
+ break;
+ case 56: /* 8 (decr angle) */
+ nav._vf.typeParams[0] -= 0.02;
+ nav._heliUpdated = false;
+ x3dom.debug.logInfo("Changed helicopter angle to " + nav._vf.typeParams[0]);
+ break;
+ case 57: /* 9 (incr angle) */
+ nav._vf.typeParams[0] += 0.02;
+ nav._heliUpdated = false;
+ x3dom.debug.logInfo("Changed helicopter angle to " + nav._vf.typeParams[0]);
+ break;
+ case 97: /* a, view all */
+ this._viewarea.showAll();
+ break;
+ case 99: /* c, toggle frustum culling */
+ env._vf.frustumCulling = !env._vf.frustumCulling;
+ x3dom.debug.logInfo("Viewfrustum culling " + (env._vf.frustumCulling ? "on" : "off"));
+ break;
+ case 100: /* d, switch on/off buffer view for dbg */
+ if (this._viewarea._visDbgBuf === undefined) {
+ this._viewarea._visDbgBuf = (this._x3dElem.getAttribute("showLog") === 'true');
+ }
+ this._viewarea._visDbgBuf = !this._viewarea._visDbgBuf;
+ x3dom.debug.logContainer.style.display = (this._viewarea._visDbgBuf == true) ? "block" : "none";
+ break;
+ case 101: /* e, examine mode */
+ nav.setType("examine", this._viewarea);
+ break;
+ case 102: /* f, fly mode */
+ nav.setType("fly", this._viewarea);
+ break;
+ case 103: /* g, game mode */
+ nav.setType("game", this._viewarea);
+ break;
+ case 104: /* h, helicopter mode */
+ nav.setType("helicopter", this._viewarea);
+ break;
+ case 105: /* i, fit all */
+ this._viewarea.fit(this._scene._lastMin, this._scene._lastMax);
+ break;
+ case 108: /* l, lookAt mode */
+ nav.setType("lookat", this._viewarea);
+ break;
+ case 109: /* m, toggle "points" attribute */
+ this._viewarea._points = ++this._viewarea._points % 3;
+ break;
+ case 110: /* n, turntable */
+ nav.setType("turntable", this._viewarea);
+ break;
+ case 111: /* o, look around like in fly, but don't move */
+ nav.setType("lookaround", this._viewarea);
+ break;
+ case 112: /* p, switch intersect type */
+ switch(this._scene._vf.pickMode.toLowerCase())
+ {
+ case "idbuf":
+ this._scene._vf.pickMode = "color";
+ break;
+ case "color":
+ this._scene._vf.pickMode = "texCoord";
+ break;
+ case "texcoord":
+ this._scene._vf.pickMode = "box";
+ break;
+ default:
+ this._scene._vf.pickMode = "idBuf";
+ break;
+ }
+ x3dom.debug.logInfo("Switch pickMode to '" + this._scene._vf.pickMode + "'.");
+ break;
+ case 114: /* r, reset view */
+ this._viewarea.resetView();
+ break;
+ case 115: /* s, toggle small feature culling */
+ env._vf.smallFeatureCulling = !env._vf.smallFeatureCulling;
+ x3dom.debug.logInfo("Small feature culling " + (env._vf.smallFeatureCulling ? "on" : "off"));
+ break;
+ case 116: /* t, light view */
+ if (this._nodeBag.lights.length > 0) {
+ this._viewarea.animateTo(this._viewarea.getLightMatrix()[0], this._scene.getViewpoint());
+ }
+ break;
+ case 117: /* u, upright position */
+ this._viewarea.uprightView();
+ break;
+ case 118: /* v, print viewpoint position/orientation */
+ var that = this;
+ (function() {
+ var viewpoint = that._viewarea._scene.getViewpoint();
+ var mat_view = that._viewarea.getViewMatrix().inverse();
+
+ var rotation = new x3dom.fields.Quaternion(0, 0, 1, 0);
+ rotation.setValue(mat_view);
+ var rot = rotation.toAxisAngle();
+ var translation = mat_view.e3();
+
+ x3dom.debug.logInfo('\n&lt;Viewpoint position="' + translation.x.toFixed(5) + ' '
+ + translation.y.toFixed(5) + ' ' + translation.z.toFixed(5) + '" ' +
+ 'orientation="' + rot[0].x.toFixed(5) + ' ' + rot[0].y.toFixed(5) + ' '
+ + rot[0].z.toFixed(5) + ' ' + rot[1].toFixed(5) + '" \n\t' +
+ 'zNear="' + viewpoint.getNear().toFixed(5) + '" ' +
+ 'zFar="' + viewpoint.getFar().toFixed(5) + '" ' +
+ 'description="' + viewpoint._vf.description + '"&gt;' +
+ '&lt;/Viewpoint&gt;');
+ })();
+ break;
+ case 119: /* w, walk mode */
+ nav.setType("walk", this._viewarea);
+ break;
+ case 121: /* y, freefly mode */
+ nav.setType("freefly", this._viewarea);
+ break;
+ default:
+ }
+};
+
+x3dom.X3DDocument.prototype.shutdown = function(ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ ctx.shutdown(this._viewarea);
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+x3dom.MatrixMixer = function(beginTime, endTime) {
+ if (arguments.length === 0) {
+ this._beginTime = 0;
+ this._endTime = 1;
+ }
+ else {
+ this._beginTime = beginTime;
+ this._endTime = endTime;
+ }
+
+ this._beginMat = x3dom.fields.SFMatrix4f.identity();
+ this._beginInvMat = x3dom.fields.SFMatrix4f.identity();
+ this._beginLogMat = x3dom.fields.SFMatrix4f.identity();
+ this._endMat = x3dom.fields.SFMatrix4f.identity();
+ this._endLogMat = x3dom.fields.SFMatrix4f.identity();
+};
+
+x3dom.MatrixMixer.prototype.calcFraction = function(time) {
+ var fraction = (time - this._beginTime) / (this._endTime - this._beginTime);
+ return (Math.sin((fraction * Math.PI) - (Math.PI / 2)) + 1) / 2.0;
+};
+
+x3dom.MatrixMixer.prototype.setBeginMatrix = function(mat) {
+ this._beginMat.setValues(mat);
+ this._beginInvMat = mat.inverse();
+ this._beginLogMat = x3dom.fields.SFMatrix4f.zeroMatrix(); // mat.log();
+};
+
+x3dom.MatrixMixer.prototype.setEndMatrix = function(mat) {
+ this._endMat.setValues(mat);
+ this._endLogMat = mat.mult(this._beginInvMat).log();
+ this._logDiffMat = this._endLogMat.addScaled(this._beginLogMat, -1);
+};
+
+x3dom.MatrixMixer.prototype.mix = function(time) {
+ var mat = null;
+
+ if (time <= this._beginTime)
+ {
+ mat = x3dom.fields.SFMatrix4f.copy(this._beginLogMat);
+ }
+ else
+ {
+ if (time >= this._endTime)
+ {
+ mat = x3dom.fields.SFMatrix4f.copy(this._endLogMat);
+ }
+ else
+ {
+ var fraction = this.calcFraction(time);
+ mat = this._logDiffMat.multiply(fraction).add(this._beginLogMat);
+ }
+ }
+
+ return mat.exp().mult(this._beginMat);
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/**
+ * Input types - X3DOM allows either navigation or interaction.
+ * During each frame, only interaction of the current type is being processed, it is not possible to
+ * perform interaction (for instance, selecting or dragging objects) and navigation at the same time
+ */
+x3dom.InputTypes = {
+ NAVIGATION: 1,
+ INTERACTION: 2
+};
+
+
+/**
+* Constructor.
+*
+* @class represents a view area
+* @param {x3dom.X3DDocument} document - the target X3DDocument
+* @param {Object} scene - the scene
+*/
+// ### Viewarea ###
+x3dom.Viewarea = function (document, scene) {
+ this._doc = document; // x3ddocument
+ this._scene = scene; // FIXME: updates ?!
+
+ document._nodeBag.viewarea.push(this);
+
+ /**
+ * picking informations containing
+ * pickingpos, pickNorm, pickObj, firstObj, lastObj, lastClickObj, shadowObjId
+ * @var {Object} _pickingInfo
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._pickingInfo = {
+ pickPos: new x3dom.fields.SFVec3f(0, 0, 0),
+ pickNorm: new x3dom.fields.SFVec3f(0, 0, 1),
+ pickObj: null,
+ firstObj: null,
+ lastObj: null,
+ lastClickObj: null,
+ shadowObjectId: -1
+ };
+
+ this._currentInputType = x3dom.InputTypes.NAVIGATION;
+
+ /**
+ * rotation matrix
+ * @var {x3dom.fields.SFMatrix4f} _rotMat
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._rotMat = x3dom.fields.SFMatrix4f.identity();
+
+ /**
+ * translation matrix
+ * @var {x3dom.fields.SFMatrix4f} _transMat
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._transMat = x3dom.fields.SFMatrix4f.identity();
+
+ /**
+ * movement vector
+ * @var {x3dom.fields.SFVec3f} _movement
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._movement = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ /**
+ * flag to signal a needed NavigationMatrixUpdate
+ * @var {Boolean} _needNavigationMatrixUpdate
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._needNavigationMatrixUpdate = true;
+
+ /**
+ * time passed since last update
+ * @var {Number} _deltaT
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._deltaT = 0;
+
+ this._flyMat = null;
+
+ this._pitch = 0;
+ this._yaw = 0;
+
+ /**
+ * eye position of the view area
+ * @var {x3dom.fields.SFVec3f} _eyePos
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._eyePos = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ /**
+ * width of the view area
+ * @var {Number} _width
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._width = 400;
+
+ /**
+ * height of the view area
+ * @var {Number} _height
+ * @memberof x3dom.Viewarea
+ * @instance
+ * @protected
+ */
+ this._height = 300;
+
+ this._dx = 0;
+ this._dy = 0;
+ this._lastX = -1;
+ this._lastY = -1;
+ this._pressX = -1;
+ this._pressY = -1;
+ this._lastButton = 0;
+
+ this._points = 0; // old render mode flag (but think of better name!)
+ this._numRenderedNodes = 0;
+
+ this._pick = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._pickNorm = new x3dom.fields.SFVec3f(0, 0, 1);
+
+ this._isAnimating = false;
+ this._isMoving = false;
+ this._lastTS = 0;
+ this._mixer = new x3dom.MatrixMixer();
+
+ this.arc = null;
+};
+
+/**
+ * Method gets called every frame with the current timestamp
+ * @param {Number} timeStamp - current time stamp
+ * @return {Boolean} view area animation state
+ */
+x3dom.Viewarea.prototype.tick = function(timeStamp)
+{
+ var needMixAnim = false;
+ var env = this._scene.getEnvironment();
+
+ if (env._vf.enableARC && this.arc == null)
+ {
+ this.arc = new x3dom.arc.AdaptiveRenderControl(this._scene);
+ }
+
+ if (this._mixer._beginTime > 0)
+ {
+ needMixAnim = true;
+
+ if (timeStamp >= this._mixer._beginTime)
+ {
+ if (timeStamp <= this._mixer._endTime)
+ {
+ var mat = this._mixer.mix(timeStamp);
+
+ this._scene.getViewpoint().setView(mat);
+ }
+ else {
+ this._mixer._beginTime = 0;
+ this._mixer._endTime = 0;
+
+ this._scene.getViewpoint().setView(this._mixer._endMat);
+ }
+ }
+ else {
+ this._mixer._beginTime = 0;
+ this._mixer._endTime = 0;
+
+ this._scene.getViewpoint().setView(this._mixer._beginMat);
+ }
+ }
+
+ var needNavAnim = this.navigateTo(timeStamp);
+ var lastIsAnimating = this._isAnimating;
+
+ this._lastTS = timeStamp;
+ this._isAnimating = (needMixAnim || needNavAnim);
+
+ if (this.arc != null )
+ {
+ this.arc.update(this.isMovingOrAnimating() ? 1 : 0, this._doc._x3dElem.runtime.getFPS());
+ }
+
+ return (this._isAnimating || lastIsAnimating);
+};
+
+/**
+ * Returns moving state of view are
+ * @return {Boolean} moving state of view area
+ */
+x3dom.Viewarea.prototype.isMoving = function()
+{
+ return this._isMoving;
+};
+
+/**
+ * Returns animation state of view area
+ * @return {Boolean} animation state of view area
+ */
+x3dom.Viewarea.prototype.isAnimating = function()
+{
+ return this._isAnimating;
+};
+
+/**
+ * is view area moving or animating
+ * @return {Boolean} view area moving or animating state
+ */
+x3dom.Viewarea.prototype.isMovingOrAnimating = function()
+{
+ return (this._isMoving || this._isAnimating);
+};
+
+/**
+ * triggers view area to move to something by passing the timestamp
+ * returning a flag if the view area needs a navigation animation
+ * @return {Boolean} flag if the view area need a navigation state
+ */
+x3dom.Viewarea.prototype.navigateTo = function(timeStamp)
+{
+ var navi = this._scene.getNavigationInfo();
+ var navType = navi.getType();
+
+ var needNavAnim = (this._currentInputType == x3dom.InputTypes.NAVIGATION) &&
+ ( navType === "game" ||
+ (this._lastButton > 0 &&
+ (navType.indexOf("fly") >= 0 ||
+ navType === "walk" ||
+ navType === "helicopter" ||
+ navType.substr(0, 5) === "looka")) );
+
+ this._deltaT = timeStamp - this._lastTS;
+
+ var removeZeroMargin = function(val, offset) {
+ if (val > 0) {
+ if (val <= offset) {
+ return 0;
+ } else {
+ return val - offset;
+ }
+ } else if (val <= 0) {
+ if (val >= -offset) {
+ return 0;
+ } else {
+ return val + offset;
+ }
+ }
+ };
+
+ // slightly increasing slope function
+ var humanizeDiff = function(scale, diff) {
+ return ((diff < 0) ? -1 : 1 ) * Math.pow(scale * Math.abs(diff), 1.65 /*lower is easier on the novice*/);
+ };
+
+ if (needNavAnim)
+ {
+ var avatarRadius = 0.25;
+ var avatarHeight = 1.6;
+ var avatarKnee = 0.75; // TODO; check max. step size
+
+ if (navi._vf.avatarSize.length > 2) {
+ avatarRadius = navi._vf.avatarSize[0];
+ avatarHeight = navi._vf.avatarSize[1];
+ avatarKnee = navi._vf.avatarSize[2];
+ }
+
+
+
+ // get current view matrix
+ var currViewMat = this.getViewMatrix();
+ var dist = 0;
+
+ // estimate one screen size for motion puposes so navigation behaviour
+ // is less dependent on screen geometry. This makes no sense for very
+ // anisotropic cases, so it should probably be configurable.
+ var screenSize = Math.min(this._width, this._height);
+ var rdeltaX = removeZeroMargin((this._pressX - this._lastX) / screenSize, 0.01);
+ var rdeltaY = removeZeroMargin((this._pressY - this._lastY) / screenSize, 0.01);
+
+ var userXdiff = humanizeDiff(1, rdeltaX);
+ var userYdiff = humanizeDiff(1, rdeltaY);
+
+ // check if forwards or backwards (on right button)
+ var step = (this._lastButton & 2) ? -1 : 1;
+ step *= (this._deltaT * navi._vf.speed);
+
+ // factor in delta time and the nav speed setting
+ var userXstep = this._deltaT * navi._vf.speed * userXdiff;
+ var userYstep = this._deltaT * navi._vf.speed * userYdiff;
+
+ var phi = Math.PI * this._deltaT * userXdiff;
+ var theta = Math.PI * this._deltaT * userYdiff;
+
+ if (this._needNavigationMatrixUpdate === true)
+ {
+ this._needNavigationMatrixUpdate = false;
+
+ // reset examine matrices to identity
+ this._rotMat = x3dom.fields.SFMatrix4f.identity();
+ this._transMat = x3dom.fields.SFMatrix4f.identity();
+ this._movement = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ var angleX = 0;
+ var angleY = Math.asin(currViewMat._02);
+ var C = Math.cos(angleY);
+
+ if (Math.abs(C) > 0.0001) {
+ angleX = Math.atan2(-currViewMat._12 / C, currViewMat._22 / C);
+ }
+
+ // too many inversions here can lead to distortions
+ this._flyMat = currViewMat.inverse();
+
+ this._from = this._flyMat.e3();
+ this._at = this._from.subtract(this._flyMat.e2());
+
+ if (navType === "helicopter")
+ this._at.y = this._from.y;
+
+ //lookat, lookaround
+ if (navType.substr(0, 5) === "looka")
+ {
+ this._up = this._flyMat.e1();
+ }
+ //all other modes
+ else
+ {
+ //initially read up-vector from current orientation and keep it
+ if (typeof this._up == 'undefined')
+ {
+ this._up = this._flyMat.e1();
+ }
+ }
+
+ this._pitch = angleX * 180 / Math.PI;
+ this._yaw = angleY * 180 / Math.PI;
+ this._eyePos = this._from.negate();
+ }
+
+ var tmpAt = null, tmpUp = null, tmpMat = null;
+ var q, temp, fin;
+ var lv, sv, up;
+
+ if (navType === "game")
+ {
+ this._pitch += this._dy;
+ this._yaw += this._dx;
+
+ if (this._pitch >= 89) this._pitch = 89;
+ if (this._pitch <= -89) this._pitch = -89;
+ if (this._yaw >= 360) this._yaw -= 360;
+ if (this._yaw < 0) this._yaw = 360 + this._yaw;
+
+ this._dx = 0;
+ this._dy = 0;
+
+ var xMat = x3dom.fields.SFMatrix4f.rotationX(this._pitch / 180 * Math.PI);
+ var yMat = x3dom.fields.SFMatrix4f.rotationY(this._yaw / 180 * Math.PI);
+
+ var fPos = x3dom.fields.SFMatrix4f.translation(this._eyePos);
+
+ this._flyMat = xMat.mult(yMat).mult(fPos);
+
+ // Finally check floor for terrain following (TODO: optimize!)
+ var flyMat = this._flyMat.inverse();
+
+ var tmpFrom = flyMat.e3();
+ tmpUp = new x3dom.fields.SFVec3f(0, -1, 0);
+
+ tmpAt = tmpFrom.add(tmpUp);
+ tmpUp = flyMat.e0().cross(tmpUp).normalize();
+
+ tmpMat = x3dom.fields.SFMatrix4f.lookAt(tmpFrom, tmpAt, tmpUp);
+ tmpMat = tmpMat.inverse();
+
+ this._scene._nameSpace.doc.ctx.pickValue(this, this._width/2, this._height/2,
+ this._lastButton, tmpMat, this.getProjectionMatrix().mult(tmpMat));
+
+ if (this._pickingInfo.pickObj)
+ {
+ dist = this._pickingInfo.pickPos.subtract(tmpFrom).length();
+ //x3dom.debug.logWarning("Floor collision at dist=" + dist.toFixed(4));
+
+ tmpFrom.y += (avatarHeight - dist);
+ flyMat.setTranslate(tmpFrom);
+
+ this._eyePos = flyMat.e3().negate();
+ this._flyMat = flyMat.inverse();
+
+ this._pickingInfo.pickObj = null;
+ }
+
+ this._scene.getViewpoint().setView(this._flyMat);
+
+ return needNavAnim;
+ } // game
+ else if (navType === "helicopter") {
+ var typeParams = navi.getTypeParams();
+
+
+
+ if (this._lastButton & 2) // up/down levelling
+ {
+ var stepUp = 200 * userYstep;
+ typeParams[1] += stepUp;
+ navi.setTypeParams(typeParams);
+ }
+
+ if (this._lastButton & 1) { // forward/backward motion
+ step = 300 * userYstep;
+ }
+ else {
+ step = 0;
+ }
+
+ theta = typeParams[0];
+ this._from.y = typeParams[1];
+ this._at.y = this._from.y;
+
+ // rotate around the up vector
+ q = x3dom.fields.Quaternion.axisAngle(this._up, phi);
+ temp = q.toMatrix();
+
+ fin = x3dom.fields.SFMatrix4f.translation(this._from);
+ fin = fin.mult(temp);
+
+ temp = x3dom.fields.SFMatrix4f.translation(this._from.negate());
+ fin = fin.mult(temp);
+
+ this._at = fin.multMatrixPnt(this._at);
+
+ // rotate around the side vector
+ lv = this._at.subtract(this._from).normalize();
+ sv = lv.cross(this._up).normalize();
+ up = sv.cross(lv).normalize();
+
+ lv = lv.multiply(step);
+
+ this._from = this._from.add(lv);
+ this._at = this._at.add(lv);
+
+ // rotate around the side vector
+ q = x3dom.fields.Quaternion.axisAngle(sv, theta);
+ temp = q.toMatrix();
+
+ fin = x3dom.fields.SFMatrix4f.translation(this._from);
+ fin = fin.mult(temp);
+
+ temp = x3dom.fields.SFMatrix4f.translation(this._from.negate());
+ fin = fin.mult(temp);
+
+ var at = fin.multMatrixPnt(this._at);
+
+ this._flyMat = x3dom.fields.SFMatrix4f.lookAt(this._from, at, up);
+
+ this._scene.getViewpoint().setView(this._flyMat.inverse());
+
+ return needNavAnim;
+ } // helicopter
+
+ // rotate around the up vector
+ q = x3dom.fields.Quaternion.axisAngle(this._up, phi);
+ temp = q.toMatrix();
+
+ fin = x3dom.fields.SFMatrix4f.translation(this._from);
+ fin = fin.mult(temp);
+
+ temp = x3dom.fields.SFMatrix4f.translation(this._from.negate());
+ fin = fin.mult(temp);
+
+ this._at = fin.multMatrixPnt(this._at);
+
+ // rotate around the side vector
+ lv = this._at.subtract(this._from).normalize();
+ sv = lv.cross(this._up).normalize();
+ up = sv.cross(lv).normalize();
+ //this._up = up;
+
+ q = x3dom.fields.Quaternion.axisAngle(sv, theta);
+ temp = q.toMatrix();
+
+ fin = x3dom.fields.SFMatrix4f.translation(this._from);
+ fin = fin.mult(temp);
+
+ temp = x3dom.fields.SFMatrix4f.translation(this._from.negate());
+ fin = fin.mult(temp);
+
+ this._at = fin.multMatrixPnt(this._at);
+
+ // forward along view vector
+ if (navType.substr(0, 5) !== "looka")
+ {
+ var currProjMat = this.getProjectionMatrix();
+
+ if (navType !== "freefly") {
+ if (step < 0) {
+ // backwards: negate viewing direction
+ tmpMat = new x3dom.fields.SFMatrix4f();
+ tmpMat.setValue(this._last_mat_view.e0(), this._last_mat_view.e1(),
+ this._last_mat_view.e2().negate(), this._last_mat_view.e3());
+
+ this._scene._nameSpace.doc.ctx.pickValue(this, this._width/2, this._height/2,
+ this._lastButton, tmpMat, currProjMat.mult(tmpMat));
+ }
+ else {
+ this._scene._nameSpace.doc.ctx.pickValue(this, this._width/2, this._height/2, this._lastButton);
+ }
+ if (this._pickingInfo.pickObj)
+ {
+ dist = this._pickingInfo.pickPos.subtract(this._from).length();
+
+ if (dist <= avatarRadius) {
+ step = 0;
+ }
+ }
+ }
+
+ lv = this._at.subtract(this._from).normalize().multiply(step);
+
+ this._at = this._at.add(lv);
+ this._from = this._from.add(lv);
+
+ // finally attach to ground when walking
+ if (navType === "walk")
+ {
+ tmpAt = this._from.addScaled(up, -1.0);
+ tmpUp = sv.cross(up.negate()).normalize(); // lv
+
+ tmpMat = x3dom.fields.SFMatrix4f.lookAt(this._from, tmpAt, tmpUp);
+ tmpMat = tmpMat.inverse();
+
+ this._scene._nameSpace.doc.ctx.pickValue(this, this._width/2, this._height/2,
+ this._lastButton, tmpMat, currProjMat.mult(tmpMat));
+
+ if (this._pickingInfo.pickObj)
+ {
+ dist = this._pickingInfo.pickPos.subtract(this._from).length();
+
+ this._at = this._at.add(up.multiply(avatarHeight - dist));
+ this._from = this._from.add(up.multiply(avatarHeight - dist));
+ }
+ }
+ this._pickingInfo.pickObj = null;
+ }
+
+ this._flyMat = x3dom.fields.SFMatrix4f.lookAt(this._from, this._at, up);
+
+ this._scene.getViewpoint().setView(this._flyMat.inverse());
+ }
+
+ return needNavAnim;
+};
+
+x3dom.Viewarea.prototype.moveFwd = function()
+{
+ var navi = this._scene.getNavigationInfo();
+
+ if (navi.getType() === "game")
+ {
+ var avatarRadius = 0.25;
+ var avatarHeight = 1.6;
+
+ if (navi._vf.avatarSize.length > 2) {
+ avatarRadius = navi._vf.avatarSize[0];
+ avatarHeight = navi._vf.avatarSize[1];
+ }
+
+ var speed = 5 * this._deltaT * navi._vf.speed;
+ var yRotRad = (this._yaw / 180 * Math.PI);
+ var xRotRad = (this._pitch / 180 * Math.PI);
+
+ var dist = 0;
+ var fMat = this._flyMat.inverse();
+
+ // check front for collisions
+ this._scene._nameSpace.doc.ctx.pickValue(this, this._width/2, this._height/2, this._lastButton);
+
+ if (this._pickingInfo.pickObj)
+ {
+ dist = this._pickingInfo.pickPos.subtract(fMat.e3()).length();
+
+ if (dist <= 2 * avatarRadius) {
+ //x3dom.debug.logWarning("Collision at dist=" + dist.toFixed(4));
+ }
+ else {
+ this._eyePos.x -= Math.sin(yRotRad) * speed;
+ this._eyePos.z += Math.cos(yRotRad) * speed;
+ this._eyePos.y += Math.sin(xRotRad) * speed;
+ }
+ }
+ }
+};
+
+x3dom.Viewarea.prototype.moveBwd = function()
+{
+ var navi = this._scene.getNavigationInfo();
+
+ if (navi.getType() === "game")
+ {
+ var speed = 5 * this._deltaT * navi._vf.speed;
+ var yRotRad = (this._yaw / 180 * Math.PI);
+ var xRotRad = (this._pitch / 180 * Math.PI);
+
+ this._eyePos.x += Math.sin(yRotRad) * speed;
+ this._eyePos.z -= Math.cos(yRotRad) * speed;
+ this._eyePos.y -= Math.sin(xRotRad) * speed;
+ }
+};
+
+x3dom.Viewarea.prototype.strafeRight = function()
+{
+ var navi = this._scene.getNavigationInfo();
+
+ if (navi.getType() === "game")
+ {
+ var speed = 5 * this._deltaT * navi._vf.speed;
+ var yRotRad = (this._yaw / 180 * Math.PI);
+
+ this._eyePos.x -= Math.cos(yRotRad) * speed;
+ this._eyePos.z -= Math.sin(yRotRad) * speed;
+ }
+};
+
+x3dom.Viewarea.prototype.strafeLeft = function()
+{
+ var navi = this._scene.getNavigationInfo();
+
+ if (navi.getType() === "game")
+ {
+ var speed = 5 * this._deltaT * navi._vf.speed;
+ var yRotRad = (this._yaw / 180 * Math.PI);
+
+ this._eyePos.x += Math.cos(yRotRad) * speed;
+ this._eyePos.z += Math.sin(yRotRad) * speed;
+ }
+};
+
+x3dom.Viewarea.prototype.animateTo = function(target, prev, dur)
+{
+ var navi = this._scene.getNavigationInfo();
+
+ if (x3dom.isa(target, x3dom.nodeTypes.X3DViewpointNode)) {
+ target = target.getViewMatrix().mult(target.getCurrentTransform().inverse());
+ }
+
+ if (navi._vf.transitionType[0].toLowerCase() !== "teleport" && navi.getType() !== "game")
+ {
+ if (prev && x3dom.isa(prev, x3dom.nodeTypes.X3DViewpointNode)) {
+ prev = prev.getViewMatrix().mult(prev.getCurrentTransform().inverse()).
+ mult(this._transMat).mult(this._rotMat);
+
+ this._mixer._beginTime = this._lastTS;
+
+ if (arguments.length >= 3) {
+ // for lookAt to assure travel speed of 1 m/s
+ this._mixer._endTime = this._lastTS + dur;
+ }
+ else {
+ this._mixer._endTime = this._lastTS + navi._vf.transitionTime;
+ }
+
+ this._mixer.setBeginMatrix (prev);
+ this._mixer.setEndMatrix (target);
+
+ this._scene.getViewpoint().setView(prev);
+ }
+ else {
+ this._scene.getViewpoint().setView(target);
+ }
+ }
+ else
+ {
+ this._scene.getViewpoint().setView(target);
+ }
+
+ this._rotMat = x3dom.fields.SFMatrix4f.identity();
+ this._transMat = x3dom.fields.SFMatrix4f.identity();
+ this._movement = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._needNavigationMatrixUpdate = true;
+};
+
+x3dom.Viewarea.prototype.getLights = function () {
+ var enabledLights = [];
+ for (var i=0; i<this._doc._nodeBag.lights.length; i++)
+ {
+ if (this._doc._nodeBag.lights[i]._vf.on == true)
+ {
+ enabledLights.push(this._doc._nodeBag.lights[i]);
+ }
+ }
+ return enabledLights;
+};
+
+x3dom.Viewarea.prototype.getLightsShadow = function () {
+ var lights = this._doc._nodeBag.lights;
+ for(var l=0; l<lights.length; l++) {
+ if(lights[l]._vf.shadowIntensity > 0.0){
+ return true;
+ }
+ }
+ return false;
+};
+
+x3dom.Viewarea.prototype.updateSpecialNavigation = function (viewpoint, mat_viewpoint) {
+ var navi = this._scene.getNavigationInfo();
+ var navType = navi.getType();
+
+ // helicopter mode needs to manipulate view matrix specially
+ if (navType == "helicopter" && !navi._heliUpdated)
+ {
+ var typeParams = navi.getTypeParams();
+ var theta = typeParams[0];
+ var currViewMat = viewpoint.getViewMatrix().mult(mat_viewpoint.inverse()).inverse();
+
+ this._from = currViewMat.e3();
+ this._at = this._from.subtract(currViewMat.e2());
+ this._up = new x3dom.fields.SFVec3f(0, 1, 0);
+
+ this._from.y = typeParams[1];
+ this._at.y = this._from.y;
+
+ var sv = currViewMat.e0();
+ var q = x3dom.fields.Quaternion.axisAngle(sv, theta);
+ var temp = q.toMatrix();
+
+ var fin = x3dom.fields.SFMatrix4f.translation(this._from);
+ fin = fin.mult(temp);
+
+ temp = x3dom.fields.SFMatrix4f.translation(this._from.negate());
+ fin = fin.mult(temp);
+
+ this._at = fin.multMatrixPnt(this._at);
+
+ this._flyMat = x3dom.fields.SFMatrix4f.lookAt(this._from, this._at, this._up);
+ this._scene.getViewpoint().setView(this._flyMat.inverse());
+
+ navi._heliUpdated = true;
+ }
+};
+
+/**
+ * Get the view areas view point matrix
+ * @return {x3dom.fields.SFMatrix4f} view areas view point matrix
+ */
+x3dom.Viewarea.prototype.getViewpointMatrix = function ()
+{
+ var viewpoint = this._scene.getViewpoint();
+ var mat_viewpoint = viewpoint.getCurrentTransform();
+
+ this.updateSpecialNavigation(viewpoint, mat_viewpoint);
+
+ return viewpoint.getViewMatrix().mult(mat_viewpoint.inverse());
+};
+
+/**
+ * Get the view areas view matrix
+ * @return {x3dom.fields.SFMatrix4f} view areas view matrix
+ */
+x3dom.Viewarea.prototype.getViewMatrix = function ()
+{
+ return this.getViewpointMatrix().mult(this._transMat).mult(this._rotMat);
+};
+
+x3dom.Viewarea.prototype.getLightMatrix = function ()
+{
+ var lights = this._doc._nodeBag.lights;
+ var i, n = lights.length;
+
+ if (n > 0)
+ {
+ var vol = this._scene.getVolume();
+
+ if (vol.isValid())
+ {
+ var min = x3dom.fields.SFVec3f.MAX();
+ var max = x3dom.fields.SFVec3f.MIN();
+ vol.getBounds(min, max);
+
+ var l_arr = [];
+ var viewpoint = this._scene.getViewpoint();
+ var fov = viewpoint.getFieldOfView();
+
+ var dia = max.subtract(min);
+ var dist1 = (dia.y/2.0) / Math.tan(fov/2.0) + (dia.z/2.0);
+ var dist2 = (dia.x/2.0) / Math.tan(fov/2.0) + (dia.z/2.0);
+
+ dia = min.add(dia.multiply(0.5));
+
+ for (i=0; i<n; i++)
+ {
+ if (x3dom.isa(lights[i], x3dom.nodeTypes.PointLight)) {
+ var wcLoc = lights[i].getCurrentTransform().multMatrixPnt(lights[i]._vf.location);
+ dia = dia.subtract(wcLoc).normalize();
+ }
+ else {
+ var dir = lights[i].getCurrentTransform().multMatrixVec(lights[i]._vf.direction);
+ dir = dir.normalize().negate();
+ dia = dia.add(dir.multiply(1.2 * (dist1 > dist2 ? dist1 : dist2)));
+ }
+
+ l_arr[i] = lights[i].getViewMatrix(dia);
+ }
+
+ return l_arr;
+ }
+ }
+
+ //TODO, this is only for testing
+ return [ this.getViewMatrix() ];
+};
+
+x3dom.Viewarea.prototype.getWCtoLCMatrix = function(lMat)
+{
+ var proj = this.getProjectionMatrix();
+ var view;
+
+ if (arguments.length === 0) {
+ view = this.getLightMatrix()[0];
+ }
+ else {
+ view = lMat;
+ }
+
+ return proj.mult(view);
+};
+
+/**
+ * Get six WCtoLCMatrices for point light
+ * @param {x3dom.fields.SFMatrix4f} view - the view matrix
+ * @param {x3dom.nodeTypes.X3DNode} lightNode - the light node
+ * @param {x3dom.fields.SFMatrix4f} mat_proj - the projection matrix
+ * @return {Array} six WCtoLCMatrices
+ */
+x3dom.Viewarea.prototype.getWCtoLCMatricesPointLight = function(view, lightNode, mat_proj)
+{
+ var zNear = lightNode._vf.zNear;
+ var zFar = lightNode._vf.zFar;
+
+ var proj = this.getLightProjectionMatrix(view, zNear, zFar, false, mat_proj);
+
+ //set projection matrix to 90 degrees FOV (vertical and horizontal)
+ proj._00 = 1;
+ proj._11 = 1;
+
+ var matrices = [];
+
+ //create six matrices to cover all directions of point light
+ matrices[0] = proj.mult(view);
+
+ var rotationMatrix;
+
+ //y-rotation
+ for (var i=1; i<=3; i++){
+ rotationMatrix = x3dom.fields.SFMatrix4f.rotationY(i*Math.PI/2);
+ matrices[i] = proj.mult(rotationMatrix.mult(view));
+ }
+
+ //x-rotation
+ rotationMatrix = x3dom.fields.SFMatrix4f.rotationX(Math.PI/2);
+ matrices[4] = proj.mult(rotationMatrix.mult(view));
+
+ rotationMatrix = x3dom.fields.SFMatrix4f.rotationX(3*Math.PI/2);
+ matrices[5] = proj.mult(rotationMatrix.mult(view));
+
+ return matrices;
+};
+
+/*
+ * Get WCToLCMatrices for cascaded light
+ */
+x3dom.Viewarea.prototype.getWCtoLCMatricesCascaded = function(view, lightNode, mat_proj)
+{
+ var numCascades = Math.max(1, Math.min(lightNode._vf.shadowCascades, 6));
+ var splitFactor = Math.max(0, Math.min(lightNode._vf.shadowSplitFactor, 1));
+ var splitOffset = Math.max(0, Math.min(lightNode._vf.shadowSplitOffset, 1));
+
+ var isSpotLight = x3dom.isa(lightNode, x3dom.nodeTypes.SpotLight);
+ var zNear = lightNode._vf.zNear;
+ var zFar = lightNode._vf.zFar;
+
+ var proj = this.getLightProjectionMatrix(view, zNear, zFar, true, mat_proj);
+
+ if (isSpotLight){
+ //set FOV to 90 degrees
+ proj._00 = 1;
+ proj._11 = 1;
+ }
+
+ //get view projection matrix
+ var viewProj = proj.mult(view);
+
+ var matrices = [];
+
+ if (numCascades == 1){
+ //return if only one cascade
+ matrices[0] = viewProj;
+ return matrices;
+ }
+
+ //compute split positions of view frustum
+ var cascadeSplits = this.getShadowSplitDepths(numCascades, splitFactor, splitOffset, true, mat_proj);
+
+ //calculate fitting matrices and multiply with view projection
+ for (var i=0; i<numCascades; i++){
+ var fittingMat = this.getLightFittingMatrix(viewProj, cascadeSplits[i], cascadeSplits[i+1], mat_proj);
+ matrices[i] = fittingMat.mult(viewProj);
+ }
+
+ return matrices;
+};
+
+x3dom.Viewarea.prototype.getLightProjectionMatrix = function(lMat, zNear, zFar, highPrecision, mat_proj)
+{
+ var proj = x3dom.fields.SFMatrix4f.copy(mat_proj);
+
+ if (!highPrecision || zNear > 0 || zFar > 0) {
+ //replace near and far plane of projection matrix
+ //by values adapted to the light position
+
+ var lightPos = lMat.inverse().e3();
+
+ var nearScale = 0.8;
+ var farScale = 1.2;
+
+ var min = x3dom.fields.SFVec3f.copy(this._scene._lastMin);
+ var max = x3dom.fields.SFVec3f.copy(this._scene._lastMax);
+
+ var dia = max.subtract(min);
+ var sRad = dia.length() / 2;
+
+ var sCenter = min.add(dia.multiply(0.5));
+ var vDist = (lightPos.subtract(sCenter)).length();
+
+ var near, far;
+
+ if (sRad) {
+ if (vDist > sRad)
+ near = (vDist - sRad) * nearScale;
+ else
+ near = 1;
+ far = (vDist + sRad) * farScale;
+ }
+ if (zNear > 0) near = zNear;
+ if (zFar > 0) far = zFar;
+
+ proj._22 = -(far+near)/(far-near);
+ proj._23 = -2.0*far*near / (far-near);
+
+ return proj;
+ }
+ else {
+ //should be more accurate, but also more expensive
+ var cropMatrix = this.getLightCropMatrix(proj.mult(lMat));
+
+ return cropMatrix.mult(proj);
+ }
+};
+
+x3dom.Viewarea.prototype.getProjectionMatrix = function()
+{
+ var viewpoint = this._scene.getViewpoint();
+
+ return viewpoint.getProjectionMatrix(this._width/this._height);
+};
+
+/**
+ * Get the view frustum for a given clipping matrix
+ * @param {x3dom.fields.SFMatrix4f} clipMat - the clipping matrix
+ * @return {x3dom.fields.FrustumVolume} the resulting view frustum
+ */
+x3dom.Viewarea.prototype.getViewfrustum = function(clipMat)
+{
+ var env = this._scene.getEnvironment();
+
+ if (env._vf.frustumCulling == true)
+ {
+ if (arguments.length == 0) {
+ var proj = this.getProjectionMatrix();
+ var view = this.getViewMatrix();
+
+ return new x3dom.fields.FrustumVolume(proj.mult(view));
+ }
+ else {
+ return new x3dom.fields.FrustumVolume(clipMat);
+ }
+ }
+
+ return null;
+};
+
+/**
+ * Get the world coordinates to clipping coordinates matrix by multiplying the projection and view matrices
+ * @return {x3dom.fields.SFMatrix4f} world coordinates to clipping coordinates matrix
+ */
+x3dom.Viewarea.prototype.getWCtoCCMatrix = function()
+{
+ var view = this.getViewMatrix();
+ var proj = this.getProjectionMatrix();
+
+ return proj.mult(view);
+};
+
+/**
+ * Get the clipping coordinates to world coordinates matrix by multiplying the projection and view matrices
+ * @return {x3dom.fields.SFMatrix4f} clipping coordinates to world coordinates matrix
+ */
+x3dom.Viewarea.prototype.getCCtoWCMatrix = function()
+{
+ var mat = this.getWCtoCCMatrix();
+
+ return mat.inverse();
+};
+
+x3dom.Viewarea.prototype.calcViewRay = function(x, y, mat)
+{
+ var cctowc = mat ? mat : this.getCCtoWCMatrix();
+
+ var rx = x / (this._width - 1.0) * 2.0 - 1.0;
+ var ry = (this._height - 1.0 - y) / (this._height - 1.0) * 2.0 - 1.0;
+
+ var from = cctowc.multFullMatrixPnt(new x3dom.fields.SFVec3f(rx, ry, -1));
+ var at = cctowc.multFullMatrixPnt(new x3dom.fields.SFVec3f(rx, ry, 1));
+ var dir = at.subtract(from);
+
+ return new x3dom.fields.Ray(from, dir);
+};
+
+x3dom.Viewarea.prototype.showAll = function(axis)
+{
+ if (axis === undefined)
+ axis = "negZ";
+
+ var scene = this._scene;
+ scene.updateVolume();
+
+ var min = x3dom.fields.SFVec3f.copy(scene._lastMin);
+ var max = x3dom.fields.SFVec3f.copy(scene._lastMax);
+
+ var x = "x", y = "y", z = "z";
+ var sign = 1;
+ var to, from = new x3dom.fields.SFVec3f(0, 0, -1);
+
+ switch (axis) {
+ case "posX":
+ sign = -1;
+ case "negX":
+ z = "x"; x = "y"; y = "z";
+ to = new x3dom.fields.SFVec3f(sign, 0, 0);
+ break;
+ case "posY":
+ sign = -1;
+ case "negY":
+ z = "y"; x = "z"; y = "x";
+ to = new x3dom.fields.SFVec3f(0, sign, 0);
+ break;
+ case "posZ":
+ sign = -1;
+ case "negZ":
+ default:
+ to = new x3dom.fields.SFVec3f(0, 0, -sign);
+ break;
+ }
+
+ var viewpoint = scene.getViewpoint();
+ var fov = viewpoint.getFieldOfView();
+
+ var dia = max.subtract(min);
+
+ var diaz2 = dia[z] / 2.0, tanfov2 = Math.tan(fov / 2.0);
+
+ var dist1 = (dia[y] / 2.0) / tanfov2 + diaz2;
+ var dist2 = (dia[x] / 2.0) / tanfov2 + diaz2;
+
+ dia = min.add(dia.multiply(0.5));
+
+ dia[z] += sign * (dist1 > dist2 ? dist1 : dist2) * 1.01;
+
+ var quat = x3dom.fields.Quaternion.rotateFromTo(from, to);
+
+ var viewmat = quat.toMatrix();
+ viewmat = viewmat.mult(x3dom.fields.SFMatrix4f.translation(dia.negate()));
+
+ this.animateTo(viewmat, viewpoint);
+};
+
+x3dom.Viewarea.prototype.fit = function(min, max, updateCenterOfRotation)
+{
+ if (updateCenterOfRotation === undefined) {
+ updateCenterOfRotation = true;
+ }
+
+ var dia2 = max.subtract(min).multiply(0.5); // half diameter
+ var center = min.add(dia2); // center in wc
+ var bsr = dia2.length(); // bounding sphere radius
+
+ var viewpoint = this._scene.getViewpoint();
+ var fov = viewpoint.getFieldOfView();
+
+ var viewmat = x3dom.fields.SFMatrix4f.copy(this.getViewMatrix());
+
+ var rightDir = new x3dom.fields.SFVec3f(viewmat._00, viewmat._01, viewmat._02);
+ var upDir = new x3dom.fields.SFVec3f(viewmat._10, viewmat._11, viewmat._12);
+ var viewDir = new x3dom.fields.SFVec3f(viewmat._20, viewmat._21, viewmat._22);
+
+ var tanfov2 = Math.tan(fov / 2.0);
+ var dist = bsr / tanfov2;
+
+ var eyePos = center.add(viewDir.multiply(dist));
+
+ viewmat._03 = -rightDir.dot(eyePos);
+ viewmat._13 = -upDir.dot(eyePos);
+ viewmat._23 = -viewDir.dot(eyePos);
+
+ if (updateCenterOfRotation) {
+ viewpoint.setCenterOfRotation(center);
+ }
+
+ if (x3dom.isa(viewpoint, x3dom.nodeTypes.OrthoViewpoint))
+ {
+ viewpoint._vf.fieldOfView[0] = -dist;
+ viewpoint._vf.fieldOfView[1] = -dist;
+ viewpoint._vf.fieldOfView[2] = dist;
+ viewpoint._vf.fieldOfView[3] = dist;
+ viewpoint._projMatrix = null;
+ this.animateTo(viewmat, viewpoint, 0);
+ }
+ else
+ {
+ this.animateTo(viewmat, viewpoint);
+ }
+};
+
+x3dom.Viewarea.prototype.resetView = function()
+{
+ var navi = this._scene.getNavigationInfo();
+
+ if (navi._vf.transitionType[0].toLowerCase() !== "teleport" && navi.getType() !== "game")
+ {
+ this._mixer._beginTime = this._lastTS;
+ this._mixer._endTime = this._lastTS + navi._vf.transitionTime;
+
+ this._mixer.setBeginMatrix(this.getViewMatrix());
+
+ var target = this._scene.getViewpoint();
+ target.resetView();
+
+ target = target.getViewMatrix().mult(target.getCurrentTransform().inverse());
+
+ this._mixer.setEndMatrix(target);
+ }
+ else
+ {
+ this._scene.getViewpoint().resetView();
+ }
+
+ this.resetNavHelpers();
+ navi._heliUpdated = false;
+};
+
+x3dom.Viewarea.prototype.resetNavHelpers = function()
+{
+ this._rotMat = x3dom.fields.SFMatrix4f.identity();
+ this._transMat = x3dom.fields.SFMatrix4f.identity();
+ this._movement = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._needNavigationMatrixUpdate = true;
+};
+
+x3dom.Viewarea.prototype.uprightView = function()
+{
+ var mat = this.getViewMatrix().inverse();
+
+ var from = mat.e3();
+ var at = from.subtract(mat.e2());
+ var up = new x3dom.fields.SFVec3f(0, 1, 0);
+
+ var s = mat.e2().cross(up).normalize();
+ var v = s.cross(up).normalize();
+ at = from.add(v);
+
+ mat = x3dom.fields.SFMatrix4f.lookAt(from, at, up);
+ mat = mat.inverse();
+
+ this.animateTo(mat, this._scene.getViewpoint());
+};
+
+x3dom.Viewarea.prototype.callEvtHandler = function (node, eventType, event)
+{
+ if (!node || !node._xmlNode)
+ return null;
+
+ try {
+ var attrib = node._xmlNode[eventType];
+
+ if (typeof(attrib) === "function") {
+ attrib.call(node._xmlNode, event);
+ }
+ else {
+ var funcStr = node._xmlNode.getAttribute(eventType);
+ var func = new Function('event', funcStr);
+ func.call(node._xmlNode, event);
+ }
+
+ var list = node._listeners[event.type];
+ if (list) {
+ for (var it=0; it<list.length; it++) {
+ list[it].call(node._xmlNode, event);
+ }
+ }
+ }
+ catch(e) {
+ x3dom.debug.logException(e);
+ }
+
+ return event.cancelBubble;
+};
+
+x3dom.Viewarea.prototype.checkEvents = function (obj, x, y, buttonState, eventType)
+{
+ var that = this;
+ var needRecurse = true;
+ var childNode;
+ var i, n;
+ var target = (obj && obj._xmlNode) ? obj._xmlNode : {};
+
+
+ var affectedPointingSensorsList = this._doc._nodeBag.affectedPointingSensors;
+
+
+ var event = {
+ viewarea: that,
+ target: target,
+ type: eventType.substr(2, eventType.length-2),
+ button: buttonState,
+ layerX: x,
+ layerY: y,
+ worldX: that._pick.x,
+ worldY: that._pick.y,
+ worldZ: that._pick.z,
+ normalX: that._pickNorm.x,
+ normalY: that._pickNorm.y,
+ normalZ: that._pickNorm.z,
+ hitPnt: that._pick.toGL(), // for convenience
+ hitObject: target, // deprecated, remove!
+ shadowObjectId: that._pickingInfo.shadowObjectId,
+ cancelBubble: false,
+ stopPropagation: function() { this.cancelBubble = true; },
+ preventDefault: function() { this.cancelBubble = true; }
+ };
+
+ try {
+ var anObj = obj;
+
+ if ( anObj && anObj._xmlNode && anObj._cf.geometry &&
+ !anObj._xmlNode[eventType] &&
+ !anObj._xmlNode.hasAttribute(eventType) &&
+ !anObj._listeners[event.type]) {
+ anObj = anObj._cf.geometry.node;
+ }
+
+ if (anObj && that.callEvtHandler(anObj, eventType, event) === true) {
+ needRecurse = false;
+ }
+ }
+ catch(e) {
+ x3dom.debug.logException(e);
+ }
+
+ var recurse = function(obj) {
+ Array.forEach(obj._parentNodes, function (node) {
+ if ( node._xmlNode && (node._xmlNode[eventType] ||
+ node._xmlNode.hasAttribute(eventType) ||
+ node._listeners[event.type]) )
+ {
+ if (that.callEvtHandler(node, eventType, event) === true) {
+ needRecurse = false;
+ }
+ }
+
+ //find the lowest pointing device sensors in the hierarchy that might be affected
+ //(note that, for X3DTouchSensors, 'affected' does not necessarily mean 'activated')
+ if (buttonState == 0 && affectedPointingSensorsList.length == 0 &&
+ (eventType == 'onmousemove' || eventType == 'onmouseover' || eventType == 'onmouseout') )
+ {
+ n = node._childNodes.length;
+
+ for (i = 0; i < n; ++i)
+ {
+ childNode = node._childNodes[i];
+
+ if (x3dom.isa(childNode, x3dom.nodeTypes.X3DPointingDeviceSensorNode) && childNode._vf.enabled)
+ {
+ affectedPointingSensorsList.push(childNode);
+ }
+ }
+ }
+
+ if (x3dom.isa(node, x3dom.nodeTypes.Anchor) && eventType === 'onclick') {
+ node.handleTouch();
+ needRecurse = false;
+ }
+ else if (needRecurse) {
+ recurse(node);
+ }
+ });
+ };
+
+ if (needRecurse && obj) {
+ recurse(obj);
+ }
+
+ return needRecurse;
+};
+
+
+/**
+ * Notifies all pointing device sensors that are currently affected by mouse events, if any, about the given event
+ * @param {DOMEvent} event - a mouse event, enriched by X3DOM-specific members
+ */
+x3dom.Viewarea.prototype._notifyAffectedPointingSensors = function(event)
+{
+ var funcDict = {
+ "mousedown" : "pointerPressedOverSibling",
+ "mousemove" : "pointerMoved",
+ "mouseover" : "pointerMovedOver",
+ "mouseout" : "pointerMovedOut"
+ };
+
+ var func = funcDict[event.type];
+ var affectedPointingSensorsList = this._doc._nodeBag.affectedPointingSensors;
+ var i, n = affectedPointingSensorsList.length;
+
+ if (n > 0 && func !== undefined)
+ {
+ for (i = 0; i < n; i++)
+ affectedPointingSensorsList[i][func](event);
+ }
+};
+
+
+x3dom.Viewarea.prototype.initMouseState = function()
+{
+ this._deltaT = 0;
+ this._dx = 0;
+ this._dy = 0;
+ this._lastX = -1;
+ this._lastY = -1;
+ this._pressX = -1;
+ this._pressY = -1;
+ this._lastButton = 0;
+ this._isMoving = false;
+ this._needNavigationMatrixUpdate = true;
+};
+
+x3dom.Viewarea.prototype.initTurnTable = function(navi, flyTo)
+{
+ flyTo = (flyTo == undefined) ? true : flyTo;
+
+ var currViewMat = this.getViewMatrix();
+
+ var viewpoint = this._scene.getViewpoint();
+ var center = x3dom.fields.SFVec3f.copy(viewpoint.getCenterOfRotation());
+
+ this._flyMat = currViewMat.inverse();
+
+ this._from = this._flyMat.e3();
+ //this._at = this._from.subtract(this._flyMat.e2());
+ this._at = center;
+ this._up = this._flyMat.e1();
+
+ this._flyMat = x3dom.fields.SFMatrix4f.lookAt(this._from, this._at, this._up);
+ this._flyMat = this.calcOrbit(0, 0, navi);
+
+ var dur = 0.0;
+
+ if (flyTo) {
+ dur = 0.2 / navi._vf.speed; // fly to pivot point
+ }
+
+ this.animateTo(this._flyMat.inverse(), viewpoint, dur);
+
+ this.resetNavHelpers();
+};
+
+x3dom.Viewarea.prototype.onMousePress = function (x, y, buttonState)
+{
+ this._needNavigationMatrixUpdate = true;
+
+ this.prepareEvents(x, y, buttonState, "onmousedown");
+ this._pickingInfo.lastClickObj = this._pickingInfo.pickObj;
+ this._pickingInfo.firstObj = this._pickingInfo.pickObj;
+
+ this._dx = 0;
+ this._dy = 0;
+ this._lastX = x;
+ this._lastY = y;
+ this._pressX = x;
+ this._pressY = y;
+ this._lastButton = buttonState;
+ this._isMoving = false;
+
+ if (this._currentInputType == x3dom.InputTypes.NAVIGATION)
+ {
+ var navi = this._scene.getNavigationInfo();
+
+ if (navi.getType() === "turntable") {
+ this.initTurnTable(navi, false);
+ }
+ }
+};
+
+x3dom.Viewarea.prototype.onMouseRelease = function (x, y, buttonState, prevButton)
+{
+ var i;
+ //if the mouse is released, reset the list of currently affected pointing sensors
+ var affectedPointingSensorsList = this._doc._nodeBag.affectedPointingSensors;
+ for (i = 0; i < affectedPointingSensorsList.length; ++i)
+ {
+ affectedPointingSensorsList[i].pointerReleased();
+ }
+ this._doc._nodeBag.affectedPointingSensors = [];
+
+ var tDist = 3.0; // distance modifier for lookat, could be param
+ var dir;
+ var navi = this._scene.getNavigationInfo();
+ var navType = navi.getType();
+
+ if (this._scene._vf.pickMode.toLowerCase() !== "box") {
+ this.prepareEvents(x, y, prevButton, "onmouseup");
+
+ // click means that mousedown _and_ mouseup were detected on same element
+ if (this._pickingInfo.pickObj &&
+ this._pickingInfo.pickObj === this._pickingInfo.lastClickObj)
+ {
+ this.prepareEvents(x, y, prevButton, "onclick");
+ }
+ else if (!this._pickingInfo.pickObj && !this._pickingInfo.lastClickObj &&
+ !this._pickingInfo.firstObj) // press and release outside object
+ {
+ var eventType = "backgroundClicked";
+ try {
+ if ( this._scene._xmlNode &&
+ (this._scene._xmlNode["on" + eventType] ||
+ this._scene._xmlNode.hasAttribute("on" + eventType) ||
+ this._scene._listeners[eventType]) ) {
+ var event = {
+ target: this._scene._xmlNode, type: eventType,
+ button: prevButton, layerX: x, layerY: y,
+ cancelBubble: false,
+ stopPropagation: function () { this.cancelBubble = true; },
+ preventDefault: function () { this.cancelBubble = true; }
+ };
+ this._scene.callEvtHandler(("on" + eventType), event);
+ }
+ }
+ catch (e) { x3dom.debug.logException("backgroundClicked: " + e); }
+ }
+ }
+ else {
+ var t0 = new Date().getTime();
+ var line = this.calcViewRay(x, y);
+ var isect = this._scene.doIntersect(line);
+ var obj = line.hitObject;
+
+ if (isect && obj)
+ {
+ this._pick.setValues(line.hitPoint);
+
+ this.checkEvents(obj, x, y, buttonState, "onclick");
+
+ x3dom.debug.logInfo("Hit '" + obj._xmlNode.localName + "/ " +
+ obj._DEF + "' at dist=" + line.dist.toFixed(4));
+ x3dom.debug.logInfo("Ray hit at position " + this._pick);
+ }
+
+ var t1 = new Date().getTime() - t0;
+ x3dom.debug.logInfo("Picking time (box): " + t1 + "ms");
+
+ if (!isect) {
+ dir = this.getViewMatrix().e2().negate();
+ var u = dir.dot(line.pos.negate()) / dir.dot(line.dir);
+ this._pick = line.pos.add(line.dir.multiply(u));
+ //x3dom.debug.logInfo("No hit at position " + this._pick);
+ }
+ }
+ this._pickingInfo.firstObj = null;
+
+ if (this._currentInputType == x3dom.InputTypes.NAVIGATION &&
+ (this._pickingInfo.pickObj || this._pickingInfo.shadowObjectId >= 0) &&
+ navType === "lookat" && this._pressX === x && this._pressY === y)
+ {
+ var step = (this._lastButton & 2) ? -1 : 1;
+ var dist = this._pickingInfo.pickPos.subtract(this._from).length() / tDist;
+
+ var laMat = new x3dom.fields.SFMatrix4f();
+ laMat.setValues(this.getViewMatrix());
+ laMat = laMat.inverse();
+
+ var from = laMat.e3();
+ var at = from.subtract(laMat.e2());
+ var up = laMat.e1();
+
+ dir = this._pickingInfo.pickPos.subtract(from);
+ var len = dir.length();
+ dir = dir.normalize();
+
+ //var newUp = new x3dom.fields.SFVec3f(0, 1, 0);
+ var newAt = from.addScaled(dir, len);
+
+ var s = dir.cross(up).normalize();
+ dir = s.cross(up).normalize();
+
+ if (step < 0) {
+ dist = (0.5 + len + dist) * 2;
+ }
+ var newFrom = newAt.addScaled(dir, dist);
+
+ laMat = x3dom.fields.SFMatrix4f.lookAt(newFrom, newAt, up);
+ laMat = laMat.inverse();
+
+ dist = newFrom.subtract(from).length();
+ var dur = Math.max(0.5, Math.log((1 + dist) / navi._vf.speed));
+
+ this.animateTo(laMat, this._scene.getViewpoint(), dur);
+ }
+
+ this._dx = 0;
+ this._dy = 0;
+ this._lastX = x;
+ this._lastY = y;
+ this._lastButton = buttonState;
+ this._isMoving = false;
+};
+
+x3dom.Viewarea.prototype.onMouseOver = function (x, y, buttonState)
+{
+ this._dx = 0;
+ this._dy = 0;
+ this._lastButton = 0;
+ this._isMoving = false;
+ this._lastX = x;
+ this._lastY = y;
+ this._deltaT = 0;
+};
+
+x3dom.Viewarea.prototype.onMouseOut = function (x, y, buttonState)
+{
+ this._dx = 0;
+ this._dy = 0;
+ this._lastButton = 0;
+ this._isMoving = false;
+ this._lastX = x;
+ this._lastY = y;
+ this._deltaT = 0;
+
+ //if the mouse is moved out of the canvas, reset the list of currently affected pointing sensors
+ //(this behaves similar to a mouse release inside the canvas)
+ var i;
+ var affectedPointingSensorsList = this._doc._nodeBag.affectedPointingSensors;
+ for (i = 0; i < affectedPointingSensorsList.length; ++i)
+ {
+ affectedPointingSensorsList[i].pointerReleased();
+ }
+ this._doc._nodeBag.affectedPointingSensors = [];
+};
+
+x3dom.Viewarea.prototype.onDoubleClick = function (x, y)
+{
+ if (this._doc._x3dElem.hasAttribute('disableDoubleClick') &&
+ this._doc._x3dElem.getAttribute('disableDoubleClick') === 'true') {
+ return;
+ }
+
+ var navi = this._scene.getNavigationInfo();
+
+ if (navi.getType() == "none") {
+ return;
+ }
+
+ var pickMode = this._scene._vf.pickMode.toLowerCase();
+
+ if ((pickMode == "color" || pickMode == "texcoord")) {
+ return;
+ }
+
+ var viewpoint = this._scene.getViewpoint();
+
+ viewpoint.setCenterOfRotation(this._pick);
+ x3dom.debug.logInfo("New center of Rotation: " + this._pick);
+
+ var mat = this.getViewMatrix().inverse();
+
+ var from = mat.e3();
+ var at = this._pick;
+ var up = mat.e1();
+
+ var norm = mat.e0().cross(up).normalize();
+ // get distance between look-at point and viewing plane
+ var dist = norm.dot(this._pick.subtract(from));
+
+ from = at.addScaled(norm, -dist);
+ mat = x3dom.fields.SFMatrix4f.lookAt(from, at, up);
+
+ x3dom.debug.logInfo("New camera position: " + from);
+ this.animateTo(mat.inverse(), viewpoint);
+};
+
+x3dom.Viewarea.prototype.handleMoveEvt = function (x, y, buttonState)
+{
+ //pointing sensors might still be in use, if the mouse has previously been pressed over sensor geometry
+ //(in general, transitions between INTERACTION and NAVIGATION require that the mouse is not pressed)
+ if (buttonState == 0)
+ {
+ this._doc._nodeBag.affectedPointingSensors = [];
+ }
+
+ this.prepareEvents(x, y, buttonState, "onmousemove");
+
+ if (this._pickingInfo.pickObj !== this._pickingInfo.lastObj)
+ {
+ if (this._pickingInfo.lastObj) {
+ var obj = this._pickingInfo.pickObj;
+ this._pickingInfo.pickObj = this._pickingInfo.lastObj;
+
+ // call event for lastObj
+ this.prepareEvents(x, y, buttonState, "onmouseout");
+ this._pickingInfo.pickObj = obj;
+ }
+
+ if (this._pickingInfo.pickObj) {
+ // call event for pickObj
+ this.prepareEvents(x, y, buttonState, "onmouseover");
+ }
+
+ this._pickingInfo.lastObj = this._pickingInfo.pickObj;
+ }
+};
+
+x3dom.Viewarea.prototype.onMove = function (x, y, buttonState)
+{
+ this.handleMoveEvt(x, y, buttonState);
+
+ if (this._lastX < 0 || this._lastY < 0) {
+ this._lastX = x;
+ this._lastY = y;
+ }
+ this._dx = x - this._lastX;
+ this._dy = y - this._lastY;
+ this._lastX = x;
+ this._lastY = y;
+};
+
+// multi-touch version of examine mode, called from X3DCanvas.js
+x3dom.Viewarea.prototype.onMoveView = function (translation, rotation)
+{
+ if (this._currentInputType == x3dom.InputTypes.NAVIGATION)
+ {
+ var navi = this._scene.getNavigationInfo();
+ var viewpoint = this._scene.getViewpoint();
+
+ if (navi.getType() === "examine")
+ {
+ if (translation)
+ {
+ var distance = (this._scene._lastMax.subtract(this._scene._lastMin)).length();
+ distance = ((distance < x3dom.fields.Eps) ? 1 : distance) * navi._vf.speed;
+
+ translation = translation.multiply(distance);
+ this._movement = this._movement.add(translation);
+
+ this._transMat = viewpoint.getViewMatrix().inverse().
+ mult(x3dom.fields.SFMatrix4f.translation(this._movement)).
+ mult(viewpoint.getViewMatrix());
+ }
+
+ if (rotation)
+ {
+ var center = viewpoint.getCenterOfRotation();
+ var mat = this.getViewMatrix();
+ mat.setTranslate(new x3dom.fields.SFVec3f(0,0,0));
+
+ this._rotMat = this._rotMat.
+ mult(x3dom.fields.SFMatrix4f.translation(center)).
+ mult(mat.inverse()).mult(rotation).mult(mat).
+ mult(x3dom.fields.SFMatrix4f.translation(center.negate()));
+ }
+
+ this._isMoving = true;
+ }
+ }
+};
+
+x3dom.Viewarea.prototype.onDrag = function (x, y, buttonState)
+{
+ // should onmouseover/-out be handled on drag?
+ this.handleMoveEvt(x, y, buttonState);
+
+ if (this._currentInputType == x3dom.InputTypes.NAVIGATION)
+ {
+ var navi = this._scene.getNavigationInfo();
+
+ var navType = navi.getType();
+ var navRestrict = navi.getExplorationMode();
+
+ if (navType === "none" || navRestrict == 0) {
+ return;
+ }
+
+ var viewpoint = this._scene.getViewpoint();
+
+ var dx = x - this._lastX;
+ var dy = y - this._lastY;
+ var d, vec, cor, mat = null;
+ var alpha, beta;
+
+ buttonState = (!navRestrict || (navRestrict != 7 && buttonState == 1)) ? navRestrict : buttonState;
+
+ if (navType === "examine")
+ {
+ if (buttonState & 1) //left
+ {
+ alpha = (dy * 2 * Math.PI) / this._width;
+ beta = (dx * 2 * Math.PI) / this._height;
+ mat = this.getViewMatrix();
+
+ var mx = x3dom.fields.SFMatrix4f.rotationX(alpha);
+ var my = x3dom.fields.SFMatrix4f.rotationY(beta);
+
+ var center = viewpoint.getCenterOfRotation();
+ mat.setTranslate(new x3dom.fields.SFVec3f(0,0,0));
+
+ this._rotMat = this._rotMat.
+ mult(x3dom.fields.SFMatrix4f.translation(center)).
+ mult(mat.inverse()).mult(mx).mult(my).mult(mat).
+ mult(x3dom.fields.SFMatrix4f.translation(center.negate()));
+ }
+ if (buttonState & 4) //middle
+ {
+ d = (this._scene._lastMax.subtract(this._scene._lastMin)).length();
+ d = ((d < x3dom.fields.Eps) ? 1 : d) * navi._vf.speed;
+
+ vec = new x3dom.fields.SFVec3f(d*dx/this._width, d*(-dy)/this._height, 0);
+ this._movement = this._movement.add(vec);
+
+ mat = this.getViewpointMatrix().mult(this._transMat);
+ //TODO; move real distance along viewing plane
+ this._transMat = mat.inverse().
+ mult(x3dom.fields.SFMatrix4f.translation(this._movement)).
+ mult(mat);
+ }
+ if (buttonState & 2) //right
+ {
+ d = (this._scene._lastMax.subtract(this._scene._lastMin)).length();
+ d = ((d < x3dom.fields.Eps) ? 1 : d) * navi._vf.speed;
+
+ vec = new x3dom.fields.SFVec3f(0, 0, d*(dx+dy)/this._height);
+
+ if (x3dom.isa(viewpoint, x3dom.nodeTypes.OrthoViewpoint))
+ {
+ viewpoint._vf.fieldOfView[0] += vec.z;
+ viewpoint._vf.fieldOfView[1] += vec.z;
+ viewpoint._vf.fieldOfView[2] -= vec.z;
+ viewpoint._vf.fieldOfView[3] -= vec.z;
+ viewpoint._projMatrix = null;
+ }
+ else
+ {
+ this._movement = this._movement.add(vec);
+ mat = this.getViewpointMatrix().mult(this._transMat);
+ //TODO; move real distance along viewing ray
+ this._transMat = mat.inverse().
+ mult(x3dom.fields.SFMatrix4f.translation(this._movement)).
+ mult(mat);
+ }
+ }
+
+ this._isMoving = true;
+ }
+ else if (navType === "turntable") // requires that y is up vector in world coords
+ {
+ if (!this._flyMat)
+ this.initTurnTable(navi, false);
+
+ if (buttonState & 1) //left
+ {
+ alpha = (dy * 2 * Math.PI) / this._height;
+ beta = (dx * 2 * Math.PI) / this._width;
+
+ this._flyMat = this.calcOrbit(alpha, beta, navi);
+ viewpoint.setView(this._flyMat.inverse());
+ }
+ else if (buttonState & 2) //right
+ {
+ d = (this._scene._lastMax.subtract(this._scene._lastMin)).length();
+ d = ((d < x3dom.fields.Eps) ? 1 : d) * navi._vf.speed;
+
+ this._up = this._flyMat.e1();
+ this._from = this._flyMat.e3(); // eye
+
+ // zoom in/out
+ cor = viewpoint.getCenterOfRotation();
+
+ var lastDir = cor.subtract(this._from);
+ var lastDirL = lastDir.length();
+ lastDir = lastDir.normalize();
+
+ var zoomAmount = d * (dx + dy) / this._height;
+
+ // FIXME: very experimental HACK to switch between both versions (clamp to CoR and CoR translation)
+ if (navi._vf.typeParams.length >= 5 && navi._vf.typeParams[4] > 0)
+ {
+ // maintain minimum distance (value given in typeParams[4]) to prevent orientation flips
+ var newDist = Math.min(zoomAmount, lastDirL - navi._vf.typeParams[4]);
+
+ // move along viewing ray, scaled with zoom factor
+ this._from = this._from.addScaled(lastDir, newDist);
+ }
+ else
+ {
+ // add z offset to look-at position, alternatively clamp
+ var diff = zoomAmount - lastDirL + 0.01;
+ if (diff >= 0) {
+ cor = cor.addScaled(lastDir, diff);
+ viewpoint.setCenterOfRotation(cor);
+ }
+
+ // move along viewing ray, scaled with zoom factor
+ this._from = this._from.addScaled(lastDir, zoomAmount);
+ }
+
+ // move along viewing ray, scaled with zoom factor
+ this._from = this._from.addScaled(lastDir, zoomAmount);
+
+ // update camera matrix with lookAt() and invert again
+ this._flyMat = x3dom.fields.SFMatrix4f.lookAt(this._from, cor, this._up);
+ viewpoint.setView(this._flyMat.inverse());
+ }
+ else if (buttonState & 4) //middle
+ {
+ d = (this._scene._lastMax.subtract(this._scene._lastMin)).length();
+ d = ((d < x3dom.fields.Eps) ? 1 : d) * navi._vf.speed * 0.75;
+
+ var tx = -d * dx / this._width;
+ var ty = d * dy / this._height;
+
+ this._up = this._flyMat.e1();
+ this._from = this._flyMat.e3(); // eye
+ var s = this._flyMat.e0();
+
+ // add xy offset to camera position for pan
+ this._from = this._from.addScaled(this._up, ty);
+ this._from = this._from.addScaled(s, tx);
+
+ // add xy offset to look-at position
+ cor = viewpoint.getCenterOfRotation();
+ cor = cor.addScaled(this._up, ty);
+ cor = cor.addScaled(s, tx);
+ viewpoint.setCenterOfRotation(cor);
+
+ // update camera matrix with lookAt() and invert
+ this._flyMat = x3dom.fields.SFMatrix4f.lookAt(this._from, cor, this._up);
+ viewpoint.setView(this._flyMat.inverse());
+ }
+
+ this._isMoving = true;
+ }
+ }
+
+ this._dx = dx;
+ this._dy = dy;
+
+ this._lastX = x;
+ this._lastY = y;
+};
+
+x3dom.Viewarea.prototype.calcOrbit = function (alpha, beta, navi)
+{
+ this._up = this._flyMat.e1();
+ this._from = this._flyMat.e3();
+
+ var offset = this._from.subtract(this._at);
+
+ // angle in xz-plane
+ var phi = Math.atan2(offset.x, offset.z);
+
+ // angle from y-axis
+ var theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.z * offset.z), offset.y);
+
+ phi -= beta;
+ theta -= alpha;
+
+ // clamp theta
+ var typeParams = navi.getTypeParams();
+ theta = Math.max(typeParams[2], Math.min(typeParams[3], theta));
+
+ var radius = offset.length();
+
+ // calc new cam position
+ var rSinPhi = radius * Math.sin(theta);
+
+ offset.x = rSinPhi * Math.sin(phi);
+ offset.y = radius * Math.cos(theta);
+ offset.z = rSinPhi * Math.cos(phi);
+
+ offset = this._at.add(offset);
+
+ // calc new up vector
+ theta -= Math.PI / 2;
+
+ var sinPhi = Math.sin(theta);
+ var cosPhi = Math.cos(theta);
+ var up = new x3dom.fields.SFVec3f(sinPhi * Math.sin(phi), cosPhi, sinPhi * Math.cos(phi));
+
+ if (up.y < 0)
+ up = up.negate();
+
+ return x3dom.fields.SFMatrix4f.lookAt(offset, this._at, up);
+};
+
+x3dom.Viewarea.prototype.prepareEvents = function (x, y, buttonState, eventType)
+{
+ var affectedPointingSensorsList = this._doc._nodeBag.affectedPointingSensors;
+ var pickMode = this._scene._vf.pickMode.toLowerCase();
+ var avoidTraversal = (pickMode.indexOf("idbuf") == 0 ||
+ pickMode == "color" || pickMode == "texcoord");
+
+ var obj = null;
+
+ if (avoidTraversal) {
+ obj = this._pickingInfo.pickObj;
+
+ if (obj) {
+ this._pick.setValues(this._pickingInfo.pickPos);
+ this._pickNorm.setValues(this._pickingInfo.pickNorm);
+
+ this.checkEvents(obj, x, y, buttonState, eventType);
+
+ if (eventType === "onclick") { // debug
+ if (obj._xmlNode)
+ x3dom.debug.logInfo("Hit \"" + obj._xmlNode.localName + "/ " + obj._DEF + "\"");
+ x3dom.debug.logInfo("Ray hit at position " + this._pick);
+ }
+ }
+ }
+
+ //TODO: this is pretty redundant - but from where should we obtain this event object?
+ // this also needs to work if there is no picked object, and independent from "avoidTraversal"?
+
+ // FIXME; avoidTraversal is only to distinguish between the ancient box and the other render-based pick modes,
+ // thus it seems the cleanest thing to just remove the old traversal-based and non-functional box mode.
+ // Concerning background: what about if we unify the onbackgroundClicked event such that there is also
+ // an onbackgroundMoved event etc?
+
+ var event = {
+ viewarea: this,
+ target: {}, // should be hit xml element
+ type: eventType.substr(2, eventType.length-2),
+ button: buttonState,
+ layerX: x,
+ layerY: y,
+ worldX: this._pick.x,
+ worldY: this._pick.y,
+ worldZ: this._pick.z,
+ normalX: this._pickNorm.x,
+ normalY: this._pickNorm.y,
+ normalZ: this._pickNorm.z,
+ hitPnt: this._pick.toGL(), // for convenience
+ hitObject: (obj && obj._xmlNode) ? obj._xmlNode : null,
+ shadowObjectId: this._pickingInfo.shadowObjectId,
+ cancelBubble: false,
+ stopPropagation: function() { this.cancelBubble = true; },
+ preventDefault: function() { this.cancelBubble = true; }
+ };
+
+ //forward event to affected pointing device sensors
+ this._notifyAffectedPointingSensors(event);
+
+ //switch between navigation and interaction
+ if (affectedPointingSensorsList.length > 0)
+ {
+ this._currentInputType = x3dom.InputTypes.INTERACTION;
+ }
+ else
+ {
+ this._currentInputType = x3dom.InputTypes.NAVIGATION;
+ }
+};
+
+
+x3dom.Viewarea.prototype.getRenderMode = function()
+{
+ // this._points == 0 ? TRIANGLES or TRIANGLE_STRIP
+ // this._points == 1 ? gl.POINTS
+ // this._points == 2 ? gl.LINES
+ // TODO: 3 :== surface with additional wireframe render mode
+ return this._points;
+};
+
+
+x3dom.Viewarea.prototype.getShadowedLights = function()
+{
+ var shadowedLights = [];
+ var shadowIndex = 0;
+ var slights = this.getLights();
+ for (var i=0; i<slights.length; i++){
+ if (slights[i]._vf.shadowIntensity > 0.0){
+ shadowedLights[shadowIndex] = slights[i];
+ shadowIndex++;
+ }
+ }
+ return shadowedLights;
+};
+
+
+/**
+ * Calculate view frustum split positions for the given number of cascades
+ * @param {Number} numCascades - the number of cascades
+ * @param {Number} splitFactor - the splitting factor
+ * @param {Number} splitOffset - the offset for the splits
+ * @param {Array} postProject - the post projection something
+ * @param {x3dom.fields.SFMatrix4f} mat_proj - the projection matrix
+ * @return {Array} the post projection something
+ */
+x3dom.Viewarea.prototype.getShadowSplitDepths = function(numCascades, splitFactor, splitOffset, postProject, mat_proj)
+{
+ var logSplit;
+ var practSplit = [];
+
+ var viewPoint = this._scene.getViewpoint();
+
+ var zNear = viewPoint.getNear();
+ var zFar = viewPoint.getFar();
+
+ practSplit[0] = zNear;
+
+ //pseudo near plane for bigger cascades near camera
+ zNear = zNear + splitOffset*(zFar-zNear)/10;
+
+ //calculate split depths according to "practical split scheme"
+ for (var i=1;i<numCascades;i++){
+ logSplit = zNear * Math.pow((zFar / zNear), i / numCascades);
+ practSplit[i] = splitFactor * logSplit + (1 - splitFactor) * (zNear + i / (numCascades * (zNear-zFar)));
+ }
+ practSplit[numCascades] = zFar;
+
+ //return in view coords
+ if (!postProject)
+ return practSplit;
+
+ //return in post projective coords
+ var postProj = [];
+
+ for (var j=0; j<=numCascades; j++){
+ postProj[j] = mat_proj.multFullMatrixPnt(new x3dom.fields.SFVec3f(0,0,-practSplit[j])).z;
+ }
+
+ return postProj;
+};
+
+
+/*
+ * calculate a matrix to enhance the placement of
+ * the near and far planes of the light projection matrix
+*/
+x3dom.Viewarea.prototype.getLightCropMatrix = function(WCToLCMatrix)
+{
+ //get corner points of scene bounds
+ var sceneMin = x3dom.fields.SFVec3f.copy(this._scene._lastMin);
+ var sceneMax = x3dom.fields.SFVec3f.copy(this._scene._lastMax);
+
+ var sceneCorners = [];
+ sceneCorners[0] = new x3dom.fields.SFVec3f(sceneMin.x, sceneMin.y, sceneMin.z);
+ sceneCorners[1] = new x3dom.fields.SFVec3f(sceneMin.x, sceneMin.y, sceneMax.z);
+ sceneCorners[2] = new x3dom.fields.SFVec3f(sceneMin.x, sceneMax.y, sceneMin.z);
+ sceneCorners[3] = new x3dom.fields.SFVec3f(sceneMin.x, sceneMax.y, sceneMax.z);
+ sceneCorners[4] = new x3dom.fields.SFVec3f(sceneMax.x, sceneMin.y, sceneMin.z);
+ sceneCorners[5] = new x3dom.fields.SFVec3f(sceneMax.x, sceneMin.y, sceneMax.z);
+ sceneCorners[6] = new x3dom.fields.SFVec3f(sceneMax.x, sceneMax.y, sceneMin.z);
+ sceneCorners[7] = new x3dom.fields.SFVec3f(sceneMax.x, sceneMax.y, sceneMax.z);
+
+ //transform scene bounds into light space
+ var i;
+ for (i=0; i<8; i++){
+ sceneCorners[i] = WCToLCMatrix.multFullMatrixPnt(sceneCorners[i]);
+ }
+
+ //determine min and max values in light space
+ var minScene = x3dom.fields.SFVec3f.copy(sceneCorners[0]);
+ var maxScene = x3dom.fields.SFVec3f.copy(sceneCorners[0]);
+
+ for (i=1; i<8; i++){
+ minScene.z = Math.min(sceneCorners[i].z, minScene.z);
+ maxScene.z = Math.max(sceneCorners[i].z, maxScene.z);
+ }
+
+ var scaleZ = 2.0 / (maxScene.z - minScene.z);
+ var offsetZ = -(scaleZ * (maxScene.z + minScene.z)) / 2.0;
+
+ //var scaleZ = 1.0 / (maxScene.z - minScene.z);
+ //var offsetZ = -minScene.z * scaleZ;
+
+ var cropMatrix = x3dom.fields.SFMatrix4f.identity();
+
+ cropMatrix._22 = scaleZ;
+ cropMatrix._23 = offsetZ;
+
+ return cropMatrix;
+};
+
+
+/*
+ * Calculate a matrix to fit the given wctolc-matrix to the split boundaries
+ */
+x3dom.Viewarea.prototype.getLightFittingMatrix = function(WCToLCMatrix, zNear, zFar, mat_proj)
+{
+ var mat_view = this.getViewMatrix();
+ var mat_view_proj = mat_proj.mult(mat_view);
+ var mat_view_proj_inverse = mat_view_proj.inverse();
+
+ //define view frustum corner points in post perspective view space
+ var frustumCorners = [];
+ frustumCorners[0] = new x3dom.fields.SFVec3f(-1, -1, zFar);
+ frustumCorners[1] = new x3dom.fields.SFVec3f(-1, -1, zNear);
+ frustumCorners[2] = new x3dom.fields.SFVec3f(-1, 1, zFar);
+ frustumCorners[3] = new x3dom.fields.SFVec3f(-1, 1, zNear);
+ frustumCorners[4] = new x3dom.fields.SFVec3f( 1, -1, zFar);
+ frustumCorners[5] = new x3dom.fields.SFVec3f( 1, -1, zNear);
+ frustumCorners[6] = new x3dom.fields.SFVec3f( 1, 1, zFar);
+ frustumCorners[7] = new x3dom.fields.SFVec3f( 1, 1, zNear);
+
+
+ //transform corner points into post perspective light space
+ var i;
+ for (i=0; i<8; i++){
+ frustumCorners[i] = mat_view_proj_inverse.multFullMatrixPnt(frustumCorners[i]);
+ frustumCorners[i] = WCToLCMatrix.multFullMatrixPnt(frustumCorners[i]);
+ }
+
+ //calculate minimum and maximum values
+ var minFrustum = x3dom.fields.SFVec3f.copy(frustumCorners[0]);
+ var maxFrustum = x3dom.fields.SFVec3f.copy(frustumCorners[0]);
+
+ for (i=1; i<8; i++){
+ minFrustum.x = Math.min(frustumCorners[i].x, minFrustum.x);
+ minFrustum.y = Math.min(frustumCorners[i].y, minFrustum.y);
+ minFrustum.z = Math.min(frustumCorners[i].z, minFrustum.z);
+
+ maxFrustum.x = Math.max(frustumCorners[i].x, maxFrustum.x);
+ maxFrustum.y = Math.max(frustumCorners[i].y, maxFrustum.y);
+ maxFrustum.z = Math.max(frustumCorners[i].z, maxFrustum.z);
+ }
+
+
+ //clip values to box (-1,-1,-1),(1,1,1)
+ function clip(min,max)
+ {
+ var xMin = min.x;
+ var yMin = min.y;
+ var zMin = min.z;
+ var xMax = max.x;
+ var yMax = max.y;
+ var zMax = max.z;
+
+ if (xMin > 1.0 || xMax < -1.0) {
+ xMin = -1.0;
+ xMax = 1.0;
+ } else {
+ xMin = Math.max(xMin,-1.0);
+ xMax = Math.min(xMax, 1.0);
+ }
+
+ if (yMin > 1.0 || yMax < -1.0) {
+ yMin = -1.0;
+ yMax = 1.0;
+ } else {
+ yMin = Math.max(yMin,-1.0);
+ yMax = Math.min(yMax, 1.0);
+ }
+
+ if (zMin > 1.0 || zMax < -1.0){
+ zMin = -1.0;
+ zMax = 1.0;
+ } else {
+ zMin = Math.max(zMin,-1.0);
+ zMax = Math.min(zMax, 1.0);
+ }
+ var minValues = new x3dom.fields.SFVec3f(xMin,yMin,zMin);
+ var maxValues = new x3dom.fields.SFVec3f(xMax,yMax,zMax);
+
+ return new x3dom.fields.BoxVolume(minValues,maxValues);
+ }
+
+ var frustumBB = clip(minFrustum, maxFrustum);
+
+ //define fitting matrix
+ var scaleX = 2.0 / (frustumBB.max.x - frustumBB.min.x);
+ var scaleY = 2.0 / (frustumBB.max.y - frustumBB.min.y);
+ var offsetX = -(scaleX * (frustumBB.max.x + frustumBB.min.x)) / 2.0;
+ var offsetY = -(scaleY * (frustumBB.max.y + frustumBB.min.y)) / 2.0;
+
+ var fittingMatrix = x3dom.fields.SFMatrix4f.identity();
+
+ fittingMatrix._00 = scaleX;
+ fittingMatrix._11 = scaleY;
+ fittingMatrix._03 = offsetX;
+ fittingMatrix._13 = offsetY;
+
+ return fittingMatrix;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/** @class x3dom.Mesh
+*/
+x3dom.Mesh = function(parent)
+{
+ this._parent = parent;
+
+ this._vol = new x3dom.fields.BoxVolume();
+
+ this._invalidate = true;
+ this._numFaces = 0;
+ this._numCoords = 0;
+
+ // cp. x3dom.Utils.primTypeDic for type list
+ this._primType = 'TRIANGLES';
+
+ this._positions = [];
+ this._normals = [];
+ this._texCoords = [];
+ this._colors = [];
+ this._indices = [];
+
+ this._positions[0] = [];
+ this._normals[0] = [];
+ this._texCoords[0] = [];
+ this._colors[0] = [];
+ this._indices[0] = [];
+};
+
+x3dom.Mesh.prototype._dynamicFields = {}; // can hold X3DVertexAttributeNodes
+/*x3dom.Mesh.prototype._positions = [];
+x3dom.Mesh.prototype._normals = [];
+x3dom.Mesh.prototype._texCoords = [];
+x3dom.Mesh.prototype._colors = [];
+x3dom.Mesh.prototype._indices = [];*/
+
+x3dom.Mesh.prototype._numPosComponents = 3;
+x3dom.Mesh.prototype._numTexComponents = 2;
+x3dom.Mesh.prototype._numColComponents = 3;
+x3dom.Mesh.prototype._numNormComponents = 3;
+x3dom.Mesh.prototype._lit = true;
+
+x3dom.Mesh.prototype._vol = null;
+x3dom.Mesh.prototype._invalidate = true;
+x3dom.Mesh.prototype._numFaces = 0;
+x3dom.Mesh.prototype._numCoords = 0;
+
+x3dom.Mesh.prototype.setMeshData = function(positions, normals, texCoords, colors, indices)
+{
+ this._positions[0] = positions;
+ this._normals[0] = normals;
+ this._texCoords[0] = texCoords;
+ this._colors[0] = colors;
+ this._indices[0] = indices;
+
+ this._invalidate = true;
+ this._numFaces = this._indices[0].length / 3;
+ this._numCoords = this._positions[0].length / 3;
+};
+
+x3dom.Mesh.prototype.getVolume = function()
+{
+ if (this._invalidate == true && !this._vol.isValid())
+ {
+ var coords = this._positions[0];
+ var n = coords.length;
+
+ if (n > 3)
+ {
+ var initVal = new x3dom.fields.SFVec3f(coords[0],coords[1],coords[2]);
+ this._vol.setBounds(initVal, initVal);
+
+ for (var i=3; i<n; i+=3)
+ {
+ if (this._vol.min.x > coords[i ]) { this._vol.min.x = coords[i ]; }
+ if (this._vol.min.y > coords[i+1]) { this._vol.min.y = coords[i+1]; }
+ if (this._vol.min.z > coords[i+2]) { this._vol.min.z = coords[i+2]; }
+
+ if (this._vol.max.x < coords[i ]) { this._vol.max.x = coords[i ]; }
+ if (this._vol.max.y < coords[i+1]) { this._vol.max.y = coords[i+1]; }
+ if (this._vol.max.z < coords[i+2]) { this._vol.max.z = coords[i+2]; }
+ }
+ this._invalidate = false;
+ }
+ }
+
+ return this._vol;
+};
+
+x3dom.Mesh.prototype.invalidate = function()
+{
+ this._invalidate = true;
+ this._vol.invalidate();
+};
+
+x3dom.Mesh.prototype.isValid = function()
+{
+ return this._vol.isValid();
+};
+
+x3dom.Mesh.prototype.getCenter = function()
+{
+ return this.getVolume().getCenter();
+};
+
+x3dom.Mesh.prototype.getDiameter = function()
+{
+ return this.getVolume().getDiameter();
+};
+
+x3dom.Mesh.prototype.doIntersect = function(line)
+{
+ var vol = this.getVolume();
+ var isect = line.intersect(vol.min, vol.max);
+
+ //TODO: iterate over all faces!
+ if (isect && line.enter < line.dist)
+ {
+ //x3dom.debug.logInfo("Hit \"" + this._parent._xmlNode.localName + "/ " +
+ // this._parent._DEF + "\" at dist=" + line.enter.toFixed(4));
+
+ line.dist = line.enter;
+ line.hitObject = this._parent;
+ line.hitPoint = line.pos.add(line.dir.multiply(line.enter));
+ }
+
+ return isect;
+};
+
+x3dom.Mesh.prototype.calcNormals = function(creaseAngle, ccw)
+{
+ if (ccw === undefined)
+ ccw = true;
+
+ var multInd = this._multiIndIndices && this._multiIndIndices.length;
+ var idxs = multInd ? this._multiIndIndices : this._indices[0];
+ var coords = this._positions[0];
+
+ var vertNormals = [];
+ var vertFaceNormals = [];
+
+ var i, j, m = coords.length;
+ var a, b, n = null;
+
+ var num = (this._posSize !== undefined && this._posSize > m) ? this._posSize / 3 : m / 3;
+ num = 3 * ((num - Math.floor(num) > 0) ? Math.floor(num + 1) : num);
+
+ for (i = 0; i < num; ++i) {
+ vertFaceNormals[i] = [];
+ }
+
+ num = idxs.length;
+
+ for (i = 0; i < num; i += 3) {
+ var ind_i0, ind_i1, ind_i2;
+ var t;
+
+ if (!multInd) {
+ ind_i0 = idxs[i ] * 3;
+ ind_i1 = idxs[i+1] * 3;
+ ind_i2 = idxs[i+2] * 3;
+
+ t = new x3dom.fields.SFVec3f(coords[ind_i1], coords[ind_i1+1], coords[ind_i1+2]);
+ a = new x3dom.fields.SFVec3f(coords[ind_i0], coords[ind_i0+1], coords[ind_i0+2]).subtract(t);
+ b = t.subtract(new x3dom.fields.SFVec3f(coords[ind_i2], coords[ind_i2+1], coords[ind_i2+2]));
+
+ // this is needed a few lines below
+ ind_i0 = i * 3;
+ ind_i1 = (i+1) * 3;
+ ind_i2 = (i+2) * 3;
+ }
+ else {
+ ind_i0 = i * 3;
+ ind_i1 = (i+1) * 3;
+ ind_i2 = (i+2) * 3;
+
+ t = new x3dom.fields.SFVec3f(coords[ind_i1], coords[ind_i1+1], coords[ind_i1+2]);
+ a = new x3dom.fields.SFVec3f(coords[ind_i0], coords[ind_i0+1], coords[ind_i0+2]).subtract(t);
+ b = t.subtract(new x3dom.fields.SFVec3f(coords[ind_i2], coords[ind_i2+1], coords[ind_i2+2]));
+ }
+
+ n = a.cross(b).normalize();
+ if (!ccw)
+ n = n.negate();
+
+ if (creaseAngle <= x3dom.fields.Eps) {
+ vertNormals[ind_i0 ] = vertNormals[ind_i1 ] = vertNormals[ind_i2 ] = n.x;
+ vertNormals[ind_i0+1] = vertNormals[ind_i1+1] = vertNormals[ind_i2+1] = n.y;
+ vertNormals[ind_i0+2] = vertNormals[ind_i1+2] = vertNormals[ind_i2+2] = n.z;
+ }
+ else {
+ vertFaceNormals[idxs[i ]].push(n);
+ vertFaceNormals[idxs[i+1]].push(n);
+ vertFaceNormals[idxs[i+2]].push(n);
+ }
+ }
+
+ // TODO: allow generic creaseAngle
+ if (creaseAngle > x3dom.fields.Eps)
+ {
+ for (i = 0; i < m; i += 3) {
+ var iThird = i / 3;
+ var arr;
+
+ if (!multInd) {
+ arr = vertFaceNormals[iThird];
+ }
+ else {
+ arr = vertFaceNormals[idxs[iThird]];
+ }
+ num = arr.length;
+
+ n = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ for (j = 0; j < num; ++j) {
+ n = n.add(arr[j]);
+ }
+ n = n.normalize();
+
+ vertNormals[i ] = n.x;
+ vertNormals[i+1] = n.y;
+ vertNormals[i+2] = n.z;
+ }
+ }
+
+ this._normals[0] = vertNormals;
+};
+
+/** @param primStride Number of index entries per primitive, for example 3 for TRIANGLES
+ */
+x3dom.Mesh.prototype.splitMesh = function(primStride, checkMultiIndIndices)
+{
+ var pStride;
+ var isMultiInd;
+
+ if (typeof primStride === undefined) {
+ pStride = 3;
+ } else {
+ pStride = primStride;
+ }
+
+ if (typeof checkMultiIndIndices === undefined) {
+ checkMultiIndIndices = false;
+ }
+
+ var MAX = x3dom.Utils.maxIndexableCoords;
+
+ //adapt MAX to match the primitive stride
+ MAX = Math.floor(MAX / pStride) * pStride;
+
+ if (this._positions[0].length / 3 <= MAX && !checkMultiIndIndices) {
+ return;
+ }
+
+ if (checkMultiIndIndices) {
+ isMultiInd = this._multiIndIndices && this._multiIndIndices.length;
+ } else {
+ isMultiInd = false;
+ }
+
+ var positions = this._positions[0];
+ var normals = this._normals[0];
+ var texCoords = this._texCoords[0];
+ var colors = this._colors[0];
+ var indices = isMultiInd ? this._multiIndIndices : this._indices[0];
+
+ var i = 0;
+
+ do
+ {
+ this._positions[i] = [];
+ this._normals[i] = [];
+ this._texCoords[i] = [];
+ this._colors[i] = [];
+ this._indices[i] = [];
+
+ var k = (indices.length - ((i + 1) * MAX) >= 0);
+
+ if (k) {
+ this._indices[i] = indices.slice(i * MAX, (i + 1) * MAX);
+ } else {
+ this._indices[i] = indices.slice(i * MAX);
+ }
+
+ if(!isMultiInd) {
+ if (i) {
+ var m = i * MAX;
+ for (var j=0, l=this._indices[i].length; j<l; j++) {
+ this._indices[i][j] -= m;
+ }
+ }
+ } else {
+ for (var j=0, l=this._indices[i].length; j<l; j++) {
+ this._indices[i][j] = j;
+ }
+ }
+
+ if (k) {
+ this._positions[i] = positions.slice(i * MAX * 3, 3 * (i + 1) * MAX);
+ } else {
+ this._positions[i] = positions.slice(i * MAX * 3);
+ }
+
+ if (normals.length) {
+ if (k) {
+ this._normals[i] = normals.slice(i * MAX * 3, 3 * (i + 1) * MAX);
+ } else {
+ this._normals[i] = normals.slice(i * MAX * 3);
+ }
+ }
+ if (texCoords.length) {
+ if (k) {
+ this._texCoords[i] = texCoords.slice(i * MAX * this._numTexComponents,
+ this._numTexComponents * (i + 1) * MAX);
+ } else {
+ this._texCoords[i] = texCoords.slice(i * MAX * this._numTexComponents);
+ }
+ }
+ if (colors.length) {
+ if (k) {
+ this._colors[i] = colors.slice(i * MAX * this._numColComponents,
+ this._numColComponents * (i + 1) * MAX);
+ } else {
+ this._colors[i] = colors.slice(i * MAX * this._numColComponents);
+ }
+ }
+ }
+ while (positions.length > ++i * MAX * 3);
+};
+
+x3dom.Mesh.prototype.calcTexCoords = function(mode)
+{
+ this._texCoords[0] = [];
+
+ // TODO; impl. all modes that aren't handled in shader!
+ // FIXME; WebKit requires valid texCoords for texturing
+ if (mode.toLowerCase() === "sphere-local")
+ {
+ for (var i=0, j=0, n=this._normals[0].length; i<n; i+=3)
+ {
+ this._texCoords[0][j++] = 0.5 + this._normals[0][i ] / 2.0;
+ this._texCoords[0][j++] = 0.5 + this._normals[0][i+1] / 2.0;
+ }
+ }
+ else // "plane" is x3d default mapping
+ {
+ var min = new x3dom.fields.SFVec3f(0, 0, 0),
+ max = new x3dom.fields.SFVec3f(0, 0, 0);
+ var vol = this.getVolume();
+
+ vol.getBounds(min, max);
+ var dia = max.subtract(min);
+
+ var S = 0, T = 1;
+
+ if (dia.x >= dia.y)
+ {
+ if (dia.x >= dia.z)
+ {
+ S = 0;
+ T = dia.y >= dia.z ? 1 : 2;
+ }
+ else // dia.x < dia.z
+ {
+ S = 2;
+ T = 0;
+ }
+ }
+ else // dia.x < dia.y
+ {
+ if (dia.y >= dia.z)
+ {
+ S = 1;
+ T = dia.x >= dia.z ? 0 : 2;
+ }
+ else // dia.y < dia.z
+ {
+ S = 2;
+ T = 1;
+ }
+ }
+
+ var sDenom = 1, tDenom = 1;
+ var sMin = 0, tMin = 0;
+
+ switch(S) {
+ case 0: sDenom = dia.x; sMin = min.x; break;
+ case 1: sDenom = dia.y; sMin = min.y; break;
+ case 2: sDenom = dia.z; sMin = min.z; break;
+ }
+
+ switch(T) {
+ case 0: tDenom = dia.x; tMin = min.x; break;
+ case 1: tDenom = dia.y; tMin = min.y; break;
+ case 2: tDenom = dia.z; tMin = min.z; break;
+ }
+
+ for (var k=0, l=0, m=this._positions[0].length; k<m; k+=3)
+ {
+ this._texCoords[0][l++] = (this._positions[0][k+S] - sMin) / sDenom;
+ this._texCoords[0][l++] = (this._positions[0][k+T] - tMin) / tDenom;
+ }
+ }
+};
+
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/** If used as standalone lib, define some basics first. */
+if (typeof x3dom === "undefined")
+{
+ /**
+ * @namespace x3dom
+ */
+ x3dom = {
+ extend: function(f) {
+ function G() {}
+ G.prototype = f.prototype || f;
+ return new G();
+ },
+
+ debug: {
+ logInfo: function(msg) { console.log(msg); },
+ logWarning: function(msg) { console.warn(msg); },
+ logError: function(msg) { console.error(msg); }
+ }
+ };
+
+ if (!Array.map) {
+ Array.map = function(array, fun, thisp) {
+ var len = array.length;
+ var res = [];
+ for (var i = 0; i < len; i++) {
+ if (i in array) {
+ res[i] = fun.call(thisp, array[i], i, array);
+ }
+ }
+ return res;
+ };
+ }
+
+ console.log("Using x3dom fields.js as standalone math and/or base types library.");
+}
+
+
+/**
+ * The x3dom.fields namespace.
+ * @namespace x3dom.fields
+ */
+x3dom.fields = {};
+
+/** shortcut for convenience and speedup */
+var VecMath = x3dom.fields;
+
+/** Epsilon */
+x3dom.fields.Eps = 0.000001;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Single-Field Definitions
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor. You must either specify all argument values or no argument. In the latter case, an identity matrix will be created.
+ *
+ * @class Represents a 4x4 matrix in row major format.
+ * @param {Number} [_00=1] - value at [0,0]
+ * @param {Number} [_01=0] - value at [0,1]
+ * @param {Number} [_02=0] - value at [0,2]
+ * @param {Number} [_03=0] - value at [0,3]
+ * @param {Number} [_10=0] - value at [1,0]
+ * @param {Number} [_11=1] - value at [1,1]
+ * @param {Number} [_12=0] - value at [1,2]
+ * @param {Number} [_13=0] - value at [1,3]
+ * @param {Number} [_20=0] - value at [2,0]
+ * @param {Number} [_21=0] - value at [2,1]
+ * @param {Number} [_22=1] - value at [2,2]
+ * @param {Number} [_23=0] - value at [2,3]
+ * @param {Number} [_30=0] - value at [3,0]
+ * @param {Number} [_31=0] - value at [3,1]
+ * @param {Number} [_32=0] - value at [3,2]
+ * @param {Number} [_33=1] - value at [3,3]
+ */
+x3dom.fields.SFMatrix4f = function( _00, _01, _02, _03,
+ _10, _11, _12, _13,
+ _20, _21, _22, _23,
+ _30, _31, _32, _33)
+{
+ if (arguments.length === 0) {
+ this._00 = 1; this._01 = 0; this._02 = 0; this._03 = 0;
+ this._10 = 0; this._11 = 1; this._12 = 0; this._13 = 0;
+ this._20 = 0; this._21 = 0; this._22 = 1; this._23 = 0;
+ this._30 = 0; this._31 = 0; this._32 = 0; this._33 = 1;
+ }
+ else {
+ this._00 = _00; this._01 = _01; this._02 = _02; this._03 = _03;
+ this._10 = _10; this._11 = _11; this._12 = _12; this._13 = _13;
+ this._20 = _20; this._21 = _21; this._22 = _22; this._23 = _23;
+ this._30 = _30; this._31 = _31; this._32 = _32; this._33 = _33;
+ }
+};
+
+/**
+ * Returns the first column vector of the matrix.
+ * @returns {x3dom.fields.SFVec3f} the vector
+ */
+x3dom.fields.SFMatrix4f.prototype.e0 = function () {
+ var baseVec = new x3dom.fields.SFVec3f(this._00, this._10, this._20);
+ return baseVec.normalize();
+};
+
+/**
+ * Returns the second column vector of the matrix.
+ * @returns {x3dom.fields.SFVec3f} the vector
+ */
+x3dom.fields.SFMatrix4f.prototype.e1 = function () {
+ var baseVec = new x3dom.fields.SFVec3f(this._01, this._11, this._21);
+ return baseVec.normalize();
+};
+
+/**
+ * Returns the third column vector of the matrix.
+ * @returns {x3dom.fields.SFVec3f} the vector
+ */
+x3dom.fields.SFMatrix4f.prototype.e2 = function () {
+ var baseVec = new x3dom.fields.SFVec3f(this._02, this._12, this._22);
+ return baseVec.normalize();
+};
+
+/**
+ * Returns the fourth column vector of the matrix.
+ * @returns {x3dom.fields.SFVec3f} the vector
+ */
+x3dom.fields.SFMatrix4f.prototype.e3 = function () {
+ return new x3dom.fields.SFVec3f(this._03, this._13, this._23);
+};
+
+/**
+ * Returns a copy of the argument matrix.
+ * @param {x3dom.fields.SFMatrix4f} that - the matrix to copy
+ * @returns {x3dom.fields.SFMatrix4f} the copy
+ */
+x3dom.fields.SFMatrix4f.copy = function(that) {
+ return new x3dom.fields.SFMatrix4f(
+ that._00, that._01, that._02, that._03,
+ that._10, that._11, that._12, that._13,
+ that._20, that._21, that._22, that._23,
+ that._30, that._31, that._32, that._33
+ );
+};
+
+/**
+ * Returns a copy of the matrix.
+ * @returns {x3dom.fields.SFMatrix4f} the copy
+ */
+x3dom.fields.SFMatrix4f.prototype.copy = function() {
+ return x3dom.fields.SFMatrix4f.copy(this);
+};
+
+/**
+ * Returns a SFMatrix4f identity matrix.
+ * @returns {x3dom.fields.SFMatrix4f} the new identity matrix
+ */
+x3dom.fields.SFMatrix4f.identity = function () {
+ return new x3dom.fields.SFMatrix4f(
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ );
+};
+
+/**
+ * Returns a new null matrix.
+ * @returns {x3dom.fields.SFMatrix4f} the new null matrix
+ */
+x3dom.fields.SFMatrix4f.zeroMatrix = function () {
+ return new x3dom.fields.SFMatrix4f(
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+ );
+};
+
+/**
+ * Returns a new translation matrix.
+ * @param {x3dom.fields.SFVec3f} vec - vector that describes the desired translation
+ * @returns {x3dom.fields.SFMatrix4f} the new identity matrix
+ */
+x3dom.fields.SFMatrix4f.translation = function (vec) {
+ return new x3dom.fields.SFMatrix4f(
+ 1, 0, 0, vec.x,
+ 0, 1, 0, vec.y,
+ 0, 0, 1, vec.z,
+ 0, 0, 0, 1
+ );
+};
+
+/**
+ * Returns a new rotation matrix , rotating around the x axis.
+ * @param {x3dom.fields.SFVec3f} a - angle in radians
+ * @returns {x3dom.fields.SFMatrix4f} the new rotation matrix
+ */
+x3dom.fields.SFMatrix4f.rotationX = function (a) {
+ var c = Math.cos(a);
+ var s = Math.sin(a);
+ return new x3dom.fields.SFMatrix4f(
+ 1, 0, 0, 0,
+ 0, c, -s, 0,
+ 0, s, c, 0,
+ 0, 0, 0, 1
+ );
+};
+
+/**
+ * Returns a new rotation matrix , rotating around the y axis.
+ * @param {x3dom.fields.SFVec3f} a - angle in radians
+ * @returns {x3dom.fields.SFMatrix4f} the new rotation matrix
+ */
+x3dom.fields.SFMatrix4f.rotationY = function (a) {
+ var c = Math.cos(a);
+ var s = Math.sin(a);
+ return new x3dom.fields.SFMatrix4f(
+ c, 0, s, 0,
+ 0, 1, 0, 0,
+ -s, 0, c, 0,
+ 0, 0, 0, 1
+ );
+};
+
+/**
+ * Returns a new rotation matrix , rotating around the z axis.
+ * @param {x3dom.fields.SFVec3f} a - angle in radians
+ * @returns {x3dom.fields.SFMatrix4f} the new rotation matrix
+ */
+x3dom.fields.SFMatrix4f.rotationZ = function (a) {
+ var c = Math.cos(a);
+ var s = Math.sin(a);
+ return new x3dom.fields.SFMatrix4f(
+ c, -s, 0, 0,
+ s, c, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ );
+};
+
+/**
+ * Returns a new scale matrix.
+ * @param {x3dom.fields.SFVec3f} vec - vector containing scale factors along the three main axes
+ * @returns {x3dom.fields.SFMatrix4f} the new scale matrix
+ */
+x3dom.fields.SFMatrix4f.scale = function (vec) {
+ return new x3dom.fields.SFMatrix4f(
+ vec.x, 0, 0, 0,
+ 0, vec.y, 0, 0,
+ 0, 0, vec.z, 0,
+ 0, 0, 0, 1
+ );
+};
+
+/**
+ * Returns a new camera matrix, using the given "look at" parameters.
+ * @param {x3dom.fields.SFVec3f} from - eye point
+ * @param {x3dom.fields.SFVec3f} at - focus ("look at") point
+ * @param {x3dom.fields.SFVec3f} up - up vector
+ * @returns {x3dom.fields.SFMatrix4f} the new camera matrix
+ */
+x3dom.fields.SFMatrix4f.lookAt = function (from, at, up)
+{
+ var view = from.subtract(at).normalize();
+ var right = up.normalize().cross(view).normalize();
+
+ // check if zero vector, i.e. linearly dependent
+ if (right.dot(right) < x3dom.fields.Eps) {
+ x3dom.debug.logWarning("View matrix is linearly dependent.");
+ return x3dom.fields.SFMatrix4f.translation(from);
+ }
+
+ var newUp = view.cross(right).normalize();
+
+ var tmp = x3dom.fields.SFMatrix4f.identity();
+ tmp.setValue(right, newUp, view, from);
+
+ return tmp;
+};
+
+x3dom.fields.SFMatrix4f.perspectiveFrustum = function(left, right, bottom, top, near, far)
+{
+ return new x3dom.fields.SFMatrix4f(
+ 2*near/(right-left), 0, (right+left)/(right-left), 0,
+ 0, 2*near/(top-bottom), (top+bottom)/(top-bottom), 0,
+ 0, 0, -(far+near)/(far-near), -2*far*near/(far-near),
+ 0, 0, -1, 0
+ );
+};
+
+/**
+ * Returns a new perspective projection matrix.
+ * @param {Number} fov - field-of-view angle in radians
+ * @param {Number} aspect - aspect ratio (width / height)
+ * @param {Number} near - near clipping distance
+ * @param {Number} far - far clipping distance
+ * @returns {x3dom.fields.SFMatrix4f} the new projection matrix
+ */
+x3dom.fields.SFMatrix4f.perspective = function(fov, aspect, near, far)
+{
+ var f = 1 / Math.tan(fov / 2);
+
+ return new x3dom.fields.SFMatrix4f(
+ f/aspect, 0, 0, 0,
+ 0, f, 0, 0,
+ 0, 0, (near+far)/(near-far), 2*near*far/(near-far),
+ 0, 0, -1, 0
+ );
+};
+
+/**
+ * Returns a new orthogonal projection matrix.
+ * @param {Number} left - left border value of the view area
+ * @param {Number} right - right border value of the view area
+ * @param {Number} bottom - bottom border value of the view area
+ * @param {Number} top - top border value of the view area
+ * @param {Number} near - near clipping distance
+ * @param {Number} far - far clipping distance
+ * @param {Number} [aspect=1.0] - desired aspect ratio (width / height) of the projected image
+ * @returns {x3dom.fields.SFMatrix4f} the new projection matrix
+ */
+x3dom.fields.SFMatrix4f.ortho = function(left, right, bottom, top, near, far, aspect)
+{
+ var rl = (right - left) / 2; // hs
+ var tb = (top - bottom) / 2; // vs
+ var fn = far - near;
+
+ if (aspect === undefined)
+ aspect = 1.0;
+
+ if (aspect < (rl / tb))
+ tb = rl / aspect;
+ else
+ rl = tb * aspect;
+
+ left = -rl;
+ right = rl;
+ bottom = -tb;
+ top = tb;
+
+ rl *= 2;
+ tb *= 2;
+
+ return new x3dom.fields.SFMatrix4f(
+ 2 / rl, 0, 0, -(right+left) / rl,
+ 0, 2 / tb, 0, -(top+bottom) / tb,
+ 0, 0, -2 / fn, -(far+near) / fn,
+ 0, 0, 0, 1
+ );
+};
+
+/**
+ * Sets the translation components of a homogenous transform matrix.
+ * @param {x3dom.fields.SFVec3f} vec - the translation vector
+ */
+x3dom.fields.SFMatrix4f.prototype.setTranslate = function (vec) {
+ this._03 = vec.x;
+ this._13 = vec.y;
+ this._23 = vec.z;
+};
+
+/**
+ * Sets the scale components of a homogenous transform matrix.
+ * @param {x3dom.fields.SFVec3f} vec - vector containing scale factors along the three main axes
+ */
+x3dom.fields.SFMatrix4f.prototype.setScale = function (vec) {
+ this._00 = vec.x;
+ this._11 = vec.y;
+ this._22 = vec.z;
+};
+
+/**
+ * Sets the rotation components of a homogenous transform matrix.
+ * @param {x3dom.fields.Quaternion} quat - quaternion that describes the rotation
+ */
+x3dom.fields.SFMatrix4f.prototype.setRotate = function (quat) {
+ var xx = quat.x * quat.x;
+ var xy = quat.x * quat.y;
+ var xz = quat.x * quat.z;
+ var yy = quat.y * quat.y;
+ var yz = quat.y * quat.z;
+ var zz = quat.z * quat.z;
+ var wx = quat.w * quat.x;
+ var wy = quat.w * quat.y;
+ var wz = quat.w * quat.z;
+
+ this._00 = 1 - 2 * (yy + zz); this._01 = 2 * (xy - wz); this._02 = 2 * (xz + wy);
+ this._10 = 2 * (xy + wz); this._11 = 1 - 2 * (xx + zz); this._12 = 2 * (yz - wx);
+ this._20 = 2 * (xz - wy); this._21 = 2 * (yz + wx); this._22 = 1 - 2 * (xx + yy);
+};
+
+/**
+ * Creates a new matrix from a column major string representation, with values separated by commas
+ * @param {String} str - string to parse
+ * @return {x3dom.fields.SFMatrix4f} the new matrix
+ */
+x3dom.fields.SFMatrix4f.parseRotation = function (str) {
+ var m = /^([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)$/.exec(str);
+ var x = +m[1], y = +m[2], z = +m[3], a = +m[4];
+
+ var d = Math.sqrt(x*x + y*y + z*z);
+ if (d === 0) {
+ x = 1; y = z = 0;
+ } else {
+ x /= d; y /= d; z /= d;
+ }
+
+ var c = Math.cos(a);
+ var s = Math.sin(a);
+ var t = 1 - c;
+
+ return new x3dom.fields.SFMatrix4f(
+ t*x*x+c, t*x*y+s*z, t*x*z-s*y, 0,
+ t*x*y-s*z, t*y*y+c, t*y*z+s*x, 0,
+ t*x*z+s*y, t*y*z-s*x, t*z*z+c, 0,
+ 0, 0, 0, 1
+ ).transpose();
+};
+
+/**
+ * Creates a new matrix from a X3D-conformant string representation
+ * @param {String} str - string to parse
+ * @return {x3dom.fields.SFMatrix4f} the new rotation matrix
+ */
+x3dom.fields.SFMatrix4f.parse = function (str) {
+ var needTranspose = false;
+ var val = /matrix.*\((.+)\)/;
+ if (val.exec(str)) {
+ str = RegExp.$1;
+ needTranspose = true;
+ }
+ var arr = Array.map(str.split(/[,\s]+/), function (n) { return +n; });
+ if (arr.length >= 16)
+ {
+ if (!needTranspose) {
+ return new x3dom.fields.SFMatrix4f(
+ arr[0], arr[1], arr[2], arr[3],
+ arr[4], arr[5], arr[6], arr[7],
+ arr[8], arr[9], arr[10], arr[11],
+ arr[12], arr[13], arr[14], arr[15]
+ );
+ }
+ else {
+ return new x3dom.fields.SFMatrix4f(
+ arr[0], arr[4], arr[8], arr[12],
+ arr[1], arr[5], arr[9], arr[13],
+ arr[2], arr[6], arr[10], arr[14],
+ arr[3], arr[7], arr[11], arr[15]
+ );
+ }
+ }
+ else if (arr.length === 6) {
+ return new x3dom.fields.SFMatrix4f(
+ arr[0], arr[1], 0, arr[4],
+ arr[2], arr[3], 0, arr[5],
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ );
+ }
+ else {
+ x3dom.debug.logWarning("SFMatrix4f - can't parse string: " + str);
+ return x3dom.fields.SFMatrix4f.identity();
+ }
+};
+
+/**
+ * Returns the result of multiplying this matrix with the given one, using "post-multiplication" / "right multiply".
+ * @param {x3dom.fields.SFMatrix4f} that - matrix to multiply with this one
+ * @return {x3dom.fields.SFMatrix4f} resulting matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.mult = function (that) {
+ return new x3dom.fields.SFMatrix4f(
+ this._00*that._00+this._01*that._10+this._02*that._20+this._03*that._30,
+ this._00*that._01+this._01*that._11+this._02*that._21+this._03*that._31,
+ this._00*that._02+this._01*that._12+this._02*that._22+this._03*that._32,
+ this._00*that._03+this._01*that._13+this._02*that._23+this._03*that._33,
+ this._10*that._00+this._11*that._10+this._12*that._20+this._13*that._30,
+ this._10*that._01+this._11*that._11+this._12*that._21+this._13*that._31,
+ this._10*that._02+this._11*that._12+this._12*that._22+this._13*that._32,
+ this._10*that._03+this._11*that._13+this._12*that._23+this._13*that._33,
+ this._20*that._00+this._21*that._10+this._22*that._20+this._23*that._30,
+ this._20*that._01+this._21*that._11+this._22*that._21+this._23*that._31,
+ this._20*that._02+this._21*that._12+this._22*that._22+this._23*that._32,
+ this._20*that._03+this._21*that._13+this._22*that._23+this._23*that._33,
+ this._30*that._00+this._31*that._10+this._32*that._20+this._33*that._30,
+ this._30*that._01+this._31*that._11+this._32*that._21+this._33*that._31,
+ this._30*that._02+this._31*that._12+this._32*that._22+this._33*that._32,
+ this._30*that._03+this._31*that._13+this._32*that._23+this._33*that._33
+ );
+};
+
+/**
+ * Transforms a given 3D point, using this matrix as a homogenous transform matrix
+ * (ignores projection part of matrix for speedup in standard cases).
+ * @param {x3dom.fields.SFVec3f} vec - point to transform
+ * @return {x3dom.fields.SFVec3f} resulting point
+ */
+x3dom.fields.SFMatrix4f.prototype.multMatrixPnt = function (vec) {
+ return new x3dom.fields.SFVec3f(
+ this._00*vec.x + this._01*vec.y + this._02*vec.z + this._03,
+ this._10*vec.x + this._11*vec.y + this._12*vec.z + this._13,
+ this._20*vec.x + this._21*vec.y + this._22*vec.z + this._23
+ );
+};
+
+/**
+ * Transforms a given 3D vector, using this matrix as a homogenous transform matrix.
+ * @param {x3dom.fields.SFVec3f} vec - vector to transform
+ * @return {x3dom.fields.SFVec3f} resulting vector
+ */
+x3dom.fields.SFMatrix4f.prototype.multMatrixVec = function (vec) {
+ return new x3dom.fields.SFVec3f(
+ this._00*vec.x + this._01*vec.y + this._02*vec.z,
+ this._10*vec.x + this._11*vec.y + this._12*vec.z,
+ this._20*vec.x + this._21*vec.y + this._22*vec.z
+ );
+};
+
+/**
+ * Transforms a given 3D point, using this matrix as a transform matrix
+ * (also includes projection part of matrix - required for e.g. modelview-projection matrix).
+ * The resulting point is normalized by a w component.
+ * @param {x3dom.fields.SFVec3f} vec - point to transform
+ * @return {x3dom.fields.SFVec3f} resulting point
+ */
+x3dom.fields.SFMatrix4f.prototype.multFullMatrixPnt = function (vec) {
+ var w = this._30*vec.x + this._31*vec.y + this._32*vec.z + this._33;
+ if (w) { w = 1.0 / w; }
+ return new x3dom.fields.SFVec3f(
+ (this._00*vec.x + this._01*vec.y + this._02*vec.z + this._03) * w,
+ (this._10*vec.x + this._11*vec.y + this._12*vec.z + this._13) * w,
+ (this._20*vec.x + this._21*vec.y + this._22*vec.z + this._23) * w
+ );
+};
+
+
+/**
+ * Transforms a given 3D point, using this matrix as a transform matrix
+ * (also includes projection part of matrix - required for e.g. modelview-projection matrix).
+ * The resulting point is normalized by a w component.
+ * @param {x3dom.fields.SFVec4f} vec - plane to transform
+ * @return {x3dom.fields.SFVec4f} resulting plane
+ */
+x3dom.fields.SFMatrix4f.prototype.multMatrixPlane = function (plane) {
+
+ var normal = new x3dom.fields.SFVec3f(plane.x, plane.y, plane.z);
+
+ var memberPnt = normal.multiply(-plane.w);
+
+ memberPnt = this.multMatrixPnt(memberPnt);
+
+ var invTranspose = this.inverse().transpose();
+
+ normal = invTranspose.multMatrixVec(normal);
+
+ var d = -normal.dot(memberPnt);
+
+ return new x3dom.fields.SFVec4f(normal.x, normal.y, normal.z, d);
+};
+
+/**
+ * Returns a transposed version of this matrix.
+ * @return {x3dom.fields.SFMatrix4f} resulting matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.transpose = function () {
+ return new x3dom.fields.SFMatrix4f(
+ this._00, this._10, this._20, this._30,
+ this._01, this._11, this._21, this._31,
+ this._02, this._12, this._22, this._32,
+ this._03, this._13, this._23, this._33
+ );
+};
+
+/**
+ * Returns a negated version of this matrix.
+ * @return {x3dom.fields.SFMatrix4f} resulting matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.negate = function () {
+ return new x3dom.fields.SFMatrix4f(
+ -this._00, -this._01, -this._02, -this._03,
+ -this._10, -this._11, -this._12, -this._13,
+ -this._20, -this._21, -this._22, -this._23,
+ -this._30, -this._31, -this._32, -this._33
+ );
+};
+
+/**
+ * Returns a scaled version of this matrix.
+ * @param {Number} s - scale factor
+ * @return {x3dom.fields.SFMatrix4f} resulting matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.multiply = function (s) {
+ return new x3dom.fields.SFMatrix4f(
+ s*this._00, s*this._01, s*this._02, s*this._03,
+ s*this._10, s*this._11, s*this._12, s*this._13,
+ s*this._20, s*this._21, s*this._22, s*this._23,
+ s*this._30, s*this._31, s*this._32, s*this._33
+ );
+};
+
+/**
+ * Returns the result of adding the given matrix to this matrix.
+ * @param {x3dom.fields.SFMatrix4f} that - the other matrix
+ * @return {x3dom.fields.SFMatrix4f} resulting matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.add = function (that) {
+ return new x3dom.fields.SFMatrix4f(
+ this._00+that._00, this._01+that._01, this._02+that._02, this._03+that._03,
+ this._10+that._10, this._11+that._11, this._12+that._12, this._13+that._13,
+ this._20+that._20, this._21+that._21, this._22+that._22, this._23+that._23,
+ this._30+that._30, this._31+that._31, this._32+that._32, this._33+that._33
+ );
+};
+
+/**
+ * Returns the result of adding the given matrix to this matrix, using an additional scale factor for the argument matrix.
+ * @param {x3dom.fields.SFMatrix4f} that - the other matrix
+ * @param {Number} s - the scale factor
+ * @return {x3dom.fields.SFMatrix4f} resulting matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.addScaled = function (that, s) {
+ return new x3dom.fields.SFMatrix4f(
+ this._00+s*that._00, this._01+s*that._01, this._02+s*that._02, this._03+s*that._03,
+ this._10+s*that._10, this._11+s*that._11, this._12+s*that._12, this._13+s*that._13,
+ this._20+s*that._20, this._21+s*that._21, this._22+s*that._22, this._23+s*that._23,
+ this._30+s*that._30, this._31+s*that._31, this._32+s*that._32, this._33+s*that._33
+ );
+};
+
+/**
+ * Fills the values of this matrix with the values of the other one.
+ * @param {x3dom.fields.SFMatrix4f} that - the other matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.setValues = function (that) {
+ this._00 = that._00; this._01 = that._01; this._02 = that._02; this._03 = that._03;
+ this._10 = that._10; this._11 = that._11; this._12 = that._12; this._13 = that._13;
+ this._20 = that._20; this._21 = that._21; this._22 = that._22; this._23 = that._23;
+ this._30 = that._30; this._31 = that._31; this._32 = that._32; this._33 = that._33;
+};
+
+/**
+ * Fills the upper left 3x3 or 3x4 values of this matrix, using the given (three or four) column vectors.
+ * @param {x3dom.fields.SFVec3f} v1 - first column vector
+ * @param {x3dom.fields.SFVec3f} v2 - second column vector
+ * @param {x3dom.fields.SFVec3f} v3 - third column vector
+ * @param {x3dom.fields.SFVec3f} [v4=undefined] - fourth column vector
+ */
+x3dom.fields.SFMatrix4f.prototype.setValue = function (v1, v2, v3, v4) {
+ this._00 = v1.x; this._01 = v2.x; this._02 = v3.x;
+ this._10 = v1.y; this._11 = v2.y; this._12 = v3.y;
+ this._20 = v1.z; this._21 = v2.z; this._22 = v3.z;
+ this._30 = 0; this._31 = 0; this._32 = 0;
+
+ if (arguments.length > 3) {
+ this._03 = v4.x;
+ this._13 = v4.y;
+ this._23 = v4.z;
+ this._33 = 1;
+ }
+};
+
+/**
+ * Fills the values of this matrix, using the given array.
+ * @param {Number[]} a - array, the first 16 values will be used to initialize the matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.setFromArray = function (a) {
+ this._00 = a[0]; this._01 = a[4]; this._02 = a[ 8]; this._03 = a[12];
+ this._10 = a[1]; this._11 = a[5]; this._12 = a[ 9]; this._13 = a[13];
+ this._20 = a[2]; this._21 = a[6]; this._22 = a[10]; this._23 = a[14];
+ this._30 = a[3]; this._31 = a[7]; this._32 = a[11]; this._33 = a[15];
+};
+
+/**
+ * Returns a column major version of this matrix, packed into a single array.
+ * @returns {Number[]} resulting array of 16 values
+ */
+x3dom.fields.SFMatrix4f.prototype.toGL = function () {
+ return [
+ this._00, this._10, this._20, this._30,
+ this._01, this._11, this._21, this._31,
+ this._02, this._12, this._22, this._32,
+ this._03, this._13, this._23, this._33
+ ];
+};
+
+/**
+ * Returns the value of this matrix at a given position.
+ * @param {Number} i - row index (starting with 0)
+ * @param {Number} j - column index (starting with 0)
+ * @returns {Number} the value
+ */
+x3dom.fields.SFMatrix4f.prototype.at = function (i, j) {
+ var field = "_" + i + j;
+ return this[field];
+};
+
+/**
+ * Computes the square root of the matrix, assuming that its determinant is greater than zero.
+ * @return {SFMatrix4f} a matrix containing the result
+ */
+x3dom.fields.SFMatrix4f.prototype.sqrt = function () {
+ var Y = x3dom.fields.SFMatrix4f.identity();
+ var result = x3dom.fields.SFMatrix4f.copy(this);
+
+ for (var i=0; i<6; i++)
+ {
+ var iX = result.inverse();
+ var iY = (i == 0) ? x3dom.fields.SFMatrix4f.identity() : Y.inverse();
+
+ var rd = result.det(), yd = Y.det();
+
+ var g = Math.abs( Math.pow(rd * yd, -0.125) );
+ var ig = 1.0 / g;
+
+ result = result.multiply(g);
+ result = result.addScaled(iY, ig);
+ result = result.multiply(0.5);
+
+ Y = Y.multiply(g);
+ Y = Y.addScaled(iX, ig);
+ Y = Y.multiply(0.5);
+ }
+
+ return result;
+};
+
+/**
+ * Returns the largest absolute value of all entries in the matrix.
+ * This is only a helper for calculating log and not the usual Infinity-norm for matrices.
+ * @returns {Number} the largest absolute value
+ */
+x3dom.fields.SFMatrix4f.prototype.normInfinity = function () {
+ var t = 0, m = 0;
+
+ if ((t = Math.abs(this._00)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._01)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._02)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._03)) > m) {
+ m = t;
+ }
+
+ if ((t = Math.abs(this._10)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._11)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._12)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._13)) > m) {
+ m = t;
+ }
+
+ if ((t = Math.abs(this._20)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._21)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._22)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._23)) > m) {
+ m = t;
+ }
+
+ if ((t = Math.abs(this._30)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._31)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._32)) > m) {
+ m = t;
+ }
+ if ((t = Math.abs(this._33)) > m) {
+ m = t;
+ }
+
+ return m;
+};
+
+/**
+ * Returns the 1-norm of the upper left 3x3 part of this matrix.
+ * The 1-norm is also known as maximum absolute column sum norm.
+ * @returns {Number} the resulting number
+ */
+x3dom.fields.SFMatrix4f.prototype.norm1_3x3 = function() {
+ var max = Math.abs(this._00) +
+ Math.abs(this._10) +
+ Math.abs(this._20);
+ var t = 0;
+
+ if ((t = Math.abs(this._01) +
+ Math.abs(this._11) +
+ Math.abs(this._21)) > max) {
+ max = t;
+ }
+
+ if ((t = Math.abs(this._02) +
+ Math.abs(this._12) +
+ Math.abs(this._22)) > max) {
+ max = t;
+ }
+
+ return max;
+};
+
+/**
+ * Returns the infinity-norm of the upper left 3x3 part of this matrix.
+ * The infinity-norm is also known as maximum absolute row sum norm.
+ * @returns {Number} the resulting number
+ */
+x3dom.fields.SFMatrix4f.prototype.normInf_3x3 = function() {
+ var max = Math.abs(this._00) +
+ Math.abs(this._01) +
+ Math.abs(this._02);
+ var t = 0;
+
+ if ((t = Math.abs(this._10) +
+ Math.abs(this._11) +
+ Math.abs(this._12)) > max) {
+ max = t;
+ }
+
+ if ((t = Math.abs(this._20) +
+ Math.abs(this._21) +
+ Math.abs(this._22)) > max) {
+ max = t;
+ }
+
+ return max;
+};
+
+/**
+ * Computes the transposed adjoint of the upper left 3x3 part of this matrix,
+ * and stores it in the upper left part of a new 4x4 identity matrix.
+ * @returns {x3dom.fields.SFMatrix4f} the resulting matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.adjointT_3x3 = function () {
+ var result = x3dom.fields.SFMatrix4f.identity();
+
+ result._00 = this._11 * this._22 - this._12 * this._21;
+ result._01 = this._12 * this._20 - this._10 * this._22;
+ result._02 = this._10 * this._21 - this._11 * this._20;
+
+ result._10 = this._21 * this._02 - this._22 * this._01;
+ result._11 = this._22 * this._00 - this._20 * this._02;
+ result._12 = this._20 * this._01 - this._21 * this._00;
+
+ result._20 = this._01 * this._12 - this._02 * this._11;
+ result._21 = this._02 * this._10 - this._00 * this._12;
+ result._22 = this._00 * this._11 - this._01 * this._10;
+
+ return result;
+};
+
+/**
+ * Checks whether this matrix equals another matrix.
+ * @param {x3dom.fields.SFMatrix4f} that - the other matrix
+ * @returns {Boolean}
+ */
+x3dom.fields.SFMatrix4f.prototype.equals = function (that) {
+ var eps = 0.000000000001;
+ return Math.abs(this._00-that._00) < eps && Math.abs(this._01-that._01) < eps &&
+ Math.abs(this._02-that._02) < eps && Math.abs(this._03-that._03) < eps &&
+ Math.abs(this._10-that._10) < eps && Math.abs(this._11-that._11) < eps &&
+ Math.abs(this._12-that._12) < eps && Math.abs(this._13-that._13) < eps &&
+ Math.abs(this._20-that._20) < eps && Math.abs(this._21-that._21) < eps &&
+ Math.abs(this._22-that._22) < eps && Math.abs(this._23-that._23) < eps &&
+ Math.abs(this._30-that._30) < eps && Math.abs(this._31-that._31) < eps &&
+ Math.abs(this._32-that._32) < eps && Math.abs(this._33-that._33) < eps;
+};
+
+/**
+ * Decomposes the matrix into a translation, rotation, scale,
+ * and scale orientation. Any projection information is discarded.
+ * The decomposition depends upon choice of center point for rotation and scaling,
+ * which is optional as the last parameter.
+ * @param {x3dom.fields.SFVec3f} translation - 3D vector to be filled with the translation values
+ * @param {x3dom.fields.Quaternion} rotation - quaternion to be filled with the rotation values
+ * @param {x3dom.fields.SFVec3f} scaleFactor - 3D vector to be filled with the scale factors
+ * @param {x3dom.fields.Quaternion} scaleOrientation - rotation (quaternion) to be applied before scaling
+ * @param {x3dom.fields.SFVec3f} [center=undefined] - center point for rotation and scaling, if not origin
+ */
+x3dom.fields.SFMatrix4f.prototype.getTransform = function(
+ translation, rotation, scaleFactor, scaleOrientation, center)
+{
+ var m = null;
+
+ if (arguments.length > 4) {
+ m = x3dom.fields.SFMatrix4f.translation(center.negate());
+ m = m.mult(this);
+
+ var c = x3dom.fields.SFMatrix4f.translation(center);
+ m = m.mult(c);
+ }
+ else {
+ m = x3dom.fields.SFMatrix4f.copy(this);
+ }
+
+ var flip = m.decompose(translation, rotation, scaleFactor, scaleOrientation);
+
+ scaleFactor.setValues(scaleFactor.multiply(flip));
+};
+
+/**
+ * Computes the decomposition of the given 4x4 affine matrix M as M = T F R SO S SO^t,
+ * where T is a translation matrix, F is +/- I (a reflection), R is a rotation matrix,
+ * SO is a rotation matrix and S is a (nonuniform) scale matrix.
+ * @param {x3dom.fields.SFVec3f} t - 3D vector to be filled with the translation values
+ * @param {x3dom.fields.Quaternion} r - quaternion to be filled with the rotation values
+ * @param {x3dom.fields.SFVec3f} s - 3D vector to be filled with the scale factors
+ * @param {x3dom.fields.Quaternion} so - rotation (quaternion) to be applied before scaling
+ * @returns {Number} signum of determinant of the transposed adjoint upper 3x3 matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.decompose = function(t, r, s, so)
+{
+ var A = x3dom.fields.SFMatrix4f.copy(this);
+
+ var Q = x3dom.fields.SFMatrix4f.identity(),
+ S = x3dom.fields.SFMatrix4f.identity(),
+ SO = x3dom.fields.SFMatrix4f.identity();
+
+ t.x = A._03;
+ t.y = A._13;
+ t.z = A._23;
+
+ A._03 = 0.0;
+ A._13 = 0.0;
+ A._23 = 0.0;
+
+ A._30 = 0.0;
+ A._31 = 0.0;
+ A._32 = 0.0;
+
+ var det = A.polarDecompose(Q, S);
+ var f = 1.0;
+
+ if (det < 0.0) {
+ Q = Q.negate();
+ f = -1.0;
+ }
+
+ r.setValue(Q);
+
+ S.spectralDecompose(SO, s);
+
+ so.setValue(SO);
+
+ return f;
+};
+
+/**
+ * Performs a polar decomposition of this matrix A into two matrices Q and S, so that A = QS
+ * @param {x3dom.fields.SFMatrix4f} Q - first resulting matrix
+ * @param {x3dom.fields.SFMatrix4f} S - first resulting matrix
+ * @returns {Number} determinant of the transposed adjoint upper 3x3 matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.polarDecompose = function(Q, S)
+{
+ var TOL = 0.000000000001;
+
+ var Mk = this.transpose();
+ var Ek = x3dom.fields.SFMatrix4f.identity();
+
+ var Mk_one = Mk.norm1_3x3();
+ var Mk_inf = Mk.normInf_3x3();
+
+ var MkAdjT;
+ var MkAdjT_one, MkAdjT_inf;
+ var Ek_one, Mk_det;
+
+ do
+ {
+ // compute transpose of adjoint
+ MkAdjT = Mk.adjointT_3x3();
+
+ // Mk_det = det(Mk) -- computed from the adjoint
+ Mk_det = Mk._00 * MkAdjT._00 +
+ Mk._01 * MkAdjT._01 +
+ Mk._02 * MkAdjT._02;
+
+ //TODO: should this be a close to zero test ?
+ if (Mk_det == 0.0)
+ {
+ x3dom.debug.logWarning("polarDecompose: Mk_det == 0.0");
+ break;
+ }
+
+ MkAdjT_one = MkAdjT.norm1_3x3();
+ MkAdjT_inf = MkAdjT.normInf_3x3();
+
+ // compute update factors
+ var gamma = Math.sqrt( Math.sqrt((MkAdjT_one * MkAdjT_inf) /
+ (Mk_one * Mk_inf)) / Math.abs(Mk_det) );
+
+ var g1 = 0.5 * gamma;
+ var g2 = 0.5 / (gamma * Mk_det);
+
+ Ek.setValues(Mk);
+
+ Mk = Mk.multiply (g1); // this does:
+ Mk = Mk.addScaled(MkAdjT, g2); // Mk = g1 * Mk + g2 * MkAdjT
+ Ek = Ek.addScaled(Mk, -1.0); // Ek -= Mk;
+
+ Ek_one = Ek.norm1_3x3();
+ Mk_one = Mk.norm1_3x3();
+ Mk_inf = Mk.normInf_3x3();
+
+ } while (Ek_one > (Mk_one * TOL));
+
+ Q.setValues(Mk.transpose());
+ S.setValues(Mk.mult(this));
+
+ for (var i = 0; i < 3; ++i)
+ {
+ for (var j = i; j < 3; ++j)
+ {
+ S['_'+j+i] = 0.5 * (S['_'+j+i] + S['_'+i+j]);
+ S['_'+i+j] = 0.5 * (S['_'+j+i] + S['_'+i+j]);
+ }
+ }
+
+ return Mk_det;
+};
+
+/**
+ * Performs a spectral decomposition of this matrix.
+ * @param {x3dom.fields.SFMatrix4f} SO - resulting matrix
+ * @param {x3dom.fields.SFVec3f} k - resulting vector
+ */
+x3dom.fields.SFMatrix4f.prototype.spectralDecompose = function(SO, k)
+{
+ var next = [1, 2, 0];
+ var maxIterations = 20;
+ var diag = [this._00, this._11, this._22];
+ var offDiag = [this._12, this._20, this._01];
+
+ for (var iter = 0; iter < maxIterations; ++iter)
+ {
+ var sm = Math.abs(offDiag[0]) + Math.abs(offDiag[1]) + Math.abs(offDiag[2]);
+
+ if (sm == 0) {
+ break;
+ }
+
+ for (var i = 2; i >= 0; --i)
+ {
+ var p = next[i];
+ var q = next[p];
+
+ var absOffDiag = Math.abs(offDiag[i]);
+ var g = 100.0 * absOffDiag;
+
+ if (absOffDiag > 0.0)
+ {
+ var t = 0, h = diag[q] - diag[p];
+ var absh = Math.abs(h);
+
+ if (absh + g == absh)
+ {
+ t = offDiag[i] / h;
+ }
+ else
+ {
+ var theta = 0.5 * h / offDiag[i];
+ t = 1.0 / (Math.abs(theta) + Math.sqrt(theta * theta + 1.0));
+
+ t = theta < 0.0 ? -t : t;
+ }
+
+ var c = 1.0 / Math.sqrt(t * t + 1.0);
+ var s = t * c;
+
+ var tau = s / (c + 1.0);
+ var ta = t * offDiag[i];
+
+ offDiag[i] = 0.0;
+
+ diag[p] -= ta;
+ diag[q] += ta;
+
+ var offDiagq = offDiag[q];
+
+ offDiag[q] -= s * (offDiag[p] + tau * offDiagq);
+ offDiag[p] += s * (offDiagq - tau * offDiag[p]);
+
+ for (var j = 2; j >= 0; --j)
+ {
+ var a = SO['_'+j+p];
+ var b = SO['_'+j+q];
+
+ SO['_'+j+p] -= s * (b + tau * a);
+ SO['_'+j+q] += s * (a - tau * b);
+ }
+ }
+ }
+ }
+
+ k.x = diag[0];
+ k.y = diag[1];
+ k.z = diag[2];
+};
+
+/**
+ * Computes the logarithm of this matrix, assuming that its determinant is greater than zero.
+ * @returns {x3dom.fields.SFMatrix4f} log of matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.log = function () {
+ var maxiter = 12;
+ var eps = 1e-12;
+
+ var A = x3dom.fields.SFMatrix4f.copy(this),
+ Z = x3dom.fields.SFMatrix4f.copy(this);
+
+ // Take repeated square roots to reduce spectral radius
+ Z._00 -= 1;
+ Z._11 -= 1;
+ Z._22 -= 1;
+ Z._33 -= 1;
+
+ var k = 0;
+
+ while (Z.normInfinity() > 0.5)
+ {
+ A = A.sqrt();
+ Z.setValues(A);
+
+ Z._00 -= 1;
+ Z._11 -= 1;
+ Z._22 -= 1;
+ Z._33 -= 1;
+
+ k++;
+ }
+
+ A._00 -= 1;
+ A._11 -= 1;
+ A._22 -= 1;
+ A._33 -= 1;
+
+ A = A.negate();
+ Z.setValues(A);
+
+ var result = x3dom.fields.SFMatrix4f.copy(A);
+ var i = 1;
+
+ while (Z.normInfinity() > eps && i < maxiter)
+ {
+ Z = Z.mult(A);
+ i++;
+
+ result = result.addScaled(Z, 1.0 / i);
+ }
+
+ return result.multiply( -(1 << k) );
+};
+
+/**
+ * Computes the exponential of this matrix.
+ * @returns {x3dom.fields.SFMatrix4f} exp of matrix
+ */
+x3dom.fields.SFMatrix4f.prototype.exp = function () {
+ var q = 6;
+ var A = x3dom.fields.SFMatrix4f.copy(this),
+ D = x3dom.fields.SFMatrix4f.identity(),
+ N = x3dom.fields.SFMatrix4f.identity(),
+ result = x3dom.fields.SFMatrix4f.identity();
+ var k = 0, c = 1.0;
+
+ var j = 1.0 + parseInt(Math.log(A.normInfinity() / 0.693));
+ //var j = 1.0 + (Math.log(A.normInfinity() / 0.693) | 0);
+
+ if (j < 0) {
+ j = 0;
+ }
+
+ A = A.multiply(1.0 / (1 << j));
+
+ for (k = 1; k <= q; k++)
+ {
+ c *= (q - k + 1) / (k * (2 * q - k + 1));
+
+ result = A.mult(result);
+
+ N = N.addScaled(result, c);
+
+ if (k % 2) {
+ D = D.addScaled(result, -c);
+ }
+ else {
+ D = D.addScaled(result, c);
+ }
+ }
+
+ result = D.inverse().mult(N);
+
+ for (k = 0; k < j; k++)
+ {
+ result = result.mult(result);
+ }
+
+ return result;
+};
+
+/**
+ * Computes a determinant for a 3x3 matrix m, given as values in row major order.
+ * @param {Number} a1 - value of m at (0,0)
+ * @param {Number} a2 - value of m at (0,1)
+ * @param {Number} a3 - value of m at (0,2)
+ * @param {Number} b1 - value of m at (1,0)
+ * @param {Number} b2 - value of m at (1,1)
+ * @param {Number} b3 - value of m at (1,2)
+ * @param {Number} c1 - value of m at (2,0)
+ * @param {Number} c2 - value of m at (2,1)
+ * @param {Number} c3 - value of m at (2,2)
+ * @returns {Number} determinant
+ */
+x3dom.fields.SFMatrix4f.prototype.det3 = function (a1, a2, a3, b1, b2, b3, c1, c2, c3) {
+ return ((a1 * b2 * c3) + (a2 * b3 * c1) + (a3 * b1 * c2) -
+ (a1 * b3 * c2) - (a2 * b1 * c3) - (a3 * b2 * c1));
+};
+
+/**
+ * Computes the determinant of this matrix.
+ * @returns {Number} determinant
+ */
+x3dom.fields.SFMatrix4f.prototype.det = function () {
+ var a1 = this._00;
+ var b1 = this._10;
+ var c1 = this._20;
+ var d1 = this._30;
+
+ var a2 = this._01;
+ var b2 = this._11;
+ var c2 = this._21;
+ var d2 = this._31;
+
+ var a3 = this._02;
+ var b3 = this._12;
+ var c3 = this._22;
+ var d3 = this._32;
+
+ var a4 = this._03;
+ var b4 = this._13;
+ var c4 = this._23;
+ var d4 = this._33;
+
+ return (a1 * this.det3(b2, b3, b4, c2, c3, c4, d2, d3, d4) -
+ b1 * this.det3(a2, a3, a4, c2, c3, c4, d2, d3, d4) +
+ c1 * this.det3(a2, a3, a4, b2, b3, b4, d2, d3, d4) -
+ d1 * this.det3(a2, a3, a4, b2, b3, b4, c2, c3, c4));
+};
+
+/**
+ * Computes the inverse of this matrix, given that it is not singular.
+ * @returns {x3dom.fields.SFMatrix4f}
+ */
+x3dom.fields.SFMatrix4f.prototype.inverse = function () {
+ var a1 = this._00;
+ var b1 = this._10;
+ var c1 = this._20;
+ var d1 = this._30;
+
+ var a2 = this._01;
+ var b2 = this._11;
+ var c2 = this._21;
+ var d2 = this._31;
+
+ var a3 = this._02;
+ var b3 = this._12;
+ var c3 = this._22;
+ var d3 = this._32;
+
+ var a4 = this._03;
+ var b4 = this._13;
+ var c4 = this._23;
+ var d4 = this._33;
+
+ var rDet = this.det();
+
+ //if (Math.abs(rDet) < 1e-30)
+ if (rDet == 0)
+ {
+ x3dom.debug.logWarning("Invert matrix: singular matrix, no inverse!");
+ return x3dom.fields.SFMatrix4f.identity();
+ }
+
+ rDet = 1.0 / rDet;
+
+ return new x3dom.fields.SFMatrix4f(
+ +this.det3(b2, b3, b4, c2, c3, c4, d2, d3, d4) * rDet,
+ -this.det3(a2, a3, a4, c2, c3, c4, d2, d3, d4) * rDet,
+ +this.det3(a2, a3, a4, b2, b3, b4, d2, d3, d4) * rDet,
+ -this.det3(a2, a3, a4, b2, b3, b4, c2, c3, c4) * rDet,
+ -this.det3(b1, b3, b4, c1, c3, c4, d1, d3, d4) * rDet,
+ +this.det3(a1, a3, a4, c1, c3, c4, d1, d3, d4) * rDet,
+ -this.det3(a1, a3, a4, b1, b3, b4, d1, d3, d4) * rDet,
+ +this.det3(a1, a3, a4, b1, b3, b4, c1, c3, c4) * rDet,
+ +this.det3(b1, b2, b4, c1, c2, c4, d1, d2, d4) * rDet,
+ -this.det3(a1, a2, a4, c1, c2, c4, d1, d2, d4) * rDet,
+ +this.det3(a1, a2, a4, b1, b2, b4, d1, d2, d4) * rDet,
+ -this.det3(a1, a2, a4, b1, b2, b4, c1, c2, c4) * rDet,
+ -this.det3(b1, b2, b3, c1, c2, c3, d1, d2, d3) * rDet,
+ +this.det3(a1, a2, a3, c1, c2, c3, d1, d2, d3) * rDet,
+ -this.det3(a1, a2, a3, b1, b2, b3, d1, d2, d3) * rDet,
+ +this.det3(a1, a2, a3, b1, b2, b3, c1, c2, c3) * rDet
+ );
+};
+
+/**
+ * Returns an array of 2*3 = 6 euler angles (in radians), assuming that this is a rotation matrix.
+ * The first three and the second three values are alternatives for the three euler angles,
+ * where each of the two cases leads to the same resulting rotation.
+ * @returns {Number[]}
+ */
+x3dom.fields.SFMatrix4f.prototype.getEulerAngles = function() {
+ var theta_1, theta_2, theta;
+ var phi_1, phi_2, phi;
+ var psi_1, psi_2, psi;
+ var cos_theta_1, cos_theta_2;
+
+ if ( Math.abs((Math.abs(this._20) - 1.0)) > 0.0001) {
+ theta_1 = -Math.asin(this._20);
+ theta_2 = Math.PI - theta_1;
+
+ cos_theta_1 = Math.cos(theta_1);
+ cos_theta_2 = Math.cos(theta_2);
+
+ psi_1 = Math.atan2(this._21 / cos_theta_1, this._22 / cos_theta_1);
+ psi_2 = Math.atan2(this._21 / cos_theta_2, this._22 / cos_theta_2);
+
+ phi_1 = Math.atan2(this._10 / cos_theta_1, this._00 / cos_theta_1);
+ phi_2 = Math.atan2(this._10 / cos_theta_2, this._00 / cos_theta_2);
+
+ return [psi_1, theta_1, phi_1,
+ psi_2, theta_2, phi_2];
+ }
+ else {
+ phi = 0;
+
+ if (this._20 == -1.0) {
+ theta = Math.PI / 2.0;
+ psi = phi + Math.atan2(this._01, this._02);
+ }
+ else {
+ theta = -(Math.PI / 2.0);
+ psi = -phi + Math.atan2(-this._01, -this._02);
+ }
+
+ return [psi, theta, phi,
+ psi, theta, phi];
+ }
+};
+
+/**
+ * Converts this matrix to a string representation, where all entries are separated by commas,
+ * and where rows are additionally separated by linebreaks.
+ * @returns {String}
+ */
+x3dom.fields.SFMatrix4f.prototype.toString = function () {
+ return '\n' +
+ this._00.toFixed(6)+', '+this._01.toFixed(6)+', '+
+ this._02.toFixed(6)+', '+this._03.toFixed(6)+', \n'+
+ this._10.toFixed(6)+', '+this._11.toFixed(6)+', '+
+ this._12.toFixed(6)+', '+this._13.toFixed(6)+', \n'+
+ this._20.toFixed(6)+', '+this._21.toFixed(6)+', '+
+ this._22.toFixed(6)+', '+this._23.toFixed(6)+', \n'+
+ this._30.toFixed(6)+', '+this._31.toFixed(6)+', '+
+ this._32.toFixed(6)+', '+this._33.toFixed(6);
+};
+
+/**
+ * Fills the values of this matrix from a string, where the entries are separated
+ * by commas and given in column-major order.
+ * @param {String} str - the string representation
+ */
+x3dom.fields.SFMatrix4f.prototype.setValueByStr = function(str) {
+ var needTranspose = false;
+ var val = /matrix.*\((.+)\)/;
+ // check if matrix is set via CSS string
+ if (val.exec(str)) {
+ str = RegExp.$1;
+ needTranspose = true;
+ }
+ var arr = Array.map(str.split(/[,\s]+/), function (n) { return +n; });
+ if (arr.length >= 16)
+ {
+ if (!needTranspose) {
+ this._00 = arr[0]; this._01 = arr[1]; this._02 = arr[2]; this._03 = arr[3];
+ this._10 = arr[4]; this._11 = arr[5]; this._12 = arr[6]; this._13 = arr[7];
+ this._20 = arr[8]; this._21 = arr[9]; this._22 = arr[10]; this._23 = arr[11];
+ this._30 = arr[12]; this._31 = arr[13]; this._32 = arr[14]; this._33 = arr[15];
+ }
+ else {
+ this._00 = arr[0]; this._01 = arr[4]; this._02 = arr[8]; this._03 = arr[12];
+ this._10 = arr[1]; this._11 = arr[5]; this._12 = arr[9]; this._13 = arr[13];
+ this._20 = arr[2]; this._21 = arr[6]; this._22 = arr[10]; this._23 = arr[14];
+ this._30 = arr[3]; this._31 = arr[7]; this._32 = arr[11]; this._33 = arr[15];
+ }
+ }
+ else if (arr.length === 6) {
+ this._00 = arr[0]; this._01 = arr[1]; this._02 = 0; this._03 = arr[4];
+ this._10 = arr[2]; this._11 = arr[3]; this._12 = 0; this._13 = arr[5];
+ this._20 = 0; this._21 = 0; this._22 = 1; this._23 = 0;
+ this._30 = 0; this._31 = 0; this._32 = 0; this._33 = 1;
+ }
+ else {
+ x3dom.debug.logWarning("SFMatrix4f - can't parse string: " + str);
+ }
+ return this;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** SFVec2f constructor.
+ @class Represents a SFVec2f
+ */
+x3dom.fields.SFVec2f = function(x, y) {
+ if (arguments.length === 0) {
+ this.x = 0;
+ this.y = 0;
+ }
+ else {
+ this.x = x;
+ this.y = y;
+ }
+};
+
+
+x3dom.fields.SFVec2f.copy = function(v) {
+ return new x3dom.fields.SFVec2f(v.x, v.y);
+};
+
+x3dom.fields.SFVec2f.parse = function (str) {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ return new x3dom.fields.SFVec2f(+m[1], +m[2]);
+};
+
+x3dom.fields.SFVec2f.prototype.copy = function() {
+ return x3dom.fields.SFVec2f.copy(this);
+};
+
+x3dom.fields.SFVec2f.prototype.setValues = function (that) {
+ this.x = that.x;
+ this.y = that.y;
+};
+
+x3dom.fields.SFVec2f.prototype.at = function (i) {
+ switch(i) {
+ case 0: return this.x;
+ case 1: return this.y;
+ default: return this.x;
+ }
+};
+
+x3dom.fields.SFVec2f.prototype.add = function (that) {
+ return new x3dom.fields.SFVec2f(this.x+that.x, this.y+that.y);
+};
+
+x3dom.fields.SFVec2f.prototype.subtract = function (that) {
+ return new x3dom.fields.SFVec2f(this.x-that.x, this.y-that.y);
+};
+
+x3dom.fields.SFVec2f.prototype.negate = function () {
+ return new x3dom.fields.SFVec2f(-this.x, -this.y);
+};
+
+x3dom.fields.SFVec2f.prototype.dot = function (that) {
+ return this.x * that.x + this.y * that.y;
+};
+
+x3dom.fields.SFVec2f.prototype.reflect = function (n) {
+ var d2 = this.dot(n)*2;
+ return new x3dom.fields.SFVec2f(this.x-d2*n.x, this.y-d2*n.y);
+};
+
+x3dom.fields.SFVec2f.prototype.normalize = function() {
+ var n = this.length();
+ if (n) { n = 1.0 / n; }
+ return new x3dom.fields.SFVec2f(this.x*n, this.y*n);
+};
+
+x3dom.fields.SFVec2f.prototype.multComponents = function (that) {
+ return new x3dom.fields.SFVec2f(this.x*that.x, this.y*that.y);
+};
+
+x3dom.fields.SFVec2f.prototype.multiply = function (n) {
+ return new x3dom.fields.SFVec2f(this.x*n, this.y*n);
+};
+
+x3dom.fields.SFVec2f.prototype.divide = function (n) {
+ var denom = n ? (1.0 / n) : 1.0;
+ return new x3dom.fields.SFVec2f(this.x*denom, this.y*denom);
+};
+
+x3dom.fields.SFVec2f.prototype.equals = function (that, eps) {
+ return Math.abs(this.x - that.x) < eps &&
+ Math.abs(this.y - that.y) < eps;
+};
+
+x3dom.fields.SFVec2f.prototype.length = function() {
+ return Math.sqrt((this.x*this.x) + (this.y*this.y));
+};
+
+x3dom.fields.SFVec2f.prototype.toGL = function () {
+ return [ this.x, this.y ];
+};
+
+x3dom.fields.SFVec2f.prototype.toString = function () {
+ return this.x + " " + this.y;
+};
+
+x3dom.fields.SFVec2f.prototype.setValueByStr = function(str) {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ this.x = +m[1];
+ this.y = +m[2];
+ return this;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** SFVec3f constructor.
+ @class Represents a SFVec3f
+ */
+x3dom.fields.SFVec3f = function(x, y, z) {
+ if (arguments.length === 0) {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ }
+ else {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+};
+
+x3dom.fields.SFVec3f.NullVector = new x3dom.fields.SFVec3f(0, 0, 0);
+x3dom.fields.SFVec3f.OneVector = new x3dom.fields.SFVec3f(1, 1, 1);
+
+x3dom.fields.SFVec3f.copy = function(v) {
+ return new x3dom.fields.SFVec3f(v.x, v.y, v.z);
+};
+
+x3dom.fields.SFVec3f.MIN = function() {
+ return new x3dom.fields.SFVec3f(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+};
+
+x3dom.fields.SFVec3f.MAX = function() {
+ return new x3dom.fields.SFVec3f(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+};
+
+x3dom.fields.SFVec3f.parse = function (str) {
+ try {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ return new x3dom.fields.SFVec3f(+m[1], +m[2], +m[3]);
+ }
+ catch (e) {
+ // allow automatic type conversion as is convenient for shaders
+ var c = x3dom.fields.SFColor.colorParse(str);
+ return new x3dom.fields.SFVec3f(c.r, c.g, c.b);
+ }
+};
+
+x3dom.fields.SFVec3f.prototype.copy = function() {
+ return x3dom.fields.SFVec3f.copy(this);
+};
+
+x3dom.fields.SFVec3f.prototype.setValues = function (that) {
+ this.x = that.x;
+ this.y = that.y;
+ this.z = that.z;
+};
+
+x3dom.fields.SFVec3f.prototype.at = function (i) {
+ switch(i) {
+ case 0: return this.x;
+ case 1: return this.y;
+ case 2: return this.z;
+ default: return this.x;
+ }
+};
+
+x3dom.fields.SFVec3f.prototype.add = function (that) {
+ return new x3dom.fields.SFVec3f(this.x + that.x, this.y + that.y, this.z + that.z);
+};
+
+x3dom.fields.SFVec3f.prototype.addScaled = function (that, s) {
+ return new x3dom.fields.SFVec3f(this.x + s*that.x, this.y + s*that.y, this.z + s*that.z);
+};
+
+x3dom.fields.SFVec3f.prototype.subtract = function (that) {
+ return new x3dom.fields.SFVec3f(this.x - that.x, this.y - that.y, this.z - that.z);
+};
+
+x3dom.fields.SFVec3f.prototype.negate = function () {
+ return new x3dom.fields.SFVec3f(-this.x, -this.y, -this.z);
+};
+
+x3dom.fields.SFVec3f.prototype.dot = function (that) {
+ return (this.x*that.x + this.y*that.y + this.z*that.z);
+};
+
+x3dom.fields.SFVec3f.prototype.cross = function (that) {
+ return new x3dom.fields.SFVec3f( this.y*that.z - this.z*that.y,
+ this.z*that.x - this.x*that.z,
+ this.x*that.y - this.y*that.x );
+};
+
+x3dom.fields.SFVec3f.prototype.reflect = function (n) {
+ var d2 = this.dot(n)*2;
+ return new x3dom.fields.SFVec3f(this.x - d2*n.x, this.y - d2*n.y, this.z - d2*n.z);
+};
+
+x3dom.fields.SFVec3f.prototype.length = function() {
+ return Math.sqrt((this.x*this.x) + (this.y*this.y) + (this.z*this.z));
+};
+
+x3dom.fields.SFVec3f.prototype.normalize = function() {
+ var n = this.length();
+ if (n) { n = 1.0 / n; }
+ return new x3dom.fields.SFVec3f(this.x*n, this.y*n, this.z*n);
+};
+
+x3dom.fields.SFVec3f.prototype.multComponents = function (that) {
+ return new x3dom.fields.SFVec3f(this.x*that.x, this.y*that.y, this.z*that.z);
+};
+
+x3dom.fields.SFVec3f.prototype.multiply = function (n) {
+ return new x3dom.fields.SFVec3f(this.x*n, this.y*n, this.z*n);
+};
+
+x3dom.fields.SFVec3f.prototype.divide = function (n) {
+ var denom = n ? (1.0 / n) : 1.0;
+ return new x3dom.fields.SFVec3f(this.x*denom, this.y*denom, this.z*denom);
+};
+
+x3dom.fields.SFVec3f.prototype.equals = function (that, eps) {
+ return Math.abs(this.x - that.x) < eps &&
+ Math.abs(this.y - that.y) < eps &&
+ Math.abs(this.z - that.z) < eps;
+};
+
+x3dom.fields.SFVec3f.prototype.toGL = function () {
+ return [ this.x, this.y, this.z ];
+};
+
+x3dom.fields.SFVec3f.prototype.toString = function () {
+ return this.x + " " + this.y + " " + this.z;
+};
+
+x3dom.fields.SFVec3f.prototype.setValueByStr = function(str) {
+ try {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ this.x = +m[1];
+ this.y = +m[2];
+ this.z = +m[3];
+ }
+ catch (e) {
+ // allow automatic type conversion as is convenient for shaders
+ var c = x3dom.fields.SFColor.colorParse(str);
+ this.x = c.r;
+ this.y = c.g;
+ this.z = c.b;
+ }
+ return this;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** SFVec4f constructor.
+ @class Represents a SFVec4f
+ */
+x3dom.fields.SFVec4f = function(x, y, z, w) {
+ if (arguments.length === 0) {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 0;
+ }
+ else {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+};
+
+x3dom.fields.SFVec4f.copy = function(v) {
+ return new x3dom.fields.SFVec4f(v.x, v.y, v.z, v.w);
+};
+
+
+x3dom.fields.SFVec4f.prototype.copy = function() {
+ return x3dom.fields.SFVec4f(this);
+};
+
+x3dom.fields.SFVec4f.parse = function (str) {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ return new x3dom.fields.SFVec4f(+m[1], +m[2], +m[3], +m[4]);
+};
+
+x3dom.fields.SFVec4f.prototype.setValueByStr = function(str) {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ this.x = +m[1];
+ this.y = +m[2];
+ this.z = +m[3];
+ this.w = +m[4];
+ return this;
+};
+
+x3dom.fields.SFVec4f.prototype.toGL = function () {
+ return [ this.x, this.y, this.z, this.w ];
+};
+
+x3dom.fields.SFVec4f.prototype.toString = function () {
+ return this.x + " " + this.y + " " + this.z + " " + this.w;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** Quaternion constructor.
+ @class Represents a Quaternion
+ */
+x3dom.fields.Quaternion = function(x, y, z, w) {
+ if (arguments.length === 0) {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 1;
+ }
+ else {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+};
+
+x3dom.fields.Quaternion.copy = function(v) {
+ return new x3dom.fields.Quaternion(v.x, v.y, v.z, v.w);
+};
+
+x3dom.fields.Quaternion.prototype.multiply = function (that) {
+ return new x3dom.fields.Quaternion(
+ this.w*that.x + this.x*that.w + this.y*that.z - this.z*that.y,
+ this.w*that.y + this.y*that.w + this.z*that.x - this.x*that.z,
+ this.w*that.z + this.z*that.w + this.x*that.y - this.y*that.x,
+ this.w*that.w - this.x*that.x - this.y*that.y - this.z*that.z
+ );
+};
+
+x3dom.fields.Quaternion.parseAxisAngle = function (str) {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ return x3dom.fields.Quaternion.axisAngle(new x3dom.fields.SFVec3f(+m[1], +m[2], +m[3]), +m[4]);
+};
+
+x3dom.fields.Quaternion.axisAngle = function (axis, a) {
+ var t = axis.length();
+
+ if (t > x3dom.fields.Eps)
+ {
+ var s = Math.sin(a/2) / t;
+ var c = Math.cos(a/2);
+ return new x3dom.fields.Quaternion(axis.x*s, axis.y*s, axis.z*s, c);
+ }
+ else
+ {
+ return new x3dom.fields.Quaternion(0, 0, 0, 1);
+ }
+};
+
+x3dom.fields.Quaternion.prototype.copy = function() {
+ return x3dom.fields.Quaternion(this);
+};
+
+x3dom.fields.Quaternion.prototype.toMatrix = function () {
+ var xx = this.x * this.x;
+ var xy = this.x * this.y;
+ var xz = this.x * this.z;
+ var yy = this.y * this.y;
+ var yz = this.y * this.z;
+ var zz = this.z * this.z;
+ var wx = this.w * this.x;
+ var wy = this.w * this.y;
+ var wz = this.w * this.z;
+
+ return new x3dom.fields.SFMatrix4f(
+ 1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy), 0,
+ 2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx), 0,
+ 2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy), 0,
+ 0, 0, 0, 1
+ );
+};
+
+x3dom.fields.Quaternion.prototype.toAxisAngle = function()
+{
+ var x = 0, y = 0, z = 0;
+ var s = 0, a = 0;
+ var that = this;
+
+ if ( this.w > 1 )
+ {
+ that = x3dom.fields.Quaternion.normalize( this );
+ }
+
+ a = 2 * Math.acos( that.w );
+ s = Math.sqrt( 1 - that.w * that.w );
+
+ if ( s == 0 ) //< x3dom.fields.Eps )
+ {
+ x = that.x;
+ y = that.y;
+ z = that.z;
+ }
+ else
+ {
+ x = that.x / s;
+ y = that.y / s;
+ z = that.z / s;
+ }
+
+ return [ new x3dom.fields.SFVec3f(x,y,z), a ];
+};
+
+x3dom.fields.Quaternion.prototype.angle = function()
+{
+ return 2 * Math.acos(this.w);
+};
+
+x3dom.fields.Quaternion.prototype.setValue = function(matrix)
+{
+ var tr, s = 1;
+ var qt = [0, 0, 0];
+
+ var i = 0, j = 0, k = 0;
+ var nxt = [1, 2, 0];
+
+ tr = matrix._00 + matrix._11 + matrix._22;
+
+ if (tr > 0.0)
+ {
+ s = Math.sqrt(tr + 1.0);
+
+ this.w = s * 0.5;
+
+ s = 0.5 / s;
+
+ this.x = (matrix._21 - matrix._12) * s;
+ this.y = (matrix._02 - matrix._20) * s;
+ this.z = (matrix._10 - matrix._01) * s;
+ }
+ else
+ {
+ if (matrix._11 > matrix._00) {
+ i = 1;
+ }
+ else {
+ i = 0;
+ }
+
+ if (matrix._22 > matrix.at(i, i)) {
+ i = 2;
+ }
+
+ j = nxt[i];
+ k = nxt[j];
+
+ s = Math.sqrt(matrix.at(i, i) - (matrix.at(j, j) + matrix.at(k, k)) + 1.0);
+
+ qt[i] = s * 0.5;
+ s = 0.5 / s;
+
+ this.w = (matrix.at(k, j) - matrix.at(j, k)) * s;
+
+ qt[j] = (matrix.at(j, i) + matrix.at(i, j)) * s;
+ qt[k] = (matrix.at(k, i) + matrix.at(i, k)) * s;
+
+ this.x = qt[0];
+ this.y = qt[1];
+ this.z = qt[2];
+ }
+
+ if (this.w > 1.0 || this.w < -1.0)
+ {
+ var errThreshold = 1 + (x3dom.fields.Eps * 100);
+
+ if (this.w > errThreshold || this.w < -errThreshold)
+ {
+ // When copying, then everything, incl. the famous OpenSG MatToQuat bug
+ x3dom.debug.logInfo("MatToQuat: BUG: |quat[4]| (" + this.w +") >> 1.0 !");
+ }
+
+ if (this.w > 1.0) {
+ this.w = 1.0;
+ }
+ else {
+ this.w = -1.0;
+ }
+ }
+};
+
+x3dom.fields.Quaternion.prototype.setFromEuler = function (alpha, beta, gamma) {
+ var sx = Math.sin(alpha * 0.5);
+ var cx = Math.cos(alpha * 0.5);
+ var sy = Math.sin(beta * 0.5);
+ var cy = Math.cos(beta * 0.5);
+ var sz = Math.sin(gamma * 0.5);
+ var cz = Math.cos(gamma * 0.5);
+
+ this.x = (sx * cy * cz) - (cx * sy * sz);
+ this.y = (cx * sy * cz) + (sx * cy * sz);
+ this.z = (cx * cy * sz) - (sx * sy * cz);
+ this.w = (cx * cy * cz) + (sx * sy * sz);
+};
+
+x3dom.fields.Quaternion.prototype.dot = function (that) {
+ return this.x*that.x + this.y*that.y + this.z*that.z + this.w*that.w;
+};
+
+x3dom.fields.Quaternion.prototype.add = function (that) {
+ return new x3dom.fields.Quaternion(this.x + that.x, this.y + that.y, this.z + that.z, this.w + that.w);
+};
+
+x3dom.fields.Quaternion.prototype.subtract = function (that) {
+ return new x3dom.fields.Quaternion(this.x - that.x, this.y - that.y, this.z - that.z, this.w - that.w);
+};
+
+x3dom.fields.Quaternion.prototype.setValues = function (that) {
+ this.x = that.x;
+ this.y = that.y;
+ this.z = that.z;
+ this.w = that.w;
+};
+
+x3dom.fields.Quaternion.prototype.equals = function (that, eps) {
+ return (this.dot(that) >= 1.0 - eps);
+};
+
+x3dom.fields.Quaternion.prototype.multScalar = function (s) {
+ return new x3dom.fields.Quaternion(this.x*s, this.y*s, this.z*s, this.w*s);
+};
+
+x3dom.fields.Quaternion.prototype.normalize = function (that) {
+ var d2 = this.dot(that);
+ var id = 1.0;
+ if (d2) { id = 1.0 / Math.sqrt(d2); }
+ return new x3dom.fields.Quaternion(this.x*id, this.y*id, this.z*id, this.w*id);
+};
+
+x3dom.fields.Quaternion.prototype.negate = function() {
+ return new x3dom.fields.Quaternion(-this.x, -this.y, -this.z, -this.w);
+};
+
+x3dom.fields.Quaternion.prototype.inverse = function () {
+ return new x3dom.fields.Quaternion(-this.x, -this.y, -this.z, this.w);
+};
+
+x3dom.fields.Quaternion.prototype.slerp = function (that, t) {
+ // calculate the cosine
+ var cosom = this.dot(that);
+ var rot1;
+
+ // adjust signs if necessary
+ if (cosom < 0.0)
+ {
+ cosom = -cosom;
+ rot1 = that.negate();
+ }
+ else
+ {
+ rot1 = new x3dom.fields.Quaternion(that.x, that.y, that.z, that.w);
+ }
+
+ // calculate interpolating coeffs
+ var scalerot0, scalerot1;
+
+ if ((1.0 - cosom) > 0.00001)
+ {
+ // standard case
+ var omega = Math.acos(cosom);
+ var sinom = Math.sin(omega);
+ scalerot0 = Math.sin((1.0 - t) * omega) / sinom;
+ scalerot1 = Math.sin(t * omega) / sinom;
+ }
+ else
+ {
+ // rot0 and rot1 very close - just do linear interp.
+ scalerot0 = 1.0 - t;
+ scalerot1 = t;
+ }
+
+ // build the new quaternion
+ return this.multScalar(scalerot0).add(rot1.multScalar(scalerot1));
+};
+
+x3dom.fields.Quaternion.rotateFromTo = function (fromVec, toVec) {
+ var from = fromVec.normalize();
+ var to = toVec.normalize();
+ var cost = from.dot(to);
+
+ // check for degeneracies
+ if (cost > 0.99999)
+ {
+ // vectors are parallel
+ return new x3dom.fields.Quaternion(0, 0, 0, 1);
+ }
+ else if (cost < -0.99999)
+ {
+ // vectors are opposite
+ // find an axis to rotate around, which should be
+ // perpendicular to the original axis
+ // Try cross product with (1,0,0) first, if that's one of our
+ // original vectors then try (0,1,0).
+ var cAxis = new x3dom.fields.SFVec3f(1, 0, 0);
+
+ var tmp = from.cross(cAxis);
+
+ if (tmp.length() < 0.00001)
+ {
+ cAxis.x = 0;
+ cAxis.y = 1;
+ cAxis.z = 0;
+
+ tmp = from.cross(cAxis);
+ }
+ tmp = tmp.normalize();
+
+ return x3dom.fields.Quaternion.axisAngle(tmp, Math.PI);
+ }
+
+ var axis = fromVec.cross(toVec);
+ axis = axis.normalize();
+
+ // use half-angle formulae
+ // sin^2 t = ( 1 - cos (2t) ) / 2
+ var s = Math.sqrt(0.5 * (1.0 - cost));
+ axis = axis.multiply(s);
+
+ // scale the axis by the sine of half the rotation angle to get
+ // the normalized quaternion
+ // cos^2 t = ( 1 + cos (2t) ) / 2
+ // w part is cosine of half the rotation angle
+ s = Math.sqrt(0.5 * (1.0 + cost));
+
+ return new x3dom.fields.Quaternion(axis.x, axis.y, axis.z, s);
+};
+
+x3dom.fields.Quaternion.prototype.toGL = function () {
+ var val = this.toAxisAngle();
+ return [ val[0].x, val[0].y, val[0].z, val[1] ];
+};
+
+x3dom.fields.Quaternion.prototype.toString = function () {
+ return this.x + " " + this.y + " " + this.z + ", " + this.w;
+};
+
+x3dom.fields.Quaternion.prototype.setValueByStr = function(str) {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ var quat = x3dom.fields.Quaternion.axisAngle(new x3dom.fields.SFVec3f(+m[1], +m[2], +m[3]), +m[4]);
+ this.x = quat.x;
+ this.y = quat.y;
+ this.z = quat.z;
+ this.w = quat.w;
+ return this;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** SFColor constructor.
+ @class Represents a SFColor
+ */
+x3dom.fields.SFColor = function(r, g, b) {
+ if (arguments.length === 0) {
+ this.r = 0;
+ this.g = 0;
+ this.b = 0;
+ }
+ else {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+};
+
+x3dom.fields.SFColor.parse = function(str) {
+ try {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ return new x3dom.fields.SFColor( +m[1], +m[2], +m[3] );
+ }
+ catch (e) {
+ return x3dom.fields.SFColor.colorParse(str);
+ }
+};
+
+x3dom.fields.SFColor.copy = function(that) {
+ return new x3dom.fields.SFColor(that.r, that.g, that.b);
+};
+
+x3dom.fields.SFColor.prototype.copy = function() {
+ return x3dom.fields.SFColor.copy(this);
+};
+
+x3dom.fields.SFColor.prototype.setHSV = function (h, s, v) {
+ x3dom.debug.logWarning("SFColor.setHSV() NYI");
+};
+
+x3dom.fields.SFColor.prototype.getHSV = function () {
+ var h = 0, s = 0, v = 0;
+ x3dom.debug.logWarning("SFColor.getHSV() NYI");
+ return [ h, s, v ];
+};
+
+x3dom.fields.SFColor.prototype.setValues = function (color) {
+ this.r = color.r;
+ this.g = color.g;
+ this.b = color.b;
+};
+
+x3dom.fields.SFColor.prototype.equals = function (that, eps) {
+ return Math.abs(this.r - that.r) < eps &&
+ Math.abs(this.g - that.g) < eps &&
+ Math.abs(this.b - that.b) < eps;
+};
+
+x3dom.fields.SFColor.prototype.add = function (that) {
+ return new x3dom.fields.SFColor(this.r + that.r, this.g + that.g, this.b + that.b);
+};
+
+x3dom.fields.SFColor.prototype.subtract = function (that) {
+ return new x3dom.fields.SFColor(this.r - that.r, this.g - that.g, this.b - that.b);
+};
+
+x3dom.fields.SFColor.prototype.multiply = function (n) {
+ return new x3dom.fields.SFColor(this.r*n, this.g*n, this.b*n);
+};
+
+x3dom.fields.SFColor.prototype.toGL = function () {
+ return [ this.r, this.g, this.b ];
+};
+
+x3dom.fields.SFColor.prototype.toString = function() {
+ return this.r + " " + this.g + " " + this.b;
+};
+
+x3dom.fields.SFColor.prototype.setValueByStr = function(str) {
+ try {
+ var m = /^\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*$/.exec(str);
+ this.r = +m[1];
+ this.g = +m[2];
+ this.b = +m[3];
+ }
+ catch (e) {
+ var c = x3dom.fields.SFColor.colorParse(str);
+ this.r = c.r;
+ this.g = c.g;
+ this.b = c.b;
+ }
+ return this;
+};
+
+x3dom.fields.SFColor.colorParse = function(color) {
+ var red = 0, green = 0, blue = 0;
+
+ // definition of css color names
+ var color_names = {
+ aliceblue: 'f0f8ff', antiquewhite: 'faebd7', aqua: '00ffff',
+ aquamarine: '7fffd4', azure: 'f0ffff', beige: 'f5f5dc',
+ bisque: 'ffe4c4', black: '000000', blanchedalmond: 'ffebcd',
+ blue: '0000ff', blueviolet: '8a2be2', brown: 'a52a2a',
+ burlywood: 'deb887', cadetblue: '5f9ea0', chartreuse: '7fff00',
+ chocolate: 'd2691e', coral: 'ff7f50', cornflowerblue: '6495ed',
+ cornsilk: 'fff8dc', crimson: 'dc143c', cyan: '00ffff',
+ darkblue: '00008b', darkcyan: '008b8b', darkgoldenrod: 'b8860b',
+ darkgray: 'a9a9a9', darkgreen: '006400', darkkhaki: 'bdb76b',
+ darkmagenta: '8b008b', darkolivegreen: '556b2f',darkorange: 'ff8c00',
+ darkorchid: '9932cc', darkred: '8b0000', darksalmon: 'e9967a',
+ darkseagreen: '8fbc8f', darkslateblue: '483d8b',darkslategray: '2f4f4f',
+ darkturquoise: '00ced1',darkviolet: '9400d3', deeppink: 'ff1493',
+ deepskyblue: '00bfff', dimgray: '696969', dodgerblue: '1e90ff',
+ feldspar: 'd19275', firebrick: 'b22222', floralwhite: 'fffaf0',
+ forestgreen: '228b22', fuchsia: 'ff00ff', gainsboro: 'dcdcdc',
+ ghostwhite: 'f8f8ff', gold: 'ffd700', goldenrod: 'daa520',
+ gray: '808080', green: '008000', greenyellow: 'adff2f',
+ honeydew: 'f0fff0', hotpink: 'ff69b4', indianred : 'cd5c5c',
+ indigo : '4b0082', ivory: 'fffff0', khaki: 'f0e68c',
+ lavender: 'e6e6fa', lavenderblush: 'fff0f5',lawngreen: '7cfc00',
+ lemonchiffon: 'fffacd', lightblue: 'add8e6', lightcoral: 'f08080',
+ lightcyan: 'e0ffff', lightgoldenrodyellow: 'fafad2', lightgrey: 'd3d3d3',
+ lightgreen: '90ee90', lightpink: 'ffb6c1', lightsalmon: 'ffa07a',
+ lightseagreen: '20b2aa',lightskyblue: '87cefa', lightslateblue: '8470ff',
+ lightslategray: '778899',lightsteelblue: 'b0c4de',lightyellow: 'ffffe0',
+ lime: '00ff00', limegreen: '32cd32', linen: 'faf0e6',
+ magenta: 'ff00ff', maroon: '800000', mediumaquamarine: '66cdaa',
+ mediumblue: '0000cd', mediumorchid: 'ba55d3', mediumpurple: '9370d8',
+ mediumseagreen: '3cb371',mediumslateblue: '7b68ee', mediumspringgreen: '00fa9a',
+ mediumturquoise: '48d1cc',mediumvioletred: 'c71585',midnightblue: '191970',
+ mintcream: 'f5fffa', mistyrose: 'ffe4e1', moccasin: 'ffe4b5',
+ navajowhite: 'ffdead', navy: '000080', oldlace: 'fdf5e6',
+ olive: '808000', olivedrab: '6b8e23', orange: 'ffa500',
+ orangered: 'ff4500', orchid: 'da70d6', palegoldenrod: 'eee8aa',
+ palegreen: '98fb98', paleturquoise: 'afeeee',palevioletred: 'd87093',
+ papayawhip: 'ffefd5', peachpuff: 'ffdab9', peru: 'cd853f',
+ pink: 'ffc0cb', plum: 'dda0dd', powderblue: 'b0e0e6',
+ purple: '800080', red: 'ff0000', rosybrown: 'bc8f8f',
+ royalblue: '4169e1', saddlebrown: '8b4513', salmon: 'fa8072',
+ sandybrown: 'f4a460', seagreen: '2e8b57', seashell: 'fff5ee',
+ sienna: 'a0522d', silver: 'c0c0c0', skyblue: '87ceeb',
+ slateblue: '6a5acd', slategray: '708090', snow: 'fffafa',
+ springgreen: '00ff7f', steelblue: '4682b4', tan: 'd2b48c',
+ teal: '008080', thistle: 'd8bfd8', tomato: 'ff6347',
+ turquoise: '40e0d0', violet: 'ee82ee', violetred: 'd02090',
+ wheat: 'f5deb3', white: 'ffffff', whitesmoke: 'f5f5f5',
+ yellow: 'ffff00', yellowgreen: '9acd32'
+ };
+
+ if (color_names[color]) {
+ // first check if color is given as colorname
+ color = "#" + color_names[color];
+ }
+
+ if (color.substr && color.substr(0,1) === "#") {
+ color = color.substr(1);
+ var len = color.length;
+
+ if (len === 6) {
+ red = parseInt("0x"+color.substr(0,2), 16) / 255.0;
+ green = parseInt("0x"+color.substr(2,2), 16) / 255.0;
+ blue = parseInt("0x"+color.substr(4,2), 16) / 255.0;
+ }
+ else if (len === 3) {
+ red = parseInt("0x"+color.substr(0,1), 16) / 15.0;
+ green = parseInt("0x"+color.substr(1,1), 16) / 15.0;
+ blue = parseInt("0x"+color.substr(2,1), 16) / 15.0;
+ }
+ }
+
+ return new x3dom.fields.SFColor( red, green, blue );
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** SFColorRGBA constructor.
+ @class Represents a SFColorRGBA
+ */
+x3dom.fields.SFColorRGBA = function(r, g, b, a) {
+ if (arguments.length === 0) {
+ this.r = 0;
+ this.g = 0;
+ this.b = 0;
+ this.a = 1;
+ }
+ else {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+ }
+};
+
+x3dom.fields.SFColorRGBA.parse = function(str) {
+ try {
+ var m = /^([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)$/.exec(str);
+ return new x3dom.fields.SFColorRGBA( +m[1], +m[2], +m[3], +m[4] );
+ }
+ catch (e) {
+ return x3dom.fields.SFColorRGBA.colorParse(str);
+ }
+};
+
+x3dom.fields.SFColorRGBA.copy = function(that) {
+ return new x3dom.fields.SFColorRGBA(that.r, that.g, that.b, that.a);
+};
+
+x3dom.fields.SFColorRGBA.prototype.copy = function() {
+ return x3dom.fields.SFColorRGBA.copy(this);
+};
+
+x3dom.fields.SFColorRGBA.prototype.setValues = function (color) {
+ this.r = color.r;
+ this.g = color.g;
+ this.b = color.b;
+ this.a = color.a;
+};
+
+x3dom.fields.SFColorRGBA.prototype.equals = function (that, eps) {
+ return Math.abs(this.r - that.r) < eps &&
+ Math.abs(this.g - that.g) < eps &&
+ Math.abs(this.b - that.b) < eps &&
+ Math.abs(this.a - that.a) < eps;
+};
+
+x3dom.fields.SFColorRGBA.prototype.toGL = function () {
+ return [ this.r, this.g, this.b, this.a ];
+};
+
+x3dom.fields.SFColorRGBA.prototype.toString = function() {
+ return this.r + " " + this.g + " " + this.b + " " + this.a;
+};
+
+x3dom.fields.SFColorRGBA.prototype.setValueByStr = function(str) {
+ try {
+ var m = /^([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)\s*,?\s*([+\-]?\d*\.*\d*[eE]?[+\-]?\d*?)$/.exec(str);
+ this.r = +m[1];
+ this.g = +m[2];
+ this.b = +m[3];
+ this.a = +m[4];
+ }
+ catch (e) {
+ var c = x3dom.fields.SFColorRGBA.colorParse(str);
+ this.r = c.r;
+ this.g = c.g;
+ this.b = c.b;
+ this.a = c.a;
+ }
+ return this;
+};
+
+x3dom.fields.SFColorRGBA.prototype.toUint = function() {
+ return ((Math.round(this.r * 255) << 24) |
+ (Math.round(this.g * 255) << 16) |
+ (Math.round(this.b * 255) << 8) |
+ Math.round(this.a * 255)) >>> 0;
+};
+
+x3dom.fields.SFColorRGBA.colorParse = function(color) {
+ var red = 0, green = 0, blue = 0, alpha = 0;
+
+ // definition of css color names
+ var color_names = {
+ aliceblue: 'f0f8ff', antiquewhite: 'faebd7', aqua: '00ffff',
+ aquamarine: '7fffd4', azure: 'f0ffff', beige: 'f5f5dc',
+ bisque: 'ffe4c4', black: '000000', blanchedalmond: 'ffebcd',
+ blue: '0000ff', blueviolet: '8a2be2', brown: 'a52a2a',
+ burlywood: 'deb887', cadetblue: '5f9ea0', chartreuse: '7fff00',
+ chocolate: 'd2691e', coral: 'ff7f50', cornflowerblue: '6495ed',
+ cornsilk: 'fff8dc', crimson: 'dc143c', cyan: '00ffff',
+ darkblue: '00008b', darkcyan: '008b8b', darkgoldenrod: 'b8860b',
+ darkgray: 'a9a9a9', darkgreen: '006400', darkkhaki: 'bdb76b',
+ darkmagenta: '8b008b', darkolivegreen: '556b2f',darkorange: 'ff8c00',
+ darkorchid: '9932cc', darkred: '8b0000', darksalmon: 'e9967a',
+ darkseagreen: '8fbc8f', darkslateblue: '483d8b',darkslategray: '2f4f4f',
+ darkturquoise: '00ced1',darkviolet: '9400d3', deeppink: 'ff1493',
+ deepskyblue: '00bfff', dimgray: '696969', dodgerblue: '1e90ff',
+ feldspar: 'd19275', firebrick: 'b22222', floralwhite: 'fffaf0',
+ forestgreen: '228b22', fuchsia: 'ff00ff', gainsboro: 'dcdcdc',
+ ghostwhite: 'f8f8ff', gold: 'ffd700', goldenrod: 'daa520',
+ gray: '808080', green: '008000', greenyellow: 'adff2f',
+ honeydew: 'f0fff0', hotpink: 'ff69b4', indianred : 'cd5c5c',
+ indigo : '4b0082', ivory: 'fffff0', khaki: 'f0e68c',
+ lavender: 'e6e6fa', lavenderblush: 'fff0f5',lawngreen: '7cfc00',
+ lemonchiffon: 'fffacd', lightblue: 'add8e6', lightcoral: 'f08080',
+ lightcyan: 'e0ffff', lightgoldenrodyellow: 'fafad2', lightgrey: 'd3d3d3',
+ lightgreen: '90ee90', lightpink: 'ffb6c1', lightsalmon: 'ffa07a',
+ lightseagreen: '20b2aa',lightskyblue: '87cefa', lightslateblue: '8470ff',
+ lightslategray: '778899',lightsteelblue: 'b0c4de',lightyellow: 'ffffe0',
+ lime: '00ff00', limegreen: '32cd32', linen: 'faf0e6',
+ magenta: 'ff00ff', maroon: '800000', mediumaquamarine: '66cdaa',
+ mediumblue: '0000cd', mediumorchid: 'ba55d3', mediumpurple: '9370d8',
+ mediumseagreen: '3cb371',mediumslateblue: '7b68ee', mediumspringgreen: '00fa9a',
+ mediumturquoise: '48d1cc',mediumvioletred: 'c71585',midnightblue: '191970',
+ mintcream: 'f5fffa', mistyrose: 'ffe4e1', moccasin: 'ffe4b5',
+ navajowhite: 'ffdead', navy: '000080', oldlace: 'fdf5e6',
+ olive: '808000', olivedrab: '6b8e23', orange: 'ffa500',
+ orangered: 'ff4500', orchid: 'da70d6', palegoldenrod: 'eee8aa',
+ palegreen: '98fb98', paleturquoise: 'afeeee',palevioletred: 'd87093',
+ papayawhip: 'ffefd5', peachpuff: 'ffdab9', peru: 'cd853f',
+ pink: 'ffc0cb', plum: 'dda0dd', powderblue: 'b0e0e6',
+ purple: '800080', red: 'ff0000', rosybrown: 'bc8f8f',
+ royalblue: '4169e1', saddlebrown: '8b4513', salmon: 'fa8072',
+ sandybrown: 'f4a460', seagreen: '2e8b57', seashell: 'fff5ee',
+ sienna: 'a0522d', silver: 'c0c0c0', skyblue: '87ceeb',
+ slateblue: '6a5acd', slategray: '708090', snow: 'fffafa',
+ springgreen: '00ff7f', steelblue: '4682b4', tan: 'd2b48c',
+ teal: '008080', thistle: 'd8bfd8', tomato: 'ff6347',
+ turquoise: '40e0d0', violet: 'ee82ee', violetred: 'd02090',
+ wheat: 'f5deb3', white: 'ffffff', whitesmoke: 'f5f5f5',
+ yellow: 'ffff00', yellowgreen: '9acd32'
+ };
+
+ if (color_names[color]) {
+ // first check if color is given as colorname
+ color = "#" + color_names[color] + "ff";
+ }
+
+ if (color.substr && color.substr(0,1) === "#") {
+ color = color.substr(1);
+ var len = color.length;
+
+ if (len === 8) {
+ red = parseInt("0x"+color.substr(0,2), 16) / 255.0;
+ green = parseInt("0x"+color.substr(2,2), 16) / 255.0;
+ blue = parseInt("0x"+color.substr(4,2), 16) / 255.0;
+ alpha = parseInt("0x"+color.substr(6,2), 16) / 255.0;
+ }
+ else if (len === 6) {
+ red = parseInt("0x"+color.substr(0,2), 16) / 255.0;
+ green = parseInt("0x"+color.substr(2,2), 16) / 255.0;
+ blue = parseInt("0x"+color.substr(4,2), 16) / 255.0;
+ alpha = 1.0;
+ }
+ else if (len === 4) {
+ red = parseInt("0x"+color.substr(0,1), 16) / 15.0;
+ green = parseInt("0x"+color.substr(1,1), 16) / 15.0;
+ blue = parseInt("0x"+color.substr(2,1), 16) / 15.0;
+ alpha = parseInt("0x"+color.substr(3,1), 16) / 15.0;
+ }
+ else if (len === 3) {
+ red = parseInt("0x"+color.substr(0,1), 16) / 15.0;
+ green = parseInt("0x"+color.substr(1,1), 16) / 15.0;
+ blue = parseInt("0x"+color.substr(2,1), 16) / 15.0;
+ alpha = 1.0;
+ }
+ }
+
+ return new x3dom.fields.SFColorRGBA( red, green, blue, alpha );
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** SFImage constructor.
+ @class Represents an SFImage
+ */
+x3dom.fields.SFImage = function(w, h, c, arr) {
+ if (arguments.length === 0 || !(arr && arr.map)) {
+ this.width = 0;
+ this.height = 0;
+ this.comp = 0;
+ this.array = [];
+ }
+ else {
+ this.width = w;
+ this.height = h;
+ this.comp = c;
+ var that = this.array;
+ arr.map( function(v) { that.push(v); }, this.array );
+ }
+};
+
+x3dom.fields.SFImage.parse = function(str) {
+ var img = new x3dom.fields.SFImage();
+ img.setValueByStr(str);
+ return img;
+};
+
+x3dom.fields.SFImage.copy = function(that) {
+ var destination = new x3dom.fields.SFImage();
+ destination.width = that.width;
+ destination.height = that.height;
+ destination.comp = that.comp;
+ destination.setPixels(that.array);
+ return destination;
+};
+
+x3dom.fields.SFImage.prototype.copy = function() {
+ return x3dom.fields.SFImage.copy(this);
+};
+
+x3dom.fields.SFImage.prototype.setValueByStr = function(str) {
+ var mc = str.match(/(\w+)/g);
+ var n = mc.length;
+ var c2 = 0;
+ var hex = "0123456789ABCDEF";
+
+ this.array = [];
+
+ if (n > 2) {
+ this.width = +mc[0];
+ this.height = +mc[1];
+ this.comp = +mc[2];
+ c2 = 2 * this.comp;
+ } else {
+ this.width = 0;
+ this.height = 0;
+ this.comp = 0;
+ return;
+ }
+
+ var len, i;
+ for (i=3; i<n; i++) {
+ var r, g, b, a;
+
+ if (!mc[i].substr) {
+ continue;
+ }
+
+ if (mc[i].substr(1,1).toLowerCase() !== "x") {
+ // Maybe optimize by directly parsing value!
+ var inp = parseInt(mc[i], 10);
+
+ if (this.comp === 1) {
+ r = inp;
+ this.array.push( r );
+ }
+ else if (this.comp === 2) {
+ r = inp >> 8 & 255;
+ g = inp & 255;
+ this.array.push( r, g );
+ }
+ else if (this.comp === 3) {
+ r = inp >> 16 & 255;
+ g = inp >> 8 & 255;
+ b = inp & 255;
+ this.array.push( r, g, b );
+ }
+ else if (this.comp === 4) {
+ r = inp >> 24 & 255;
+ g = inp >> 16 & 255;
+ b = inp >> 8 & 255;
+ a = inp & 255;
+ this.array.push( r, g, b, a );
+ }
+ }
+ else if (mc[i].substr(1,1).toLowerCase() === "x") {
+ mc[i] = mc[i].substr(2);
+ len = mc[i].length;
+
+ if (len === c2) {
+ if (this.comp === 1) {
+ r = parseInt("0x"+mc[i].substr(0,2), 16);
+ this.array.push( r );
+ }
+ else if (this.comp === 2) {
+ r = parseInt("0x"+mc[i].substr(0,2), 16);
+ g = parseInt("0x"+mc[i].substr(2,2), 16);
+ this.array.push( r, g );
+ }
+ else if (this.comp === 3) {
+ r = parseInt("0x"+mc[i].substr(0,2), 16);
+ g = parseInt("0x"+mc[i].substr(2,2), 16);
+ b = parseInt("0x"+mc[i].substr(4,2), 16);
+ this.array.push( r, g, b );
+ }
+ else if (this.comp === 4) {
+ r = parseInt("0x"+mc[i].substr(0,2), 16);
+ g = parseInt("0x"+mc[i].substr(2,2), 16);
+ b = parseInt("0x"+mc[i].substr(4,2), 16);
+ a = parseInt("0x"+mc[i].substr(6,2), 16);
+ this.array.push( r, g, b, a );
+ }
+ }
+ }
+ }
+};
+
+x3dom.fields.SFImage.prototype.setPixel = function(x, y, color) {
+ var startIdx = (y * this.width + x) * this.comp;
+
+ if (this.comp === 1 && startIdx < this.array.length) {
+ this.array[startIdx] = color.r * 255;
+ }
+ else if (this.comp === 2 && (startIdx+1) < this.array.length) {
+ this.array[startIdx ] = color.r * 255;
+ this.array[startIdx+1] = color.g * 255;
+ }
+ else if (this.comp === 3 && (startIdx+2) < this.array.length) {
+ this.array[startIdx ] = color.r * 255;
+ this.array[startIdx+1] = color.g * 255;
+ this.array[startIdx+2] = color.b * 255;
+ }
+ else if (this.comp === 4 && (startIdx+3) < this.array.length) {
+ this.array[startIdx ] = color.r * 255;
+ this.array[startIdx+1] = color.g * 255;
+ this.array[startIdx+2] = color.b * 255;
+ this.array[startIdx+3] = color.a * 255;
+ }
+};
+
+x3dom.fields.SFImage.prototype.getPixel = function(x, y) {
+ var startIdx = (y * this.width + x) * this.comp;
+
+ if (this.comp === 1 && startIdx < this.array.length) {
+ return new x3dom.fields.SFColorRGBA(this.array[startIdx] / 255,
+ 0,
+ 0,
+ 1);
+ }
+ else if (this.comp === 2 && (startIdx+1) < this.array.length) {
+ return new x3dom.fields.SFColorRGBA(this.array[startIdx] / 255,
+ this.array[startIdx+1] / 255,
+ 0,
+ 1);
+ }
+ else if (this.comp === 3 && (startIdx+2) < this.array.length) {
+ return new x3dom.fields.SFColorRGBA(this.array[startIdx] / 255,
+ this.array[startIdx+1] / 255,
+ this.array[startIdx+2] / 255,
+ 1);
+ }
+ else if (this.comp === 4 && (startIdx+3) < this.array.length) {
+ return new x3dom.fields.SFColorRGBA(this.array[startIdx] / 255,
+ this.array[startIdx+1] / 255,
+ this.array[startIdx+2] / 255,
+ this.array[startIdx+3] / 255);
+ }
+};
+
+x3dom.fields.SFImage.prototype.setPixels = function(pixels) {
+
+ var i, idx = 0;
+
+ if (this.comp === 1) {
+ for(i=0; i<pixels.length; i++) {
+ this.array[idx++] = pixels[i].r * 255;
+ }
+ }
+ else if (this.comp === 2) {
+ for(i=0; i<pixels.length; i++) {
+ this.array[idx++] = pixels[i].r * 255;
+ this.array[idx++] = pixels[i].g * 255;
+ }
+ }
+ else if (this.comp === 3) {
+ for(i=0; i<pixels.length; i++) {
+ this.array[idx++] = pixels[i].r * 255;
+ this.array[idx++] = pixels[i].g * 255;
+ this.array[idx++] = pixels[i].b * 255;
+ }
+ }
+ else if (this.comp === 4) {
+ for(i=0; i<pixels.length; i++) {
+ this.array[idx++] = pixels[i].r * 255;
+ this.array[idx++] = pixels[i].g * 255;
+ this.array[idx++] = pixels[i].b * 255;
+ this.array[idx++] = pixels[i].a * 255;
+ }
+ }
+};
+
+x3dom.fields.SFImage.prototype.getPixels = function() {
+ var i;
+ var pixels = [];
+
+ if (this.comp === 1) {
+ for (i=0; i<this.array.length; i+=this.comp){
+ pixels.push(new x3dom.fields.SFColorRGBA(this.array[i] / 255,
+ 0,
+ 0,
+ 1));
+ }
+ }
+ else if (this.comp === 2) {
+ for (i=0; i<this.array.length; i+=this.comp) {
+ pixels.push(new x3dom.fields.SFColorRGBA(this.array[i ] / 255,
+ this.array[i + 1] / 255,
+ 0,
+ 1));
+ }
+ }
+ else if (this.comp === 3) {
+ for (i=0; i<this.array.length; i+=this.comp) {
+ pixels.push(new x3dom.fields.SFColorRGBA(this.array[i ] / 255,
+ this.array[i + 1] / 255,
+ this.array[i + 2] / 255,
+ 1));
+ }
+ }
+ else if (this.comp === 4) {
+ for (i=0; i<this.array.length; i+=this.comp) {
+ pixels.push(new x3dom.fields.SFColorRGBA(this.array[i ] / 255,
+ this.array[i + 1] / 255,
+ this.array[i + 2] / 255,
+ this.array[i + 3] / 255));
+ }
+ }
+
+ return pixels;
+};
+
+x3dom.fields.SFImage.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this.array, function(c) {
+ a.push(c);
+ });
+
+ return a;
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Multi-Field Definitions
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFColor constructor.
+ @class Represents a MFColor
+ */
+x3dom.fields.MFColor = function(colorArray) {
+
+ if (colorArray) {
+ var that = this;
+ colorArray.map( function(c) { that.push(c); }, this );
+ }
+};
+
+x3dom.fields.MFColor.copy = function(colorArray) {
+ var destination = new x3dom.fields.MFColor();
+ colorArray.map( function(v) { destination.push(v.copy()); }, this );
+ return destination;
+};
+
+x3dom.fields.MFColor.prototype = x3dom.extend([]);
+
+x3dom.fields.MFColor.parse = function(str) {
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ var colors = [];
+ for (var i=0, n=mc?mc.length:0; i<n; i+=3) {
+ colors.push( new x3dom.fields.SFColor(+mc[i+0], +mc[i+1], +mc[i+2]) );
+ }
+
+ return new x3dom.fields.MFColor( colors );
+};
+
+x3dom.fields.MFColor.prototype.copy = function() {
+ return x3dom.fields.MFColor.copy(this);
+};
+
+x3dom.fields.MFColor.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ for (var i=0, n=mc?mc.length:0; i<n; i+=3) {
+ this.push( new x3dom.fields.SFColor(+mc[i+0], +mc[i+1], +mc[i+2]) );
+ }
+};
+
+x3dom.fields.MFColor.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(c) {
+ a.push(c.r);
+ a.push(c.g);
+ a.push(c.b);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFColorRGBA constructor.
+ @class Represents a MFColorRGBA
+ */
+x3dom.fields.MFColorRGBA = function(colorArray) {
+ if (colorArray) {
+ var that = this;
+ colorArray.map( function(c) { that.push(c); }, this );
+ }
+};
+
+x3dom.fields.MFColorRGBA.copy = function(colorArray) {
+ var destination = new x3dom.fields.MFColorRGBA();
+ colorArray.map( function(v) { destination.push(v.copy()); }, this );
+ return destination;
+};
+
+x3dom.fields.MFColorRGBA.prototype = x3dom.extend([]);
+
+x3dom.fields.MFColorRGBA.parse = function(str) {
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ var colors = [];
+ for (var i=0, n=mc?mc.length:0; i<n; i+=4) {
+ colors.push( new x3dom.fields.SFColorRGBA(+mc[i+0], +mc[i+1], +mc[i+2], +mc[i+3]) );
+ }
+
+ return new x3dom.fields.MFColorRGBA( colors );
+};
+
+x3dom.fields.MFColorRGBA.prototype.copy = function() {
+ return x3dom.fields.MFColorRGBA.copy(this);
+};
+
+x3dom.fields.MFColorRGBA.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ for (var i=0, n=mc?mc.length:0; i<n; i+=4) {
+ this.push( new x3dom.fields.SFColorRGBA(+mc[i+0], +mc[i+1], +mc[i+2], +mc[i+3]) );
+ }
+};
+
+x3dom.fields.MFColorRGBA.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(c) {
+ a.push(c.r);
+ a.push(c.g);
+ a.push(c.b);
+ a.push(c.a);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFRotation constructor.
+ @class Represents a MFRotation
+ */
+x3dom.fields.MFRotation = function(rotArray) {
+ if (rotArray) {
+ var that = this;
+ rotArray.map( function(v) { that.push(v); }, this );
+ }
+};
+
+x3dom.fields.MFRotation.prototype = x3dom.extend([]);
+
+x3dom.fields.MFRotation.copy = function(rotationArray) {
+ var destination = new x3dom.fields.MFRotation();
+ rotationArray.map( function(v) { destination.push(v.copy()); }, this );
+ return destination;
+};
+
+x3dom.fields.MFRotation.prototype.copy = function() {
+ return x3dom.fields.MFRotation.copy(this);
+};
+
+x3dom.fields.MFRotation.parse = function(str) {
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ var vecs = [];
+ for (var i=0, n=mc?mc.length:0; i<n; i+=4) {
+ vecs.push( x3dom.fields.Quaternion.axisAngle(new x3dom.fields.SFVec3f(+mc[i+0], +mc[i+1], +mc[i+2]), +mc[i+3]) );
+ }
+
+ // holds the quaternion representation as needed by interpolators etc.
+ return new x3dom.fields.MFRotation( vecs );
+};
+
+x3dom.fields.MFRotation.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ for (var i=0, n=mc?mc.length:0; i<n; i+=4) {
+ this.push( x3dom.fields.Quaternion.axisAngle(new x3dom.fields.SFVec3f(+mc[i+0], +mc[i+1], +mc[i+2]), +mc[i+3]) );
+ }
+};
+
+x3dom.fields.MFRotation.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(c) {
+ var val = c.toAxisAngle();
+ a.push(val[0].x);
+ a.push(val[0].y);
+ a.push(val[0].z);
+ a.push(val[1]);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFVec3f constructor.
+ @class Represents a MFVec3f
+ */
+x3dom.fields.MFVec3f = function(vec3Array) {
+ if (vec3Array) {
+ var that = this;
+ vec3Array.map( function(v) { that.push(v); }, this );
+ }
+};
+
+x3dom.fields.MFVec3f.prototype = x3dom.extend([]);
+
+x3dom.fields.MFVec3f.copy = function(vec3Array) {
+ var destination = new x3dom.fields.MFVec3f();
+ vec3Array.map( function(v) { destination.push(v.copy()); }, this );
+ return destination;
+};
+
+x3dom.fields.MFVec3f.parse = function(str) {
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ var vecs = [];
+ for (var i=0, n=mc?mc.length:0; i<n; i+=3) {
+ vecs.push( new x3dom.fields.SFVec3f(+mc[i+0], +mc[i+1], +mc[i+2]) );
+ }
+
+ return new x3dom.fields.MFVec3f( vecs );
+};
+
+x3dom.fields.MFVec3f.prototype.copy = function()
+{
+ x3dom.fields.MFVec3f.copy(this);
+};
+
+x3dom.fields.MFVec3f.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ for (var i=0, n=mc?mc.length:0; i<n; i+=3) {
+ this.push( new x3dom.fields.SFVec3f(+mc[i+0], +mc[i+1], +mc[i+2]) );
+ }
+};
+
+x3dom.fields.MFVec3f.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(c) {
+ a.push(c.x);
+ a.push(c.y);
+ a.push(c.z);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFVec2f constructor.
+ @class Represents a MFVec2f
+ */
+x3dom.fields.MFVec2f = function(vec2Array) {
+ if (vec2Array) {
+ var that = this;
+ vec2Array.map( function(v) { that.push(v); }, this );
+ }
+};
+
+x3dom.fields.MFVec2f.prototype = x3dom.extend([]);
+
+x3dom.fields.MFVec2f.copy = function(vec2Array) {
+ var destination = new x3dom.fields.MFVec2f();
+ vec2Array.map( function(v) { destination.push(v.copy()); }, this );
+ return destination;
+};
+
+x3dom.fields.MFVec2f.parse = function(str) {
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ var vecs = [];
+ for (var i=0, n=mc?mc.length:0; i<n; i+=2) {
+ vecs.push( new x3dom.fields.SFVec2f(+mc[i+0], +mc[i+1]) );
+ }
+
+ return new x3dom.fields.MFVec2f( vecs );
+};
+
+x3dom.fields.MFVec2f.prototype.copy = function() {
+ return x3dom.fields.MFVec2f.copy(this);
+};
+
+x3dom.fields.MFVec2f.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ for (var i=0, n=mc?mc.length:0; i<n; i+=2) {
+ this.push( new x3dom.fields.SFVec2f(+mc[i+0], +mc[i+1]) );
+ }
+};
+
+x3dom.fields.MFVec2f.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(v) {
+ a.push(v.x);
+ a.push(v.y);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFInt32 constructor.
+ @class Represents a MFInt32
+ */
+x3dom.fields.MFInt32 = function(array) {
+ if (array) {
+ var that = this;
+ array.map( function(v) { that.push(v); }, this );
+ }
+};
+
+x3dom.fields.MFInt32.prototype = x3dom.extend([]);
+
+x3dom.fields.MFInt32.copy = function(intArray) {
+ var destination = new x3dom.fields.MFInt32();
+ intArray.map( function(v) { destination.push(v); }, this );
+ return destination;
+};
+
+x3dom.fields.MFInt32.parse = function(str) {
+ var mc = str.match(/([+\-]?\d+\s*){1},?\s*/g);
+ var vals = [];
+ for (var i=0, n=mc?mc.length:0; i<n; ++i) {
+ vals.push( parseInt(mc[i], 10) );
+ }
+
+ return new x3dom.fields.MFInt32( vals );
+};
+
+x3dom.fields.MFInt32.prototype.copy = function() {
+ return x3dom.fields.MFInt32.copy(this);
+};
+
+x3dom.fields.MFInt32.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/([+\-]?\d+\s*){1},?\s*/g);
+ for (var i=0, n=mc?mc.length:0; i<n; ++i) {
+ this.push( parseInt(mc[i], 10) );
+ }
+};
+
+x3dom.fields.MFInt32.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(v) {
+ a.push(v);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFFloat constructor.
+ @class Represents a MFFloat
+ */
+x3dom.fields.MFFloat = function(array) {
+ if (array) {
+ var that = this;
+ array.map( function(v) { that.push(v); }, this );
+ }
+};
+
+x3dom.fields.MFFloat.prototype = x3dom.extend([]);
+
+x3dom.fields.MFFloat.copy = function(floatArray) {
+ var destination = new x3dom.fields.MFFloat();
+ floatArray.map( function(v) { destination.push(v); }, this );
+ return destination;
+};
+
+x3dom.fields.MFFloat.parse = function(str) {
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ var vals = [];
+ for (var i=0, n=mc?mc.length:0; i<n; i++) {
+ vals.push( +mc[i] );
+ }
+
+ return new x3dom.fields.MFFloat( vals );
+};
+
+x3dom.fields.MFFloat.prototype.copy = function() {
+ return x3dom.fields.MFFloat.copy(this);
+};
+
+x3dom.fields.MFFloat.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/([+\-0-9eE\.]+)/g);
+ for (var i=0, n=mc?mc.length:0; i<n; i++) {
+ this.push( +mc[i] );
+ }
+};
+
+x3dom.fields.MFFloat.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(v) {
+ a.push(v);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFBoolean constructor.
+ @class Represents a MFBoolean
+ */
+x3dom.fields.MFBoolean = function(array) {
+ if (array) {
+ var that = this;
+ array.map( function(v) { that.push(v); }, this );
+ }
+};
+
+x3dom.fields.MFBoolean.prototype = x3dom.extend([]);
+
+x3dom.fields.MFBoolean.copy = function(boolArray) {
+ var destination = new x3dom.fields.MFBoolean();
+ boolArray.map( function(v) { destination.push(v); }, this );
+ return destination;
+};
+
+x3dom.fields.MFBoolean.parse = function(str) {
+ var mc = str.match(/(true|false|1|0)/ig);
+ var vals = [];
+ for (var i=0, n=mc?mc.length:0; i<n; i++) {
+ vals.push( (mc[i] == '1' || mc[i].toLowerCase() == 'true') );
+ }
+
+ return new x3dom.fields.MFBoolean( vals );
+};
+
+x3dom.fields.MFBoolean.prototype.copy = function() {
+ return x3dom.fields.MFBoolean.copy(this);
+};
+
+x3dom.fields.MFBoolean.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ var mc = str.match(/(true|false|1|0)/ig);
+ for (var i=0, n=mc?mc.length:0; i<n; i++) {
+ this.push( (mc[i] == '1' || mc[i].toLowerCase() == 'true') );
+ }
+};
+
+x3dom.fields.MFBoolean.prototype.toGL = function() {
+ var a = [];
+
+ Array.map( this, function(v) {
+ a.push(v ? 1 : 0);
+ });
+
+ return a;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFString constructor.
+ @class Represents a MFString
+ */
+x3dom.fields.MFString = function(strArray) {
+ if (strArray && strArray.map) {
+ var that = this;
+ strArray.map( function(v) { that.push(v); }, this );
+ }
+};
+
+x3dom.fields.MFString.prototype = x3dom.extend([]);
+
+x3dom.fields.MFString.copy = function(stringArray) {
+ var destination = new x3dom.fields.MFString();
+ stringArray.map( function(v) { destination.push(v); }, this );
+ return destination;
+};
+
+x3dom.fields.MFString.parse = function(str) {
+ var arr = [];
+ // ignore leading whitespace?
+ if (str.length && str[0] == '"') {
+ var m, re = /"((?:[^\\"]|\\\\|\\")*)"/g;
+ while ((m = re.exec(str))) {
+ var s = m[1].replace(/\\([\\"])/, "$1");
+ if (s !== undefined) {
+ arr.push(s);
+ }
+ }
+ }
+ else {
+ arr.push(str);
+ }
+ return new x3dom.fields.MFString( arr );
+};
+
+x3dom.fields.MFString.prototype.copy = function() {
+ return x3dom.fields.MFString.copy(this);
+};
+
+x3dom.fields.MFString.prototype.setValueByStr = function(str) {
+ this.length = 0;
+ // ignore leading whitespace?
+ if (str.length && str[0] == '"') {
+ var m, re = /"((?:[^\\"]|\\\\|\\")*)"/g;
+ while ((m = re.exec(str))) {
+ var s = m[1].replace(/\\([\\"])/, "$1");
+ if (s !== undefined) {
+ this.push(s);
+ }
+ }
+ }
+ else {
+ this.push(str);
+ }
+ return this;
+};
+
+x3dom.fields.MFString.prototype.toString = function () {
+ var str = "";
+ for (var i=0, n=this.length; i<n; i++) {
+ str = str + this[i] + " ";
+ }
+ return str;
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Single-/Multi-Field Node Definitions
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+/** SFNode constructor.
+ @class Represents a SFNode
+ */
+x3dom.fields.SFNode = function(type) {
+ this.type = type;
+ this.node = null;
+};
+
+x3dom.fields.SFNode.prototype.hasLink = function(node) {
+ return (node ? (this.node === node) : this.node);
+};
+
+x3dom.fields.SFNode.prototype.addLink = function(node) {
+ this.node = node;
+ return true;
+};
+
+x3dom.fields.SFNode.prototype.rmLink = function(node) {
+ if (this.node === node) {
+ this.node = null;
+ return true;
+ }
+ else {
+ return false;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** MFNode constructor.
+ @class Represents a MFNode
+ */
+x3dom.fields.MFNode = function(type) {
+ this.type = type;
+ this.nodes = [];
+};
+
+x3dom.fields.MFNode.prototype.hasLink = function(node) {
+ if (node) {
+ for (var i = 0, n = this.nodes.length; i < n; i++) {
+ if (this.nodes[i] === node) {
+ return true;
+ }
+ }
+ }
+ else {
+ return (this.length > 0);
+ }
+ return false;
+};
+
+x3dom.fields.MFNode.prototype.addLink = function(node) {
+ this.nodes.push (node);
+ return true;
+};
+
+x3dom.fields.MFNode.prototype.rmLink = function(node) {
+ for (var i = 0, n = this.nodes.length; i < n; i++) {
+ if (this.nodes[i] === node) {
+ this.nodes.splice(i,1);
+ return true;
+ }
+ }
+ return false;
+};
+
+x3dom.fields.MFNode.prototype.length = function() {
+ return this.nodes.length;
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Math Helper Class Definitions
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Line constructor.
+ * @param {SFVec3f} pos - anchor point of the line
+ * @param {SFVec3f} dir - direction of the line, must be normalized
+ * @class Represents a Line (as internal helper).
+ * A line has an origin and a vector that describes a direction, it is infinite in both directions.
+ */
+x3dom.fields.Line = function(pos, dir)
+{
+ if (arguments.length === 0)
+ {
+ this.pos = new x3dom.fields.SFVec3f(0, 0, 0);
+ this.dir = new x3dom.fields.SFVec3f(0, 0, 1);
+ }
+
+ this.pos = x3dom.fields.SFVec3f.copy(pos);
+ this.dir = x3dom.fields.SFVec3f.copy(dir);
+};
+
+/**
+ * For a given point, this function returns the closest point on this line.
+ * @param p {x3dom.fields.SFVec3f} - the point
+ * @returns {x3dom.fields.SFVec3f} the closest point
+ */
+x3dom.fields.Line.prototype.closestPoint = function(p)
+{
+ var distVec = p.subtract(this.pos);
+
+ //project the distance vector on the line
+ var projDist = distVec.dot(this.dir);
+
+ return this.pos.add(this.dir.multiply(projDist));
+};
+
+/**
+ * For a given point, this function returns the distance to the closest point on this line.
+ * @param p {x3dom.fields.SFVec3f} - the point
+ * @returns {Number} the distance to the closest point
+ */
+x3dom.fields.Line.prototype.shortestDistance = function(p)
+{
+ var distVec = p.subtract(this.pos);
+
+ //project the distance vector on the line
+ var projDist = distVec.dot(this.dir);
+
+ //subtract the projected distance vector, to obtain the part that is orthogonal to this line
+ return distVec.subtract(this.dir.multiply(projDist)).length();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Ray constructor.
+ * @param {SFVec3f} pos - anchor point of the ray
+ * @param {SFVec3f} dir - direction of the ray, must be normalized
+ * @class Represents a Ray (as internal helper).
+ * A ray is a special line that extends to only one direction from its origin.
+ */
+x3dom.fields.Ray = function(pos, dir)
+{
+ if (arguments.length === 0)
+ {
+ this.pos = new x3dom.fields.SFVec3f(0, 0, 0);
+ this.dir = new x3dom.fields.SFVec3f(0, 0, 1);
+ }
+ else
+ {
+ this.pos = new x3dom.fields.SFVec3f(pos.x, pos.y, pos.z);
+
+ var n = dir.length();
+ if (n) { n = 1.0 / n; }
+
+ this.dir = new x3dom.fields.SFVec3f(dir.x*n, dir.y*n, dir.z*n);
+ }
+
+ this.enter = 0;
+ this.exit = 0;
+ this.hitObject = null;
+ this.hitPoint = {};
+ this.dist = Number.MAX_VALUE;
+};
+
+x3dom.fields.Ray.prototype.toString = function () {
+ return 'Ray: [' + this.pos.toString() + '; ' + this.dir.toString() + ']';
+};
+
+/**
+ * Intersects this ray with a plane, defined by the given anchor point and normal.
+ * The result returned is the point of intersection, if any. If no point of intersection exists, null is returned.
+ * Null is also returned in case there is an infinite number of solutions (, i.e., if the ray origin lies in the plane).
+ *
+ * @param p {x3dom.fields.SFVec3f} - anchor point
+ * @param n {x3dom.fields.SFVec3f} - plane normal
+ * @returns {x3dom.fields.SFVec3f} the point of intersection, can be null
+ */
+x3dom.fields.Ray.prototype.intersectPlane = function(p, n)
+{
+ var result = null;
+
+ var alpha; //ray parameter, should be computed
+
+ var nDotDir = n.dot(this.dir);
+
+ //if the ray hits the plane, the plane normal and ray direction must be facing each other
+ if (nDotDir < 0.0)
+ {
+ alpha = (p.dot(n) - this.pos.dot(n)) / nDotDir;
+
+ result = this.pos.addScaled(this.dir, alpha);
+ }
+
+ return result;
+};
+
+/** intersect line with box volume given by low and high */
+x3dom.fields.Ray.prototype.intersect = function(low, high)
+{
+ var isect = 0.0;
+ var out = Number.MAX_VALUE;
+ var r, te, tl;
+
+ if (this.dir.x > x3dom.fields.Eps)
+ {
+ r = 1.0 / this.dir.x;
+
+ te = (low.x - this.pos.x) * r;
+ tl = (high.x - this.pos.x) * r;
+
+ if (tl < out){
+ out = tl;
+ }
+
+ if (te > isect){
+ isect = te;
+ }
+ }
+ else if (this.dir.x < -x3dom.fields.Eps)
+ {
+ r = 1.0 / this.dir.x;
+
+ te = (high.x - this.pos.x) * r;
+ tl = (low.x - this.pos.x) * r;
+
+ if (tl < out){
+ out = tl;
+ }
+
+ if (te > isect) {
+ isect = te;
+ }
+ }
+ else if (this.pos.x < low.x || this.pos.x > high.x)
+ {
+ return false;
+ }
+
+ if (this.dir.y > x3dom.fields.Eps)
+ {
+ r = 1.0 / this.dir.y;
+
+ te = (low.y - this.pos.y) * r;
+ tl = (high.y - this.pos.y) * r;
+
+ if (tl < out){
+ out = tl;
+ }
+
+ if (te > isect) {
+ isect = te;
+ }
+
+ if (isect-out >= x3dom.fields.Eps) {
+ return false;
+ }
+ }
+ else if (this.dir.y < -x3dom.fields.Eps)
+ {
+ r = 1.0 / this.dir.y;
+
+ te = (high.y - this.pos.y) * r;
+ tl = (low.y - this.pos.y) * r;
+
+ if (tl < out){
+ out = tl;
+ }
+
+ if (te > isect) {
+ isect = te;
+ }
+
+ if (isect-out >= x3dom.fields.Eps) {
+ return false;
+ }
+ }
+ else if (this.pos.y < low.y || this.pos.y > high.y)
+ {
+ return false;
+ }
+
+ if (this.dir.z > x3dom.fields.Eps)
+ {
+ r = 1.0 / this.dir.z;
+
+ te = (low.z - this.pos.z) * r;
+ tl = (high.z - this.pos.z) * r;
+
+ if (tl < out) {
+ out = tl;
+ }
+
+ if (te > isect) {
+ isect = te;
+ }
+ }
+ else if (this.dir.z < -x3dom.fields.Eps)
+ {
+ r = 1.0 / this.dir.z;
+
+ te = (high.z - this.pos.z) * r;
+ tl = (low.z - this.pos.z) * r;
+
+ if (tl < out) {
+ out = tl;
+ }
+
+ if (te > isect) {
+ isect = te;
+ }
+ }
+ else if (this.pos.z < low.z || this.pos.z > high.z)
+ {
+ return false;
+ }
+
+ this.enter = isect;
+ this.exit = out;
+
+ return (isect-out < x3dom.fields.Eps);
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** BoxVolume constructor.
+ @class Represents a box volume (as internal helper).
+ */
+x3dom.fields.BoxVolume = function(min, max)
+{
+ if (arguments.length < 2) {
+ this.min = new x3dom.fields.SFVec3f(0, 0, 0);
+ this.max = new x3dom.fields.SFVec3f(0, 0, 0);
+ this.valid = false;
+ }
+ else {
+ // compiler enforced type check for min/max would be nice
+ this.min = x3dom.fields.SFVec3f.copy(min);
+ this.max = x3dom.fields.SFVec3f.copy(max);
+ this.valid = true;
+ }
+
+ this.updateInternals();
+};
+
+x3dom.fields.BoxVolume.prototype.getScalarValue = function()
+{
+ var extent = this.max.subtract(this.min);
+
+ return (extent.x*extent.y*extent.z);
+};
+
+x3dom.fields.BoxVolume.copy = function(other)
+{
+ return new x3dom.fields.BoxVolume(other.min, other.max);
+};
+
+x3dom.fields.BoxVolume.prototype.updateInternals = function()
+{
+ this.radialVec = this.max.subtract(this.min).multiply(0.5);
+ this.center = this.min.add(this.radialVec);
+ this.diameter = 2 * this.radialVec.length();
+};
+
+x3dom.fields.BoxVolume.prototype.setBounds = function(min, max)
+{
+ this.min.setValues(min);
+ this.max.setValues(max);
+
+ this.updateInternals();
+ this.valid = true;
+};
+
+x3dom.fields.BoxVolume.prototype.setBoundsByCenterSize = function(center, size)
+{
+ var halfSize = size.multiply(0.5);
+ this.min = center.subtract(halfSize);
+ this.max = center.add(halfSize);
+
+ this.updateInternals();
+ this.valid = true;
+};
+
+x3dom.fields.BoxVolume.prototype.extendBounds = function(min, max)
+{
+ if (this.valid)
+ {
+ if (this.min.x > min.x) { this.min.x = min.x; }
+ if (this.min.y > min.y) { this.min.y = min.y; }
+ if (this.min.z > min.z) { this.min.z = min.z; }
+
+ if (this.max.x < max.x) { this.max.x = max.x; }
+ if (this.max.y < max.y) { this.max.y = max.y; }
+ if (this.max.z < max.z) { this.max.z = max.z; }
+
+ this.updateInternals();
+ }
+ else
+ {
+ this.setBounds(min, max);
+ }
+};
+
+x3dom.fields.BoxVolume.prototype.getBounds = function(min, max)
+{
+ min.setValues(this.min);
+ max.setValues(this.max);
+};
+
+x3dom.fields.BoxVolume.prototype.getRadialVec = function()
+{
+ return this.radialVec;
+};
+
+x3dom.fields.BoxVolume.prototype.invalidate = function()
+{
+ this.valid = false;
+ this.min = new x3dom.fields.SFVec3f(0, 0, 0);
+ this.max = new x3dom.fields.SFVec3f(0, 0, 0);
+};
+
+x3dom.fields.BoxVolume.prototype.isValid = function()
+{
+ return this.valid;
+};
+
+x3dom.fields.BoxVolume.prototype.getCenter = function()
+{
+ return this.center;
+};
+
+x3dom.fields.BoxVolume.prototype.getDiameter = function()
+{
+ return this.diameter;
+};
+
+x3dom.fields.BoxVolume.prototype.transform = function(m)
+{
+ var xmin, ymin, zmin;
+ var xmax, ymax, zmax;
+
+ xmin = xmax = m._03;
+ ymin = ymax = m._13;
+ zmin = zmax = m._23;
+
+ // calculate xmin and xmax of new transformed BBox
+ var a = this.max.x * m._00;
+ var b = this.min.x * m._00;
+
+ if (a >= b) {
+ xmax += a;
+ xmin += b;
+ }
+ else {
+ xmax += b;
+ xmin += a;
+ }
+
+ a = this.max.y * m._01;
+ b = this.min.y * m._01;
+
+ if (a >= b) {
+ xmax += a;
+ xmin += b;
+ }
+ else {
+ xmax += b;
+ xmin += a;
+ }
+
+ a = this.max.z * m._02;
+ b = this.min.z * m._02;
+
+ if (a >= b) {
+ xmax += a;
+ xmin += b;
+ }
+ else {
+ xmax += b;
+ xmin += a;
+ }
+
+ // calculate ymin and ymax of new transformed BBox
+ a = this.max.x * m._10;
+ b = this.min.x * m._10;
+
+ if (a >= b) {
+ ymax += a;
+ ymin += b;
+ }
+ else {
+ ymax += b;
+ ymin += a;
+ }
+
+ a = this.max.y * m._11;
+ b = this.min.y * m._11;
+
+ if (a >= b) {
+ ymax += a;
+ ymin += b;
+ }
+ else {
+ ymax += b;
+ ymin += a;
+ }
+
+ a = this.max.z * m._12;
+ b = this.min.z * m._12;
+
+ if (a >= b) {
+ ymax += a;
+ ymin += b;
+ }
+ else {
+ ymax += b;
+ ymin += a;
+ }
+
+ // calculate zmin and zmax of new transformed BBox
+ a = this.max.x * m._20;
+ b = this.min.x * m._20;
+
+ if (a >= b) {
+ zmax += a;
+ zmin += b;
+ }
+ else {
+ zmax += b;
+ zmin += a;
+ }
+
+ a = this.max.y * m._21;
+ b = this.min.y * m._21;
+
+ if (a >= b) {
+ zmax += a;
+ zmin += b;
+ }
+ else {
+ zmax += b;
+ zmin += a;
+ }
+
+ a = this.max.z * m._22;
+ b = this.min.z * m._22;
+
+ if (a >= b) {
+ zmax += a;
+ zmin += b;
+ }
+ else {
+ zmax += b;
+ zmin += a;
+ }
+
+ this.min.x = xmin;
+ this.min.y = ymin;
+ this.min.z = zmin;
+
+ this.max.x = xmax;
+ this.max.y = ymax;
+ this.max.z = zmax;
+
+ this.updateInternals();
+};
+
+x3dom.fields.BoxVolume.prototype.transformFrom = function(m, other)
+{
+ var xmin, ymin, zmin;
+ var xmax, ymax, zmax;
+
+ xmin = xmax = m._03;
+ ymin = ymax = m._13;
+ zmin = zmax = m._23;
+
+ // calculate xmin and xmax of new transformed BBox
+ var a = other.max.x * m._00;
+ var b = other.min.x * m._00;
+
+ if (a >= b) {
+ xmax += a;
+ xmin += b;
+ }
+ else {
+ xmax += b;
+ xmin += a;
+ }
+
+ a = other.max.y * m._01;
+ b = other.min.y * m._01;
+
+ if (a >= b) {
+ xmax += a;
+ xmin += b;
+ }
+ else {
+ xmax += b;
+ xmin += a;
+ }
+
+ a = other.max.z * m._02;
+ b = other.min.z * m._02;
+
+ if (a >= b) {
+ xmax += a;
+ xmin += b;
+ }
+ else {
+ xmax += b;
+ xmin += a;
+ }
+
+ // calculate ymin and ymax of new transformed BBox
+ a = other.max.x * m._10;
+ b = other.min.x * m._10;
+
+ if (a >= b) {
+ ymax += a;
+ ymin += b;
+ }
+ else {
+ ymax += b;
+ ymin += a;
+ }
+
+ a = other.max.y * m._11;
+ b = other.min.y * m._11;
+
+ if (a >= b) {
+ ymax += a;
+ ymin += b;
+ }
+ else {
+ ymax += b;
+ ymin += a;
+ }
+
+ a = other.max.z * m._12;
+ b = other.min.z * m._12;
+
+ if (a >= b) {
+ ymax += a;
+ ymin += b;
+ }
+ else {
+ ymax += b;
+ ymin += a;
+ }
+
+ // calculate zmin and zmax of new transformed BBox
+ a = other.max.x * m._20;
+ b = other.min.x * m._20;
+
+ if (a >= b) {
+ zmax += a;
+ zmin += b;
+ }
+ else {
+ zmax += b;
+ zmin += a;
+ }
+
+ a = other.max.y * m._21;
+ b = other.min.y * m._21;
+
+ if (a >= b) {
+ zmax += a;
+ zmin += b;
+ }
+ else {
+ zmax += b;
+ zmin += a;
+ }
+
+ a = other.max.z * m._22;
+ b = other.min.z * m._22;
+
+ if (a >= b) {
+ zmax += a;
+ zmin += b;
+ }
+ else {
+ zmax += b;
+ zmin += a;
+ }
+
+ this.min.x = xmin;
+ this.min.y = ymin;
+ this.min.z = zmin;
+
+ this.max.x = xmax;
+ this.max.y = ymax;
+ this.max.z = zmax;
+
+ this.updateInternals();
+ this.valid = true;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+/** FrustumVolume constructor.
+ @class Represents a frustum (as internal helper).
+ */
+x3dom.fields.FrustumVolume = function(clipMat)
+{
+ this.planeNormals = [];
+ this.planeDistances = [];
+ this.directionIndex = [];
+
+ if (arguments.length === 0) {
+ return;
+ }
+
+ var planeEquation = [];
+
+ for (var i=0; i<6; i++) {
+ this.planeNormals[i] = new x3dom.fields.SFVec3f(0, 0, 0);
+ this.planeDistances[i] = 0;
+ this.directionIndex[i] = 0;
+
+ planeEquation[i] = new x3dom.fields.SFVec4f(0, 0, 0, 0);
+ }
+
+ planeEquation[0].x = clipMat._30 - clipMat._00;
+ planeEquation[0].y = clipMat._31 - clipMat._01;
+ planeEquation[0].z = clipMat._32 - clipMat._02;
+ planeEquation[0].w = clipMat._33 - clipMat._03;
+
+ planeEquation[1].x = clipMat._30 + clipMat._00;
+ planeEquation[1].y = clipMat._31 + clipMat._01;
+ planeEquation[1].z = clipMat._32 + clipMat._02;
+ planeEquation[1].w = clipMat._33 + clipMat._03;
+
+ planeEquation[2].x = clipMat._30 + clipMat._10;
+ planeEquation[2].y = clipMat._31 + clipMat._11;
+ planeEquation[2].z = clipMat._32 + clipMat._12;
+ planeEquation[2].w = clipMat._33 + clipMat._13;
+
+ planeEquation[3].x = clipMat._30 - clipMat._10;
+ planeEquation[3].y = clipMat._31 - clipMat._11;
+ planeEquation[3].z = clipMat._32 - clipMat._12;
+ planeEquation[3].w = clipMat._33 - clipMat._13;
+
+ planeEquation[4].x = clipMat._30 + clipMat._20;
+ planeEquation[4].y = clipMat._31 + clipMat._21;
+ planeEquation[4].z = clipMat._32 + clipMat._22;
+ planeEquation[4].w = clipMat._33 + clipMat._23;
+
+ planeEquation[5].x = clipMat._30 - clipMat._20;
+ planeEquation[5].y = clipMat._31 - clipMat._21;
+ planeEquation[5].z = clipMat._32 - clipMat._22;
+ planeEquation[5].w = clipMat._33 - clipMat._23;
+
+ for (i=0; i<6; i++) {
+ var vectorLength = Math.sqrt(planeEquation[i].x * planeEquation[i].x +
+ planeEquation[i].y * planeEquation[i].y +
+ planeEquation[i].z * planeEquation[i].z);
+
+ planeEquation[i].x /= vectorLength;
+ planeEquation[i].y /= vectorLength;
+ planeEquation[i].z /= vectorLength;
+ planeEquation[i].w /= -vectorLength;
+ }
+
+ var updateDirectionIndex = function(normalVec) {
+ var ind = 0;
+ if (normalVec.x > 0) ind |= 1;
+ if (normalVec.y > 0) ind |= 2;
+ if (normalVec.z > 0) ind |= 4;
+ return ind;
+ };
+
+ // right
+ this.planeNormals[3].setValues(planeEquation[0]);
+ this.planeDistances[3] = planeEquation[0].w;
+ this.directionIndex[3] = updateDirectionIndex(this.planeNormals[3]);
+
+ // left
+ this.planeNormals[2].setValues(planeEquation[1]);
+ this.planeDistances[2] = planeEquation[1].w;
+ this.directionIndex[2] = updateDirectionIndex(this.planeNormals[2]);
+
+ // bottom
+ this.planeNormals[5].setValues(planeEquation[2]);
+ this.planeDistances[5] = planeEquation[2].w;
+ this.directionIndex[5] = updateDirectionIndex(this.planeNormals[5]);
+
+ // top
+ this.planeNormals[4].setValues(planeEquation[3]);
+ this.planeDistances[4] = planeEquation[3].w;
+ this.directionIndex[4] = updateDirectionIndex(this.planeNormals[4]);
+
+ // near
+ this.planeNormals[0].setValues(planeEquation[4]);
+ this.planeDistances[0] = planeEquation[4].w;
+ this.directionIndex[0] = updateDirectionIndex(this.planeNormals[0]);
+
+ // far
+ this.planeNormals[1].setValues(planeEquation[5]);
+ this.planeDistances[1] = planeEquation[5].w;
+ this.directionIndex[1] = updateDirectionIndex(this.planeNormals[1]);
+};
+
+/** Check the volume against the frustum. */
+x3dom.fields.FrustumVolume.prototype.intersect = function(vol, planeMask)
+{
+ if (this.planeNormals.length < 6) {
+ x3dom.debug.logWarning("FrustumVolume not initialized!");
+ return false;
+ }
+
+ var that = this;
+ var min = vol.min, max = vol.max;
+
+ var setDirectionIndexPoint = function(index) {
+ var pnt = new x3dom.fields.SFVec3f(0, 0, 0);
+ if (index & 1) { pnt.x = min.x; }
+ else { pnt.x = max.x; }
+ if (index & 2) { pnt.y = min.y; }
+ else { pnt.y = max.y; }
+ if (index & 4) { pnt.z = min.z; }
+ else { pnt.z = max.z; }
+ return pnt;
+ };
+
+ //Check if the point is in the halfspace
+ var pntIsInHalfSpace = function(i, pnt) {
+ var s = that.planeNormals[i].dot(pnt) - that.planeDistances[i];
+ return (s >= 0);
+ };
+
+ //Check if the box formed by min/max is fully inside the halfspace
+ var isInHalfSpace = function(i) {
+ var p = setDirectionIndexPoint(that.directionIndex[i]);
+ return pntIsInHalfSpace(i, p);
+ };
+
+ //Check if the box formed by min/max is fully outside the halfspace
+ var isOutHalfSpace = function(i) {
+ var p = setDirectionIndexPoint(that.directionIndex[i] ^ 7);
+ return !pntIsInHalfSpace(i, p);
+ };
+
+ //Check each point of the box to the 6 planes
+ var mask = 1;
+ if (planeMask < 0) planeMask = 0;
+
+ for (var i=0; i<6; i++, mask<<=1) {
+ if ((planeMask & mask) != 0)
+ continue;
+
+ if (isOutHalfSpace(i))
+ return -1;
+
+ if (isInHalfSpace(i))
+ planeMask |= mask;
+ }
+
+ return planeMask;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+// This module adds documentation related functionality
+// to the library.
+
+/** The x3dom.docs namespace.
+ * @namespace x3dom.docs
+ */
+x3dom.docs = {};
+
+
+x3dom.docs.specURLMap = {
+ CADGeometry: "CADGeometry.html",
+ Core: "core.html",
+ DIS: "dis.html",
+ CubeMapTexturing: "env_texture.html",
+ EnvironmentalEffects: "enveffects.html",
+ EnvironmentalSensor: "envsensor.html",
+ Followers: "followers.html",
+ Geospatial: "geodata.html",
+ Geometry2D: "geometry2D.html",
+ Geometry3D: "geometry3D.html",
+ Grouping: "group.html",
+ "H-Anim": "hanim.html",
+ Interpolation: "interp.html",
+ KeyDeviceSensor: "keyboard.html",
+ Layering: "layering.html",
+ Layout: "layout.html",
+ Lighting: "lighting.html",
+ Navigation: "navigation.html",
+ Networking: "networking.html",
+ NURBS: "nurbs.html",
+ ParticleSystems: "particle_systems.html",
+ Picking: "picking.html",
+ PointingDeviceSensor: "pointingsensor.html",
+ Rendering: "rendering.html",
+ RigidBodyPhysics: "rigid_physics.html",
+ Scripting: "scripting.html",
+ Shaders: "shaders.html",
+ Shape: "shape.html",
+ Sound: "sound.html",
+ Text: "text.html",
+ Texturing3D: "texture3D.html",
+ Texturing: "texturing.html",
+ Time: "time.html",
+ EventUtilities: "utils.html",
+ VolumeRendering: "volume.html"
+};
+
+x3dom.docs.specBaseURL = "http://www.web3d.org/x3d/specifications/ISO-IEC-19775-1.2-X3D-AbstractSpecification/Part01/components/";
+
+
+// the dump-nodetype tree functionality in a function
+x3dom.docs.getNodeTreeInfo = function() {
+
+ // Create the nodetype hierarchy
+ var tn, t;
+ var types = "";
+
+ var objInArray = function(array, obj) {
+ for(var i=0; i<array.length; i++) {
+ if (array[i] === obj) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ var dump = function(t, indent) {
+ for (var i=0; i<indent; i++) {
+ types += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
+ }
+
+ types += "<a href='" +
+ x3dom.docs.specBaseURL + x3dom.docs.specURLMap[x3dom.nodeTypes[t]._compName] + "#" + t +
+ "' style='color:black; text-decoration:none; font-weight:bold;'>" +
+ t + "</a> &nbsp; <a href='" +
+ x3dom.docs.specBaseURL + x3dom.docs.specURLMap[x3dom.nodeTypes[t]._compName] +
+ "' style='color:black; text-decoration:none; font-style:italic;'>" +
+ x3dom.nodeTypes[t]._compName + "</a><br/>";
+
+ for (var i in x3dom.nodeTypes[t].childTypes[t]) {
+ dump(x3dom.nodeTypes[t].childTypes[t][i], indent+1);
+ }
+ };
+
+ for (tn in x3dom.nodeTypes) {
+ var t = x3dom.nodeTypes[tn];
+ if (t.childTypes === undefined) {
+ t.childTypes = {};
+ }
+
+ while (t.superClass) {
+ if (t.superClass.childTypes[t.superClass._typeName] === undefined) {
+ t.superClass.childTypes[t.superClass._typeName] = [];
+ }
+ if (!objInArray(t.superClass.childTypes[t.superClass._typeName], t._typeName)) {
+ t.superClass.childTypes[t.superClass._typeName].push(t._typeName);
+ }
+ t = t.superClass;
+ }
+ }
+
+ dump("X3DNode", 0);
+
+ return "<div class='x3dom-doc-nodes-tree'>" + types + "</div>";
+};
+
+
+x3dom.docs.getComponentInfo = function() {
+ // Dump nodetypes by component
+ // but first sort alphabetically
+ var components = [];
+ var component;
+ var result = "";
+ var c, cn;
+
+ for (c in x3dom.components) {
+ components.push(c);
+ }
+ components.sort();
+
+ //for (var c in x3dom.components) {
+ for (cn in components) {
+ c = components[cn];
+ component = x3dom.components[c];
+ result += "<h2><a href='" +
+ x3dom.docs.specBaseURL + x3dom.docs.specURLMap[c] +
+ "' style='color:black; text-decoration:none; font-style:italic;'>" +
+ c + "</a></h2>";
+
+ result += "<ul style='list-style-type:circle;'>";
+
+ //var $ul = $("#components ul:last");
+ for (var t in component) {
+ result += "<li><a href='" +
+ x3dom.docs.specBaseURL + x3dom.docs.specURLMap[c] + "#" + t +
+ "' style='color:black; text-decoration:none; font-weight:bold;'>" +
+ t + "</a></li>";
+ }
+ result += "</ul>";
+ }
+
+ return result;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+x3dom.shader = {};
+
+x3dom.shader.PICKING = "picking";
+x3dom.shader.PICKING_24 = "picking24";
+x3dom.shader.PICKING_ID = "pickingId";
+x3dom.shader.PICKING_COLOR = "pickingColor";
+x3dom.shader.PICKING_TEXCOORD = "pickingTexCoord";
+x3dom.shader.FRONTGROUND_TEXTURE = "frontgroundTexture";
+x3dom.shader.BACKGROUND_TEXTURE = "backgroundTexture";
+x3dom.shader.BACKGROUND_SKYTEXTURE = "backgroundSkyTexture";
+x3dom.shader.BACKGROUND_CUBETEXTURE = "backgroundCubeTexture";
+x3dom.shader.SHADOW = "shadow";
+x3dom.shader.BLUR = "blur";
+x3dom.shader.DEPTH = "depth";
+x3dom.shader.NORMAL = "normal";
+x3dom.shader.TEXTURE_REFINEMENT = "textureRefinement";
+x3dom.shader.SSAO = "ssao";
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+/*******************************************************************************
+* Material
+********************************************************************************/
+ x3dom.shader.material = function() {
+ var shaderPart = "uniform vec3 diffuseColor;\n" +
+ "uniform vec3 specularColor;\n" +
+ "uniform vec3 emissiveColor;\n" +
+ "uniform float shininess;\n" +
+ "uniform float transparency;\n" +
+ "uniform float ambientIntensity;\n";
+
+ return shaderPart;
+};
+
+/*******************************************************************************
+ * TwoSidedMaterial
+ ********************************************************************************/
+x3dom.shader.twoSidedMaterial = function() {
+ var shaderPart = "uniform vec3 backDiffuseColor;\n" +
+ "uniform vec3 backSpecularColor;\n" +
+ "uniform vec3 backEmissiveColor;\n" +
+ "uniform float backShininess;\n" +
+ "uniform float backTransparency;\n" +
+ "uniform float backAmbientIntensity;\n";
+
+ return shaderPart;
+};
+
+/*******************************************************************************
+* Fog
+********************************************************************************/
+x3dom.shader.fog = function() {
+
+ var shaderPart = "uniform vec3 fogColor;\n" +
+ "uniform float fogType;\n" +
+ "uniform float fogRange;\n" +
+ "varying vec3 fragEyePosition;\n" +
+ "float calcFog(in vec3 eye) {\n" +
+ " float f0 = 0.0;\n" +
+ " if(fogType == 0.0) {\n" +
+ " if(length(eye) < fogRange){\n" +
+ " f0 = (fogRange-length(eye)) / fogRange;\n" +
+ " }\n" +
+ " }else{\n" +
+ " if(length(eye) < fogRange){\n" +
+ " f0 = exp(-length(eye) / (fogRange-length(eye) ) );\n" +
+ " }\n" +
+ " }\n" +
+ " f0 = clamp(f0, 0.0, 1.0);\n" +
+ " return f0;\n" +
+ "}\n";
+
+ return shaderPart;
+};
+
+/*******************************************************************************
+ * Clipplane
+ ********************************************************************************/
+x3dom.shader.clipPlanes = function(numClipPlanes) {
+ var shaderPart = "", c;
+
+ for(c=0; c<numClipPlanes; c++) {
+ shaderPart += "uniform vec4 clipPlane"+c+"_Plane;\n";
+ shaderPart += "uniform float clipPlane"+c+"_CappingStrength;\n";
+ shaderPart += "uniform vec3 clipPlane"+c+"_CappingColor;\n";
+ }
+
+ shaderPart += "vec3 calculateClipPlanes() {\n";
+
+ for(c=0; c<numClipPlanes; c++) {
+ shaderPart += " vec4 clipPlane" + c + " = clipPlane" + c + "_Plane * viewMatrixInverse;\n";
+ shaderPart += " float dist" + c + " = dot(fragPosition, clipPlane" + c + ");\n";
+ }
+
+ shaderPart += " if( ";
+
+ for(c=0; c<numClipPlanes; c++) {
+ if(c!=0) {
+ shaderPart += " || ";
+ }
+ shaderPart += "dist" + c + " < 0.0" ;
+ }
+
+ shaderPart += " ) ";
+ shaderPart += "{ discard; }\n";
+
+ for (c = 0; c < numClipPlanes; c++) {
+ shaderPart += " if( abs(dist" + c + ") < clipPlane" + c + "_CappingStrength ) ";
+ shaderPart += "{ return clipPlane" + c + "_CappingColor; }\n";
+ }
+
+ shaderPart += " return vec3(-1.0, -1.0, -1.0);\n";
+
+ shaderPart += "}\n";
+
+ return shaderPart;
+};
+
+/*******************************************************************************
+* Gamma correction support: initial declaration
+********************************************************************************/
+x3dom.shader.gammaCorrectionDecl = function(properties) {
+ var shaderPart = "";
+ if (properties.GAMMACORRECTION === "none") {
+ // do not emit any declaration. 1.0 shall behave 'as without gamma'.
+ } else if (properties.GAMMACORRECTION === "fastlinear") {
+ // This is a slightly optimized gamma correction
+ // which uses a gamma of 2.0 instead of 2.2. Gamma 2.0 is less costly
+ // to encode in terms of cycles as sqrt() is usually optimized
+ // in hardware.
+ shaderPart += "vec4 gammaEncode(vec4 color){\n" +
+ " vec4 tmp = sqrt(color);\n" +
+ " return vec4(tmp.rgb, color.a);\n" +
+ "}\n";
+
+ shaderPart += "vec4 gammaDecode(vec4 color){\n" +
+ " vec4 tmp = color * color;\n" +
+ " return vec4(tmp.rgb, color.a);\n" +
+ "}\n";
+
+ shaderPart += "vec3 gammaEncode(vec3 color){\n" +
+ " return sqrt(color);\n" +
+ "}\n";
+
+ shaderPart += "vec3 gammaDecode(vec3 color){\n" +
+ " return (color * color);\n" +
+ "}\n";
+ } else {
+ // The preferred implementation compensating for a gamma of 2.2, which closely
+ // follows sRGB; alpha remains linear
+ // minor opt: 1.0 / 2.2 = 0.4545454545454545
+ shaderPart += "const vec4 gammaEncode4Vector = vec4(0.4545454545454545, 0.4545454545454545, 0.4545454545454545, 1.0);\n";
+ shaderPart += "const vec4 gammaDecode4Vector = vec4(2.2, 2.2, 2.2, 1.0);\n";
+
+ shaderPart += "vec4 gammaEncode(vec4 color){\n" +
+ " return pow(color, gammaEncode4Vector);\n" +
+ "}\n";
+
+ shaderPart += "vec4 gammaDecode(vec4 color){\n" +
+ " return pow(color, gammaDecode4Vector);\n" +
+ "}\n";
+
+ // RGB; minor opt: 1.0 / 2.2 = 0.4545454545454545
+ shaderPart += "const vec3 gammaEncode3Vector = vec3(0.4545454545454545, 0.4545454545454545, 0.4545454545454545);\n";
+ shaderPart += "const vec3 gammaDecode3Vector = vec3(2.2, 2.2, 2.2);\n";
+
+ shaderPart += "vec3 gammaEncode(vec3 color){\n" +
+ " return pow(color, gammaEncode3Vector);\n" +
+ "}\n";
+
+ shaderPart += "vec3 gammaDecode(vec3 color){\n" +
+ " return pow(color, gammaDecode3Vector);\n" +
+ "}\n";
+ }
+ return shaderPart;
+};
+
+/*******************************************************************************
+* Gamma correction support: encoding and decoding of given expressions
+*
+* Unlike other shader parts these javascript functions wrap the same-named gamma
+* correction shader functions (if applicable). When gamma correction is not used,
+* the expression will be returned verbatim. Consequently, any terminating semicolon
+* is to be issued by the caller.
+********************************************************************************/
+x3dom.shader.encodeGamma = function(properties, expr) {
+ if (properties.GAMMACORRECTION === "none") {
+ // Naive implementation: no-op, return verbatim
+ return expr;
+ } else {
+ // The 2.0 and 2.2 cases are transparent at the call site
+ return "gammaEncode (" + expr + ")";
+ }
+};
+
+x3dom.shader.decodeGamma = function(properties, expr) {
+ if (properties.GAMMACORRECTION === "none") {
+ // Naive implementation: no-op, return verbatim
+ return expr;
+ } else {
+ // The 2.0 and 2.2 cases are transparent at the call site
+ return "gammaDecode (" + expr + ")";
+ }
+};
+
+/*******************************************************************************
+* Shadow
+********************************************************************************/
+x3dom.shader.rgbaPacking = function() {
+ var shaderPart = "";
+ shaderPart +=
+ "vec4 packDepth(float depth){\n" +
+ " depth = (depth + 1.0)*0.5;\n" +
+ " vec4 outVal = vec4(1.0, 255.0, 65025.0, 160581375.0) * depth;\n" +
+ " outVal = fract(outVal);\n" +
+ " outVal -= outVal.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0);\n" +
+ " return outVal;\n" +
+ "}\n";
+
+ shaderPart +=
+ "float unpackDepth(vec4 color){\n" +
+ " float depth = dot(color, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/160581375.0));\n" +
+ " return (2.0*depth - 1.0);\n" +
+ "}\n";
+ return shaderPart;
+};
+
+x3dom.shader.shadowRendering = function(){
+ //determine if and how much a given position is influenced by given light
+ var shaderPart = "";
+ shaderPart +=
+ "float getLightInfluence(float lType, float lShadowIntensity, float lOn, vec3 lLocation, vec3 lDirection, " +
+ "float lCutOffAngle, float lBeamWidth, vec3 lAttenuation, float lRadius, vec3 eyeCoords) {\n" +
+ " if (lOn == 0.0 || lShadowIntensity == 0.0){ return 0.0;\n" +
+ " } else if (lType == 0.0) {\n" +
+ " return 1.0;\n" +
+ " } else {\n" +
+ " float attenuation = 0.0;\n" +
+ " vec3 lightVec = (lLocation - (eyeCoords));\n" +
+ " float distance = length(lightVec);\n" +
+ " lightVec = normalize(lightVec);\n" +
+ " eyeCoords = normalize(-eyeCoords);\n" +
+ " if(lRadius == 0.0 || distance <= lRadius) {\n" +
+ " attenuation = 1.0 / max(lAttenuation.x + lAttenuation.y * distance + lAttenuation.z * (distance * distance), 1.0);\n" +
+ " }\n" +
+ " if (lType == 1.0) return attenuation;\n" +
+ " float spotAngle = acos(max(0.0, dot(-lightVec, normalize(lDirection))));\n" +
+ " if(spotAngle >= lCutOffAngle) return 0.0;\n" +
+ " else if(spotAngle <= lBeamWidth) return attenuation;\n" +
+ " else return attenuation * (spotAngle - lCutOffAngle) / (lBeamWidth - lCutOffAngle);\n" +
+ " }\n" +
+ "}\n";
+
+ // get light space depth of view sample and all entries of the shadow map
+ shaderPart +=
+ "void getShadowValues(inout vec4 shadowMapValues, inout float viewSampleDepth, in mat4 lightMatrix, in vec4 worldCoords, in sampler2D shadowMap){\n" +
+ " vec4 lightSpaceCoords = lightMatrix*worldCoords;\n" +
+ " vec3 lightSpaceCoordsCart = lightSpaceCoords.xyz / lightSpaceCoords.w;\n" +
+ " vec2 textureCoords = (lightSpaceCoordsCart.xy + 1.0)*0.5;\n" +
+ " viewSampleDepth = lightSpaceCoordsCart.z;\n" +
+ " shadowMapValues = texture2D(shadowMap, textureCoords);\n";
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE)
+ shaderPart += " shadowMapValues = vec4(1.0,1.0,unpackDepth(shadowMapValues),1.0);\n";
+ shaderPart +="}\n";
+
+
+ // get light space depth of view sample and all entries of the shadow map for point lights
+ shaderPart +=
+ "void getShadowValuesPointLight(inout vec4 shadowMapValues, inout float viewSampleDepth, in vec3 lLocation, in vec4 worldCoords, in mat4 lightViewMatrix," +
+ "in mat4 lMatrix_0, in mat4 lMatrix_1, in mat4 lMatrix_2, in mat4 lMatrix_3, in mat4 lMatrix_4, in mat4 lMatrix_5," +
+ "in sampler2D shadowMap_0, in sampler2D shadowMap_1, in sampler2D shadowMap_2, in sampler2D shadowMap_3,"+
+ "in sampler2D shadowMap_4, in sampler2D shadowMap_5){\n" +
+ " vec4 transformed = lightViewMatrix * worldCoords;\n" +
+ " vec3 lightVec = normalize(transformed.xyz/transformed.w);\n"+
+ " vec3 lightVecAbs = abs(lightVec);\n" +
+ " float maximum = max(max(lightVecAbs.x, lightVecAbs.y),lightVecAbs.z);\n" +
+ " if (lightVecAbs.x == maximum) {\n" +
+ " if (lightVec.x < 0.0) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_3,worldCoords,shadowMap_3);\n"+ //right
+ " else getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_1,worldCoords,shadowMap_1);\n" + //left
+ " }\n" +
+ " else if (lightVecAbs.y == maximum) {\n" +
+ " if (lightVec.y < 0.0) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_4,worldCoords,shadowMap_4);\n"+ //front
+ " else getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_5,worldCoords,shadowMap_5);\n" + //back
+ " }\n" +
+ " else if (lightVec.z < 0.0) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_0,worldCoords,shadowMap_0);\n"+ //bottom
+ " else getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_2,worldCoords,shadowMap_2);\n" + //top
+ "}\n";
+
+ // get light space depth of view sample and all entries of the shadow map
+ shaderPart +=
+ "void getShadowValuesCascaded(inout vec4 shadowMapValues, inout float viewSampleDepth, in vec4 worldCoords, in float eyeDepth, in mat4 lMatrix_0, in mat4 lMatrix_1, in mat4 lMatrix_2,"+
+ "in mat4 lMatrix_3, in mat4 lMatrix_4, in mat4 lMatrix_5, in sampler2D shadowMap_0, in sampler2D shadowMap_1, in sampler2D shadowMap_2,"+
+ "in sampler2D shadowMap_3, in sampler2D shadowMap_4, in sampler2D shadowMap_5, in float split_0, in float split_1, in float split_2, in float split_3, in float split_4){\n" +
+ " if (eyeDepth < split_0) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_0, worldCoords, shadowMap_0);\n" +
+ " else if (eyeDepth < split_1) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_1, worldCoords, shadowMap_1);\n" +
+ " else if (eyeDepth < split_2) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_2, worldCoords, shadowMap_2);\n" +
+ " else if (eyeDepth < split_3) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_3, worldCoords, shadowMap_3);\n" +
+ " else if (eyeDepth < split_4) getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_4, worldCoords, shadowMap_4);\n" +
+ " else getShadowValues(shadowMapValues, viewSampleDepth, lMatrix_5, worldCoords, shadowMap_5);\n" +
+ "}\n";
+
+ shaderPart +=
+ "float ESM(float shadowMapDepth, float viewSampleDepth, float offset){\n";
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE)
+ shaderPart += " return exp(-80.0*(1.0-offset)*(viewSampleDepth - shadowMapDepth));\n";
+ else shaderPart += " return shadowMapDepth * exp(-80.0*(1.0-offset)*viewSampleDepth);\n";
+ shaderPart +="}\n";
+
+
+ shaderPart +=
+ "float VSM(vec2 moments, float viewSampleDepth, float offset){\n"+
+ " viewSampleDepth = (viewSampleDepth + 1.0) * 0.5;\n" +
+ " if (viewSampleDepth <= moments.x) return 1.0;\n" +
+ " float variance = moments.y - moments.x * moments.x;\n" +
+ " variance = max(variance, 0.00002 + offset*0.01);\n" +
+ " float d = viewSampleDepth - moments.x;\n" +
+ " return variance/(variance + d*d);\n" +
+ "}\n";
+
+
+ return shaderPart;
+};
+
+
+/*******************************************************************************
+* Light
+********************************************************************************/
+x3dom.shader.light = function(numLights) {
+
+ var shaderPart = "";
+
+ for(var l=0; l<numLights; l++) {
+ shaderPart += "uniform float light"+l+"_On;\n" +
+ "uniform float light"+l+"_Type;\n" +
+ "uniform vec3 light"+l+"_Location;\n" +
+ "uniform vec3 light"+l+"_Direction;\n" +
+ "uniform vec3 light"+l+"_Color;\n" +
+ "uniform vec3 light"+l+"_Attenuation;\n" +
+ "uniform float light"+l+"_Radius;\n" +
+ "uniform float light"+l+"_Intensity;\n" +
+ "uniform float light"+l+"_AmbientIntensity;\n" +
+ "uniform float light"+l+"_BeamWidth;\n" +
+ "uniform float light"+l+"_CutOffAngle;\n" +
+ "uniform float light"+l+"_ShadowIntensity;\n";
+ }
+
+ shaderPart += "vec3 lighting(in float lType, in vec3 lLocation, in vec3 lDirection, in vec3 lColor, in vec3 lAttenuation, " +
+ "in float lRadius, in float lIntensity, in float lAmbientIntensity, in float lBeamWidth, " +
+ "in float lCutOffAngle, in vec3 N, in vec3 V, float shin, float ambIntensity)\n" +
+ "{\n" +
+ " vec3 L;\n" +
+ " float spot = 1.0, attentuation = 0.0;\n" +
+ " if(lType == 0.0) {\n" +
+ " L = -normalize(lDirection);\n" +
+ " V = normalize(V);\n" +
+ " attentuation = 1.0;\n" +
+ " } else{\n" +
+ " L = (lLocation - (-V));\n" +
+ " float d = length(L);\n" +
+ " L = normalize(L);\n" +
+ " V = normalize(V);\n" +
+ " if(lRadius == 0.0 || d <= lRadius) {\n" +
+ " attentuation = 1.0 / max(lAttenuation.x + lAttenuation.y * d + lAttenuation.z * (d * d), 1.0);\n" +
+ " }\n" +
+ " if(lType == 2.0) {\n" +
+ " float spotAngle = acos(max(0.0, dot(-L, normalize(lDirection))));\n" +
+ " if(spotAngle >= lCutOffAngle) spot = 0.0;\n" +
+ " else if(spotAngle <= lBeamWidth) spot = 1.0;\n" +
+ " else spot = (spotAngle - lCutOffAngle ) / (lBeamWidth - lCutOffAngle);\n" +
+ " }\n" +
+ " }\n" +
+
+ " vec3 H = normalize( L + V );\n" +
+ " float NdotL = clamp(dot(L, N), 0.0, 1.0);\n" +
+ " float NdotH = clamp(dot(H, N), 0.0, 1.0);\n" +
+
+ " float ambientFactor = lAmbientIntensity * ambIntensity;\n" +
+ " float diffuseFactor = lIntensity * NdotL;\n" +
+ " float specularFactor = lIntensity * pow(NdotH, shin*128.0);\n" +
+ " return vec3(ambientFactor, diffuseFactor, specularFactor) * attentuation * spot;\n" +
+ //" ambient += lColor * ambientFactor * attentuation * spot;\n" +
+ //" diffuse += lColor * diffuseFactor * attentuation * spot;\n" +
+ //" specular += lColor * specularFactor * attentuation * spot;\n" +
+ "}\n";
+
+ return shaderPart;
+};
+
+/*******************************************************************************
+ * cotangent_frame
+ ********************************************************************************/
+x3dom.shader.TBNCalculation = function() {
+ var shaderPart = "";
+
+ shaderPart += "mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv)\n" +
+ "{\n" +
+ " // get edge vectors of the pixel triangle\n" +
+ " vec3 dp1 = dFdx( p );\n" +
+ " vec3 dp2 = dFdy( p );\n" +
+ " vec2 duv1 = dFdx( uv );\n" +
+ " vec2 duv2 = dFdy( uv );\n" +
+ "\n" +
+ " // solve the linear system\n" +
+ " vec3 dp2perp = cross( dp2, N );\n" +
+ " vec3 dp1perp = cross( N, dp1 );\n" +
+ " vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n" +
+ " vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n" +
+ "\n" +
+ " // construct a scale-invariant frame\n" +
+ " float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );\n" +
+ " return mat3( T * invmax, B * invmax, N );\n" +
+ "}\n\n";
+
+ shaderPart += "vec3 perturb_normal( vec3 N, vec3 V, vec2 texcoord )\n" +
+ "{\n" +
+ " // assume N, the interpolated vertex normal and\n" +
+ " // V, the view vector (vertex to eye)\n" +
+ " vec3 map = texture2D(normalMap, texcoord ).xyz;\n" +
+ " map = map * 255./127. - 128./127.;\n" +
+ " mat3 TBN = cotangent_frame(N, -V, texcoord);\n" +
+ " return normalize(TBN * map);\n" +
+ "}\n\n";
+
+ return shaderPart;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final Shader program
+ */
+x3dom.shader.DynamicShader = function(gl, properties)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl, properties);
+ var fragmentShader = this.generateFragmentShader(gl, properties);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.DynamicShader.prototype.generateVertexShader = function(gl, properties)
+{
+ var shader = "";
+
+ /*******************************************************************************
+ * Generate dynamic attributes & uniforms & varyings
+ ********************************************************************************/
+
+ //Default Matrices
+ shader += "uniform mat4 modelViewMatrix;\n";
+ shader += "uniform mat4 modelViewProjectionMatrix;\n";
+
+ //Positions
+ if(properties.POSCOMPONENTS == 3) {
+ shader += "attribute vec3 position;\n";
+ } else if(properties.POSCOMPONENTS == 4) {
+ shader += "attribute vec4 position;\n";
+ }
+
+ //IG stuff
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform vec3 IG_bboxMin;\n";
+ shader += "uniform vec3 IG_bboxMax;\n";
+ shader += "uniform float IG_coordTextureWidth;\n";
+ shader += "uniform float IG_coordTextureHeight;\n";
+ shader += "uniform vec2 IG_implicitMeshSize;\n";
+
+ for( var i = 0; i < properties.IG_PRECISION; i++ ) {
+ shader += "uniform sampler2D IG_coords" + i + "\n;";
+ }
+
+ if(properties.IG_INDEXED) {
+ shader += "uniform sampler2D IG_index;\n";
+ shader += "uniform float IG_indexTextureWidth;\n";
+ shader += "uniform float IG_indexTextureHeight;\n";
+ }
+ }
+
+ //PG stuff
+ if (properties.POPGEOMETRY) {
+ shader += "uniform float PG_precisionLevel;\n";
+ shader += "uniform float PG_powPrecision;\n";
+ shader += "uniform vec3 PG_maxBBSize;\n";
+ shader += "uniform vec3 PG_bbMin;\n";
+ shader += "uniform vec3 PG_bbMaxModF;\n";
+ shader += "uniform vec3 PG_bboxShiftVec;\n";
+ shader += "uniform float PG_numAnchorVertices;\n";
+ shader += "attribute float PG_vertexID;\n";
+ }
+
+ //Normals
+ if(properties.LIGHTS) {
+ shader += "varying vec3 fragNormal;\n";
+ shader += "uniform mat4 normalMatrix;\n";
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform sampler2D IG_normals;\n";
+ } else {
+ if(properties.NORCOMPONENTS == 2) {
+ if(properties.POSCOMPONENTS != 4) {
+ shader += "attribute vec2 normal;\n";
+ }
+ } else if(properties.NORCOMPONENTS == 3) {
+ shader += "attribute vec3 normal;\n";
+ }
+ }
+ }
+
+ //Init Colors. In the vertex shader we do not compute any color so
+ //is is safe to ignore gamma here.
+ if(properties.VERTEXCOLOR) {
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform sampler2D IG_colors;\n";
+ if(properties.COLCOMPONENTS == 3) {
+ shader += "varying vec3 fragColor;\n";
+ } else if(properties.COLCOMPONENTS == 4) {
+ shader += "varying vec4 fragColor;\n";
+ }
+ } else {
+ if(properties.COLCOMPONENTS == 3) {
+ shader += "attribute vec3 color;\n";
+ shader += "varying vec3 fragColor;\n";
+ } else if(properties.COLCOMPONENTS == 4) {
+ shader += "attribute vec4 color;\n";
+ shader += "varying vec4 fragColor;\n";
+ }
+ }
+ }
+
+ //Textures
+ if(properties.TEXTURED || properties.CSSHADER) {
+ shader += "varying vec2 fragTexcoord;\n";
+ if(!properties.SPHEREMAPPING) {
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform sampler2D IG_texCoords;\n";
+ } else if (!properties.IS_PARTICLE) {
+ shader += "attribute vec2 texcoord;\n";
+ }
+ }
+ if(properties.TEXTRAFO){
+ shader += "uniform mat4 texTrafoMatrix;\n";
+ }
+
+ if(properties.NORMALMAP && !x3dom.caps.STD_DERIVATIVES) {
+
+ x3dom.debug.logWarning("Your System doesn't support the 'OES_STANDARD_DERIVATIVES' Extension. " +
+ "You must set tangents and binormals manually via the FloatVertexAttribute-Node " +
+ "to use normal maps");
+
+ shader += "attribute vec3 tangent;\n";
+ shader += "attribute vec3 binormal;\n";
+ shader += "varying vec3 fragTangent;\n";
+ shader += "varying vec3 fragBinormal;\n";
+ }
+
+ if(properties.CUBEMAP) {
+ shader += "varying vec3 fragViewDir;\n";
+ shader += "uniform mat4 viewMatrix;\n";
+ }
+ if (properties.DISPLACEMENTMAP) {
+ shader += "uniform sampler2D displacementMap;\n";
+ shader += "uniform float displacementFactor;\n";
+ shader += "uniform float displacementWidth;\n";
+ shader += "uniform float displacementHeight;\n";
+ shader += "uniform float displacementAxis;\n";
+ }
+ if (properties.DIFFPLACEMENTMAP) {
+ shader += "uniform sampler2D diffuseDisplacementMap;\n";
+ shader += "uniform float displacementFactor;\n";
+ shader += "uniform float displacementWidth;\n";
+ shader += "uniform float displacementHeight;\n";
+ shader += "uniform float displacementAxis;\n";
+ }
+ if (properties.MULTIDIFFALPMAP || properties.MULTIVISMAP) {
+ shader += "attribute float id;\n";
+ shader += "varying float fragID;\n";
+ }
+ }
+ if (properties.IS_PARTICLE) {
+ shader += "attribute vec3 particleSize;\n";
+ }
+
+ //Lights & Fog
+ if(properties.LIGHTS || properties.FOG || properties.CLIPPLANES){
+ shader += "uniform vec3 eyePosition;\n";
+ shader += "varying vec4 fragPosition;\n";
+ if(properties.FOG) {
+ shader += "varying vec3 fragEyePosition;\n";
+ }
+ }
+
+ //Bounding Boxes
+ if(properties.REQUIREBBOX) {
+ shader += "uniform vec3 bgCenter;\n";
+ shader += "uniform vec3 bgSize;\n";
+ shader += "uniform float bgPrecisionMax;\n";
+ }
+ if(properties.REQUIREBBOXNOR) {
+ shader += "uniform float bgPrecisionNorMax;\n";
+ }
+ if(properties.REQUIREBBOXCOL) {
+ shader += "uniform float bgPrecisionColMax;\n";
+ }
+ if(properties.REQUIREBBOXTEX) {
+ shader += "uniform float bgPrecisionTexMax;\n";
+ }
+
+
+ /*******************************************************************************
+ * Generate main function
+ ********************************************************************************/
+ shader += "void main(void) {\n";
+
+ /*******************************************************************************
+ * Start of special Geometry switch
+ ********************************************************************************/
+ if(properties.IMAGEGEOMETRY) {
+ //Indices
+ if(properties.IG_INDEXED) {
+ shader += "vec2 halfPixel = vec2(0.5/IG_indexTextureWidth,0.5/IG_indexTextureHeight);\n";
+ shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_indexTextureWidth), position.y*(IG_implicitMeshSize.y/IG_indexTextureHeight)) + halfPixel;\n";
+ shader += "vec2 IG_indices = texture2D( IG_index, IG_texCoord ).rg;\n";
+ shader += "halfPixel = vec2(0.5/IG_coordTextureWidth,0.5/IG_coordTextureHeight);\n";
+ shader += "IG_texCoord = (IG_indices * 0.996108948) + halfPixel;\n";
+ } else {
+ shader += "vec2 halfPixel = vec2(0.5/IG_coordTextureWidth, 0.5/IG_coordTextureHeight);\n";
+ shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_coordTextureWidth), position.y*(IG_implicitMeshSize.y/IG_coordTextureHeight)) + halfPixel;\n";
+ }
+
+ //Positions
+ shader += "vec3 temp = vec3(0.0, 0.0, 0.0);\n";
+ shader += "vec3 vertPosition = vec3(0.0, 0.0, 0.0);\n";
+
+ for(var i=0; i<properties.IG_PRECISION; i++) {
+ shader += "temp = 255.0 * texture2D( IG_coords" + i + ", IG_texCoord ).rgb;\n";
+ shader += "vertPosition *= 256.0;\n";
+ shader += "vertPosition += temp;\n";
+ }
+
+ shader += "vertPosition /= (pow(2.0, 8.0 * " + properties.IG_PRECISION + ".0) - 1.0);\n";
+ shader += "vertPosition = vertPosition * (IG_bboxMax - IG_bboxMin) + IG_bboxMin;\n";
+
+ //Normals
+ if(properties.LIGHTS) {
+ shader += "vec3 vertNormal = texture2D( IG_normals, IG_texCoord ).rgb;\n";
+ shader += "vertNormal = vertNormal * 2.0 - 1.0;\n";
+ }
+
+ //Colors
+ if(properties.VERTEXCOLOR) {
+ if(properties.COLCOMPONENTS == 3) {
+ shader += "fragColor = texture2D( IG_colors, IG_texCoord ).rgb;\n";
+ } else if(properties.COLCOMPONENTS == 4) {
+ shader += "fragColor = texture2D( IG_colors, IG_texCoord ).rgba;\n";
+ }
+ }
+
+ //TexCoords
+ if(properties.TEXTURED || properties.CSSHADER) {
+ shader += "vec4 IG_doubleTexCoords = texture2D( IG_texCoords, IG_texCoord );\n";
+ shader += "vec2 vertTexCoord;";
+ shader += "vertTexCoord.r = (IG_doubleTexCoords.r * 0.996108948) + (IG_doubleTexCoords.b * 0.003891051);\n";
+ shader += "vertTexCoord.g = (IG_doubleTexCoords.g * 0.996108948) + (IG_doubleTexCoords.a * 0.003891051);\n";
+ }
+ } else {
+ //Positions
+ shader += "vec3 vertPosition = position.xyz;\n";
+
+ if (properties.POPGEOMETRY) {
+ //compute offset using bounding box and test if vertPosition <= PG_bbMaxModF
+ shader += "vec3 offsetVec = step(vertPosition / bgPrecisionMax, PG_bbMaxModF) * PG_bboxShiftVec;\n";
+
+ //coordinate truncation, computation of current maximum possible value
+ //PG_vertexID currently mimics use of gl_VertexID
+ shader += "if ((PG_precisionLevel <= 2.0) || PG_vertexID >= PG_numAnchorVertices) {\n";
+ shader += " vertPosition = floor(vertPosition / PG_powPrecision) * PG_powPrecision;\n";
+ shader += " vertPosition /= (65536.0 - PG_powPrecision);\n";
+ shader += "}\n";
+ shader += "else {\n";
+ shader += " vertPosition /= bgPrecisionMax;\n";
+ shader += "}\n";
+
+ //translate coordinates, where PG_bbMin := floor(bbMin / size)
+ shader += "vertPosition = (vertPosition + offsetVec + PG_bbMin) * PG_maxBBSize;\n";
+ }
+ else if(properties.REQUIREBBOX) {
+ shader += "vertPosition = bgCenter + bgSize * vertPosition / bgPrecisionMax;\n";
+ }
+
+ //Normals
+ if(properties.LIGHTS) {
+ if(properties.NORCOMPONENTS == 2) {
+ if (properties.POSCOMPONENTS == 4) {
+ // (theta, phi) encoded in low/high byte of position.w
+ shader += "vec3 vertNormal = vec3(position.w / 256.0); \n";
+ shader += "vertNormal.x = floor(vertNormal.x) / 255.0; \n";
+ shader += "vertNormal.y = fract(vertNormal.y) * 1.00392156862745; \n"; //256.0 / 255.0
+ }
+ else if (properties.REQUIREBBOXNOR) {
+ shader += "vec3 vertNormal = vec3(normal.xy, 0.0) / bgPrecisionNorMax;\n";
+ }
+
+ shader += "vec2 thetaPhi = 3.14159265358979 * vec2(vertNormal.x, vertNormal.y*2.0-1.0); \n";
+ shader += "vec4 sinCosThetaPhi = sin( vec4(thetaPhi, thetaPhi + 1.5707963267949) ); \n";
+
+ shader += "vertNormal.x = sinCosThetaPhi.x * sinCosThetaPhi.w; \n";
+ shader += "vertNormal.y = sinCosThetaPhi.x * sinCosThetaPhi.y; \n";
+ shader += "vertNormal.z = sinCosThetaPhi.z; \n";
+ } else {
+ shader += "vec3 vertNormal = normal;\n";
+ if (properties.REQUIREBBOXNOR) {
+ shader += "vertNormal = vertNormal / bgPrecisionNorMax;\n";
+ }
+ if (properties.POPGEOMETRY) {
+ shader += "vertNormal = 2.0*vertNormal - 1.0;\n";
+ }
+ }
+ }
+
+ //Colors
+ if(properties.VERTEXCOLOR){
+ shader += "fragColor = color;\n";
+
+ if(properties.REQUIREBBOXCOL) {
+ shader += "fragColor = fragColor / bgPrecisionColMax;\n";
+ }
+ }
+
+ //TexCoords
+ if( (properties.TEXTURED || properties.CSSHADER) && !properties.SPHEREMAPPING) {
+ if (properties.IS_PARTICLE) {
+ shader += "vec2 vertTexCoord = vec2(0.0);\n";
+ }
+ else {
+ shader += "vec2 vertTexCoord = texcoord;\n";
+ if (properties.REQUIREBBOXTEX) {
+ shader += "vertTexCoord = vertTexCoord / bgPrecisionTexMax;\n";
+ }
+ }
+ }
+ }
+
+ /*******************************************************************************
+ * End of special Geometry switch
+ ********************************************************************************/
+
+
+ //Normals
+ if(properties.LIGHTS) {
+ if (properties.DISPLACEMENTMAP || properties.DIFFPLACEMENTMAP && !properties.NORMALMAP) {
+ //Map-Tile Size
+ shader += "float dx = 1.0 / displacementWidth;\n";
+ shader += "float dy = 1.0 / displacementHeight;\n";
+
+ //Get the 4 Vertex Neighbours
+ if (properties.DISPLACEMENTMAP)
+ {
+ shader += "float s1 = texture2D(displacementMap, vec2(vertTexCoord.x - dx, 1.0 - vertTexCoord.y)).r;\n"; //left
+ shader += "float s2 = texture2D(displacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y - dy)).r;\n"; //bottom
+ shader += "float s3 = texture2D(displacementMap, vec2(vertTexCoord.x + dx, 1.0 - vertTexCoord.y)).r;\n"; //right
+ shader += "float s4 = texture2D(displacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y + dy)).r;\n"; //top
+ }
+ else if (properties.DIFFPLACEMENTMAP)
+ {
+ shader += "float s1 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x - dx, 1.0 - vertTexCoord.y)).a;\n"; //left
+ shader += "float s2 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y - dy)).a;\n"; //bottom
+ shader += "float s3 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x + dx, 1.0 - vertTexCoord.y)).a;\n"; //right
+ shader += "float s4 = texture2D(diffuseDisplacementMap, vec2(vertTexCoord.x, 1.0 - vertTexCoord.y + dy)).a;\n"; //top
+ }
+
+ //Coeffiecent for smooth/sharp Normals
+ shader += "float coef = displacementFactor;\n";
+
+ //Calculate the Normal
+ shader += "vec3 calcNormal;\n";
+
+ shader += "if (displacementAxis == 0.0) {\n"; //X
+ shader += "calcNormal = vec3((s1 - s3) * coef, -5.0, (s2 - s4) * coef);\n";
+ shader += "} else if(displacementAxis == 1.0) {\n"; //Y
+ shader += "calcNormal = vec3((s1 - s3) * coef, -5.0, (s2 - s4) * coef);\n";
+ shader += "} else {\n"; //Z
+ shader += "calcNormal = vec3((s1 - s3) * coef, -(s2 - s4) * coef, 5.0);\n";
+ shader += "}\n";
+
+
+ //normalized Normal
+ shader += "calcNormal = normalize(calcNormal);\n";
+ shader += "fragNormal = (normalMatrix * vec4(calcNormal, 0.0)).xyz;\n";
+ }
+ else
+ {
+ shader += "fragNormal = (normalMatrix * vec4(vertNormal, 0.0)).xyz;\n";
+ }
+ }
+
+ //Textures
+ if(properties.TEXTURED || properties.CSSHADER){
+ if(properties.CUBEMAP) {
+ shader += "fragViewDir = (viewMatrix[3].xyz);\n";
+ } else if (properties.SPHEREMAPPING) {
+ shader += " fragTexcoord = 0.5 + fragNormal.xy / 2.0;\n";
+ } else if(properties.TEXTRAFO) {
+ shader += " fragTexcoord = (texTrafoMatrix * vec4(vertTexCoord, 1.0, 1.0)).xy;\n";
+ } else {
+ shader += " fragTexcoord = vertTexCoord;\n";
+
+ // LOD LUT HACK ###
+ if (properties.POPGEOMETRY && x3dom.debug.usePrecisionLevelAsTexCoord === true)
+ // remap texCoords to texel middle with w = 16 and tc' := 1 / (2 * w) + tc * (w - 1) / w
+ shader += "fragTexcoord = vec2(0.03125 + 0.9375 * (PG_precisionLevel / 16.0), 1.0);";
+ // LOD LUT HACK ###
+ }
+
+ if(properties.NORMALMAP && !x3dom.caps.STD_DERIVATIVES) {
+ shader += "fragTangent = (normalMatrix * vec4(tangent, 0.0)).xyz;\n";
+ shader += "fragBinormal = (normalMatrix * vec4(binormal, 0.0)).xyz;\n";
+ }
+ }
+
+ //Lights & Fog
+ if(properties.LIGHTS || properties.FOG || properties.CLIPPLANES){
+ shader += "fragPosition = (modelViewMatrix * vec4(vertPosition, 1.0));\n";
+ if (properties.FOG) {
+ shader += "fragEyePosition = eyePosition - fragPosition.xyz;\n";
+ }
+ }
+
+ //Vertex ID's
+ if (properties.MULTIDIFFALPMAP) {
+ shader += "fragID = id;\n";
+ }
+
+ //Displacement
+ if (properties.DISPLACEMENTMAP) {
+ shader += "vertPosition += normalize(vertNormal) * texture2D(displacementMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).r * displacementFactor;\n";
+ }
+ else if (properties.DIFFPLACEMENTMAP)
+ {
+ shader += "vertPosition += normalize(vertNormal) * texture2D(diffuseDisplacementMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).a * displacementFactor;\n";
+ }
+
+ //Positions
+ shader += "gl_Position = modelViewProjectionMatrix * vec4(vertPosition, 1.0);\n";
+
+ //Set point size
+ if (properties.IS_PARTICLE) {
+ shader += "float spriteDist = (gl_Position.w > 0.000001) ? gl_Position.w : 0.000001;\n";
+ shader += "float pointSize = floor(length(particleSize) * 256.0 / spriteDist + 0.5);\n";
+ shader += "gl_PointSize = clamp(pointSize, 2.0, 256.0);\n";
+ }
+ else {
+ shader += "gl_PointSize = 2.0;\n";
+ }
+
+ //END OF SHADER
+ shader += "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logInfo("VERTEX:\n" + shader);
+ x3dom.debug.logError("VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.DynamicShader.prototype.generateFragmentShader = function(gl, properties)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += " precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ /*******************************************************************************
+ * Generate dynamic uniforms & varyings
+ ********************************************************************************/
+
+ //Default Matrices
+ shader += "uniform mat4 modelMatrix;\n";
+ shader += "uniform mat4 modelViewMatrix;\n";
+ shader += "uniform mat4 viewMatrixInverse;\n";
+
+ //Material
+ shader += x3dom.shader.material();
+
+ if (properties.TWOSIDEDMAT ) {
+ shader += x3dom.shader.twoSidedMaterial();
+ }
+
+ //Colors
+ if(properties.VERTEXCOLOR){
+ if(properties.COLCOMPONENTS == 3){
+ shader += "varying vec3 fragColor; \n";
+ }else if(properties.COLCOMPONENTS == 4){
+ shader += "varying vec4 fragColor; \n";
+ }
+ }
+
+ if(properties.CUBEMAP || properties.CLIPPLANES)
+ {
+ shader += "uniform mat4 modelViewMatrixInverse;\n";
+ }
+
+ //Textures
+ if(properties.TEXTURED || properties.CSSHADER) {
+ shader += "varying vec2 fragTexcoord;\n";
+ if((properties.TEXTURED || properties.DIFFUSEMAP) && !properties.CUBEMAP) {
+ shader += "uniform sampler2D diffuseMap;\n";
+ } else if(properties.CUBEMAP) {
+ shader += "uniform samplerCube cubeMap;\n";
+ shader += "varying vec3 fragViewDir;\n";
+
+ }
+ if(properties.SPECMAP){
+ shader += "uniform sampler2D specularMap;\n";
+ }
+ if(properties.SHINMAP){
+ shader += "uniform sampler2D shininessMap;\n";
+ }
+ if (properties.DISPLACEMENTMAP) {
+ shader += "uniform sampler2D displacementMap;\n";
+ shader += "uniform float displacementWidth;\n";
+ shader += "uniform float displacementHeight;\n";
+ }
+ if (properties.DIFFPLACEMENTMAP) {
+ shader += "uniform sampler2D diffuseDisplacementMap;\n";
+ shader += "uniform float displacementWidth;\n";
+ shader += "uniform float displacementHeight;\n";
+ }
+ if (properties.MULTIDIFFALPMAP || properties.MULTIVISMAP) {
+ shader += "varying float fragID;\n";
+ }
+ if (properties.MULTIDIFFALPMAP) {
+ shader += "uniform sampler2D multiDiffuseAlphaMap;\n";
+ shader += "uniform float multiDiffuseAlphaWidth;\n";
+ shader += "uniform float multiDiffuseAlphaHeight;\n";
+ }
+ if (properties.MULTIEMIAMBMAP) {
+ shader += "uniform sampler2D multiEmissiveAmbientMap;\n";
+ shader += "uniform float multiEmissiveAmbientWidth;\n";
+ shader += "uniform float multiEmissiveAmbientHeight;\n";
+ }
+ if (properties.MULTISPECSHINMAP) {
+ shader += "uniform sampler2D multiSpecularShininessMap;\n";
+ shader += "uniform float multiSpecularShininessWidth;\n";
+ shader += "uniform float multiSpecularShininessHeight;\n";
+ }
+ if (properties.MULTIVISMAP) {
+ shader += "uniform sampler2D multiVisibilityMap;\n";
+ shader += "uniform float multiVisibilityWidth;\n";
+ shader += "uniform float multiVisibilityHeight;\n";
+ }
+ if(properties.NORMALMAP){
+ shader += "uniform sampler2D normalMap;\n";
+
+ if(x3dom.caps.STD_DERIVATIVES) {
+ shader += "#extension GL_OES_standard_derivatives:enable\n";
+ shader += x3dom.shader.TBNCalculation();
+ } else {
+ shader += "varying vec3 fragTangent;\n";
+ shader += "varying vec3 fragBinormal;\n";
+ }
+ }
+ }
+
+ //Fog
+ if(properties.FOG) {
+ shader += x3dom.shader.fog();
+ }
+
+ if(properties.LIGHTS || properties.CLIPPLANES)
+ {
+ shader += "varying vec4 fragPosition;\n";
+ }
+
+ //Lights
+ if(properties.LIGHTS) {
+ shader += "varying vec3 fragNormal;\n";
+
+ shader += x3dom.shader.light(properties.LIGHTS);
+ }
+
+ if(properties.CLIPPLANES) {
+ shader += x3dom.shader.clipPlanes(properties.CLIPPLANES);
+ }
+
+ // Declare gamma correction for color computation (see property "GAMMACORRECTION")
+ shader += x3dom.shader.gammaCorrectionDecl(properties);
+
+
+ /*******************************************************************************
+ * Generate main function
+ ********************************************************************************/
+ shader += "void main(void) {\n";
+
+
+ if(properties.CLIPPLANES)
+ {
+ shader += "vec3 cappingColor = calculateClipPlanes();\n";
+ }
+
+ //Init color. In the fragment shader we are treating color linear by
+ //gamma-adjusting actively before doing lighting computations. At the end
+ //the color value is encoded again. See shader propery GAMMACORRECTION.
+ shader += "vec4 color;\n";
+
+ shader += "color.rgb = " + x3dom.shader.decodeGamma(properties, "diffuseColor") + ";\n";
+ shader += "color.a = 1.0 - transparency;\n";
+
+ shader += "vec3 _emissiveColor = emissiveColor;\n";
+ shader += "float _shininess = shininess;\n";
+ shader += "vec3 _specularColor = specularColor;\n";
+ shader += "float _ambientIntensity = ambientIntensity;\n";
+
+ if (properties.MULTIVISMAP || properties.MULTIDIFFALPMAP || properties.MULTISPECSHINMAP || properties.MULTIEMIAMBMAP) {
+ shader += "vec2 idCoord;\n";
+ shader += "float roundedIDVisibility = floor(fragID+0.5);\n";
+ shader += "float roundedIDMaterial = floor(fragID+0.5);\n";
+ shader += "if(!gl_FrontFacing) {\n";
+ shader += " roundedIDMaterial = floor(fragID + (multiDiffuseAlphaWidth*multiDiffuseAlphaWidth) + 0.5);\n";
+ shader += "}\n";
+ }
+
+ if (properties.MULTIVISMAP) {
+ shader += "idCoord.x = mod(roundedIDVisibility, multiVisibilityWidth) * (1.0 / multiVisibilityWidth) + (0.5 / multiVisibilityWidth);\n";
+ shader += "idCoord.y = floor(roundedIDVisibility / multiVisibilityWidth) * (1.0 / multiVisibilityHeight) + (0.5 / multiVisibilityHeight);\n";
+ shader += "vec4 visibility = texture2D( multiVisibilityMap, idCoord );\n";
+ shader += "if (visibility.r < 1.0) discard; \n";
+ }
+
+ if (properties.MULTIDIFFALPMAP) {
+ shader += "idCoord.x = mod(roundedIDMaterial, multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaWidth) + (0.5 / multiDiffuseAlphaWidth);\n";
+ shader += "idCoord.y = floor(roundedIDMaterial / multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaHeight) + (0.5 / multiDiffuseAlphaHeight);\n";
+ shader += "vec4 diffAlpha = texture2D( multiDiffuseAlphaMap, idCoord );\n";
+ shader += "color.rgb = " + x3dom.shader.decodeGamma(properties, "diffAlpha.rgb") + ";\n";
+ shader += "color.a = diffAlpha.a;\n";
+ }
+
+ if (properties.MULTIEMIAMBMAP) {
+ shader += "idCoord.x = mod(roundedIDMaterial, multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaWidth) + (0.5 / multiDiffuseAlphaWidth);\n";
+ shader += "idCoord.y = floor(roundedIDMaterial / multiDiffuseAlphaWidth) * (1.0 / multiDiffuseAlphaHeight) + (0.5 / multiDiffuseAlphaHeight);\n";
+ shader += "vec4 emiAmb = texture2D( multiEmissiveAmbientMap, idCoord );\n";
+ shader += "_emissiveColor = emiAmb.rgb;\n";
+ shader += "_ambientIntensity = emiAmb.a;\n";
+ }
+
+ if(properties.VERTEXCOLOR) {
+ if(properties.COLCOMPONENTS === 3){
+ shader += "color.rgb = " + x3dom.shader.decodeGamma(properties,"fragColor") + ";\n";
+ }else if(properties.COLCOMPONENTS === 4){
+ shader += "color = " + x3dom.shader.decodeGamma(properties, "fragColor") + ";\n";
+ }
+ }
+
+ if(properties.LIGHTS) {
+ shader += "vec3 ambient = vec3(0.0, 0.0, 0.0);\n";
+ shader += "vec3 diffuse = vec3(0.0, 0.0, 0.0);\n";
+ shader += "vec3 specular = vec3(0.0, 0.0, 0.0);\n";
+ shader += "vec3 normal = normalize(fragNormal);\n";
+ shader += "vec3 eye = -fragPosition.xyz;\n";
+
+
+
+ //Normalmap
+ if(properties.NORMALMAP){
+ shader += "vec3 n = normalize( fragNormal );\n";
+
+ if (x3dom.caps.STD_DERIVATIVES) {
+ shader += "normal = perturb_normal( n, fragPosition.xyz, vec2(fragTexcoord.x, 1.0-fragTexcoord.y) );\n";
+ } else {
+ shader += "vec3 t = normalize( fragTangent );\n";
+ shader += "vec3 b = normalize( fragBinormal );\n";
+ shader += "mat3 tangentToWorld = mat3(t, b, n);\n";
+
+ shader += "normal = texture2D( normalMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y) ).rgb;\n";
+ shader += "normal = 2.0 * normal - 1.0;\n";
+ shader += "normal = normalize( normal * tangentToWorld );\n";
+
+ shader += "normal.y = -normal.y;\n";
+ shader += "normal.x = -normal.x;\n";
+ }
+ }
+
+ if(properties.SHINMAP){
+ shader += "_shininess = texture2D( shininessMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y) ).r;\n";
+ }
+
+ //Specularmap
+ if(properties.SPECMAP) {
+ shader += "_specularColor = " + x3dom.shader.decodeGamma(properties, "texture2D(specularMap, vec2(fragTexcoord.x, 1.0-fragTexcoord.y)).rgb") + ";\n";
+ }
+
+ if (properties.MULTISPECSHINMAP) {
+ shader += "idCoord.x = mod(roundedIDMaterial, multiSpecularShininessWidth) * (1.0 / multiSpecularShininessWidth) + (0.5 / multiSpecularShininessWidth);\n";
+ shader += "idCoord.y = floor(roundedIDMaterial / multiSpecularShininessWidth) * (1.0 / multiSpecularShininessHeight) + (0.5 / multiSpecularShininessHeight);\n";
+ shader += "vec4 specShin = texture2D( multiSpecularShininessMap, idCoord );\n";
+ shader += "_specularColor = specShin.rgb;\n";
+ shader += "_shininess = specShin.a;\n";
+ }
+
+ //Solid
+ if(!properties.SOLID || properties.TWOSIDEDMAT) {
+ shader += "if (dot(normal, eye) < 0.0) {\n";
+ shader += " normal *= -1.0;\n";
+ shader += "}\n";
+ }
+
+ if(properties.SEPARATEBACKMAT) {
+ shader += " if(!gl_FrontFacing) {\n";
+ shader += " color.rgb = " + x3dom.shader.decodeGamma(properties, "backDiffuseColor") + ";\n";
+ shader += " color.a = 1.0 - backTransparency;\n";
+ shader += " _shininess = backShininess;\n";
+ shader += " _emissiveColor = backEmissiveColor;\n";
+ shader += " _specularColor = backSpecularColor;\n";
+ shader += " _ambientIntensity = backAmbientIntensity;\n";
+ shader += " }\n";
+ }
+
+
+ //Calculate lights
+ if (properties.LIGHTS) {
+ shader += "vec3 ads;\n";
+
+ for(var l=0; l<properties.LIGHTS; l++) {
+ var lightCol = "light"+l+"_Color";
+ shader += "ads = lighting(light"+l+"_Type, " +
+ "light"+l+"_Location, " +
+ "light"+l+"_Direction, " +
+ lightCol + ", " +
+ "light"+l+"_Attenuation, " +
+ "light"+l+"_Radius, " +
+ "light"+l+"_Intensity, " +
+ "light"+l+"_AmbientIntensity, " +
+ "light"+l+"_BeamWidth, " +
+ "light"+l+"_CutOffAngle, " +
+ "normal, eye, _shininess, _ambientIntensity);\n";
+ shader += " ambient += " + lightCol + " * ads.r;\n" +
+ " diffuse += " + lightCol + " * ads.g;\n" +
+ " specular += " + lightCol + " * ads.b;\n";
+ }
+
+ shader += "ambient = max(ambient, 0.0);\n";
+ shader += "diffuse = max(diffuse, 0.0);\n";
+ shader += "specular = max(specular, 0.0);\n";
+ }
+
+ //Textures
+ if(properties.TEXTURED || properties.DIFFUSEMAP || properties.DIFFPLACEMENTMAP){
+ if(properties.CUBEMAP) {
+ shader += "vec3 viewDir = normalize(fragViewDir);\n";
+ shader += "vec3 reflected = reflect(viewDir, normal);\n";
+ shader += "reflected = (modelViewMatrixInverse * vec4(reflected,0.0)).xyz;\n";
+ shader += "vec4 texColor = " + x3dom.shader.decodeGamma(properties, "textureCube(cubeMap, reflected)") + ";\n";
+ shader += "color.a *= texColor.a;\n";
+ }
+ else if (properties.DIFFPLACEMENTMAP)
+ {
+ shader += "vec2 texCoord = vec2(fragTexcoord.x, 1.0-fragTexcoord.y);\n";
+ shader += "vec4 texColor = texture2D(diffuseDisplacementMap, texCoord);\n";
+ }
+ else
+ {
+ if (properties.PIXELTEX) {
+ shader += "vec2 texCoord = fragTexcoord;\n";
+ } else {
+ shader += "vec2 texCoord = vec2(fragTexcoord.x, 1.0-fragTexcoord.y);\n";
+ }
+ shader += "vec4 texColor = " + x3dom.shader.decodeGamma(properties, "texture2D(diffuseMap, texCoord)") + ";\n";
+ shader += "color.a *= texColor.a;\n";
+ }
+ if(properties.BLENDING){
+ shader += "color.rgb = (_emissiveColor + max(ambient + diffuse, 0.0) * color.rgb + specular*_specularColor);\n";
+ if(properties.CUBEMAP) {
+ shader += "color.rgb = mix(color.rgb, texColor.rgb, vec3(0.75));\n";
+ } else {
+ shader += "color.rgb *= texColor.rgb;\n";
+ }
+ }else{
+ shader += "color.rgb = (_emissiveColor + max(ambient + diffuse, 0.0) * texColor.rgb + specular*_specularColor);\n";
+ }
+ }else{
+ shader += "color.rgb = (_emissiveColor + max(ambient + diffuse, 0.0) * color.rgb + specular*_specularColor);\n";
+ }
+
+ } else {
+ if (properties.APPMAT && !properties.VERTEXCOLOR) {
+ shader += "color = vec4(0.0, 0.0, 0.0, 1.0 - transparency);\n";
+ }
+
+ if(properties.TEXTURED || properties.DIFFUSEMAP){
+ if (properties.PIXELTEX) {
+ shader += "vec2 texCoord = fragTexcoord;\n";
+ } else {
+ shader += "vec2 texCoord = vec2(fragTexcoord.x, 1.0-fragTexcoord.y);\n";
+ }
+
+ if (properties.IS_PARTICLE) {
+ shader += "texCoord = clamp(gl_PointCoord, 0.01, 0.99);\n";
+ }
+ shader += "vec4 texColor = " + x3dom.shader.decodeGamma(properties, "texture2D(diffuseMap, texCoord)") + ";\n";
+ shader += "color.a = texColor.a;\n";
+
+ if(properties.BLENDING || properties.IS_PARTICLE){
+ shader += "color.rgb += _emissiveColor.rgb;\n";
+ shader += "color.rgb *= texColor.rgb;\n";
+ } else {
+ shader += "color = texColor;\n";
+ }
+ } else if(!properties.VERTEXCOLOR && !properties.POINTLINE2D){
+ shader += "color.rgb += _emissiveColor;\n";
+ } else if(!properties.VERTEXCOLOR && properties.POINTLINE2D && !properties.MULTIDIFFALPMAP){
+ shader += "color.rgb = _emissiveColor;\n";
+ if (properties.IS_PARTICLE) {
+ shader += "float pAlpha = 1.0 - clamp(length((gl_PointCoord - 0.5) * 2.0), 0.0, 1.0);\n";
+ shader += "color.rgb *= vec3(pAlpha);\n";
+ shader += "color.a = pAlpha;\n";
+ }
+ } else if (properties.IS_PARTICLE) {
+ shader += "float pAlpha = 1.0 - clamp(length((gl_PointCoord - 0.5) * 2.0), 0.0, 1.0);\n";
+ shader += "color.rgb *= vec3(pAlpha);\n";
+ shader += "color.a = pAlpha;\n";
+ }
+ }
+
+ if(properties.CLIPPLANES)
+ {
+ shader += "if (cappingColor.r != -1.0) {\n";
+ shader += " color.rgb = cappingColor;\n";
+ shader += "}\n";
+ }
+
+ //Kill pixel
+ if(properties.TEXT) {
+ shader += "if (color.a <= 0.5) discard;\n";
+ } else {
+ shader += "if (color.a <= 0.1) discard;\n";
+ }
+
+ //Output the gamma encoded result.
+ shader += "color = clamp(color, 0.0, 1.0);\n";
+ shader += "color = " + x3dom.shader.encodeGamma(properties, "color") + ";\n";
+
+ //Fog
+ if(properties.FOG){
+ shader += "float f0 = calcFog(fragEyePosition);\n";
+ shader += "color.rgb = fogColor * (1.0-f0) + f0 * (color.rgb);\n";
+ }
+
+ shader += "gl_FragColor = color;\n";
+
+ //End Of Shader
+ shader += "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logInfo("FRAGMENT:\n" + shader);
+ x3dom.debug.logError("FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final Shader program
+ */
+x3dom.shader.DynamicMobileShader = function(gl, properties)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl, properties);
+ var fragmentShader = this.generateFragmentShader(gl, properties);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.DynamicMobileShader.prototype.generateVertexShader = function(gl, properties)
+{
+ var shader = "";
+
+ /*******************************************************************************
+ * Generate dynamic attributes & uniforms & varyings
+ ********************************************************************************/
+
+ //Material
+ shader += x3dom.shader.material();
+
+ if (properties.TWOSIDEDMAT ) {
+ shader += x3dom.shader.twoSidedMaterial();
+ }
+
+ //Default Matrices
+ shader += "uniform mat4 normalMatrix;\n";
+ shader += "uniform mat4 modelViewMatrix;\n";
+ shader += "uniform mat4 modelViewProjectionMatrix;\n";
+
+ //Positions
+ if(properties.POSCOMPONENTS == 3) {
+ shader += "attribute vec3 position;\n";
+ } else if(properties.POSCOMPONENTS == 4) {
+ shader += "attribute vec4 position;\n";
+ }
+
+ //IG stuff
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform vec3 IG_bboxMin;\n";
+ shader += "uniform vec3 IG_bboxMax;\n";
+ shader += "uniform float IG_coordTextureWidth;\n";
+ shader += "uniform float IG_coordTextureHeight;\n";
+ shader += "uniform vec2 IG_implicitMeshSize;\n";
+
+ for( var i = 0; i < properties.IG_PRECISION; i++ ) {
+ shader += "uniform sampler2D IG_coords" + i + "\n;";
+ }
+
+ if(properties.IG_INDEXED) {
+ shader += "uniform sampler2D IG_index;\n";
+ shader += "uniform float IG_indexTextureWidth;\n";
+ shader += "uniform float IG_indexTextureHeight;\n";
+ }
+ }
+
+ //PG stuff
+ if (properties.POPGEOMETRY) {
+ shader += "uniform float PG_precisionLevel;\n";
+ shader += "uniform float PG_powPrecision;\n";
+ shader += "uniform vec3 PG_maxBBSize;\n";
+ shader += "uniform vec3 PG_bbMin;\n";
+ shader += "uniform vec3 PG_bbMaxModF;\n";
+ shader += "uniform vec3 PG_bboxShiftVec;\n";
+ shader += "uniform float PG_numAnchorVertices;\n";
+ shader += "attribute float PG_vertexID;\n";
+ }
+
+ //Normals
+ if(!properties.POINTLINE2D) {
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform sampler2D IG_normals;\n";
+ } else {
+ if(properties.NORCOMPONENTS == 2) {
+ if(properties.POSCOMPONENTS != 4) {
+ shader += "attribute vec2 normal;\n";
+ }
+ } else if(properties.NORCOMPONENTS == 3) {
+ shader += "attribute vec3 normal;\n";
+ }
+ }
+ }
+
+ //Colors
+ shader += "varying vec4 fragColor;\n";
+ if(properties.VERTEXCOLOR){
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform sampler2D IG_colors;";
+ } else {
+ if(properties.COLCOMPONENTS == 3){
+ shader += "attribute vec3 color;";
+ } else if(properties.COLCOMPONENTS == 4) {
+ shader += "attribute vec4 color;";
+ }
+ }
+ }
+
+ //Textures
+ if(properties.TEXTURED) {
+ shader += "varying vec2 fragTexcoord;\n";
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform sampler2D IG_texCoords;";
+ } else {
+ shader += "attribute vec2 texcoord;\n";
+ }
+ if(properties.TEXTRAFO){
+ shader += "uniform mat4 texTrafoMatrix;\n";
+ }
+ if(!properties.BLENDING) {
+ shader += "varying vec3 fragAmbient;\n";
+ shader += "varying vec3 fragDiffuse;\n";
+ }
+ if(properties.CUBEMAP) {
+ shader += "varying vec3 fragViewDir;\n";
+ shader += "varying vec3 fragNormal;\n";
+ shader += "uniform mat4 viewMatrix;\n";
+ }
+ }
+
+ //Fog
+ if(properties.FOG) {
+ shader += x3dom.shader.fog();
+ }
+
+ //Lights
+ if(properties.LIGHTS) {
+ shader += x3dom.shader.light(properties.LIGHTS);
+ }
+
+ //Bounding Boxes
+ if(properties.REQUIREBBOX) {
+ shader += "uniform vec3 bgCenter;\n";
+ shader += "uniform vec3 bgSize;\n";
+ shader += "uniform float bgPrecisionMax;\n";
+ }
+ if(properties.REQUIREBBOXNOR) {
+ shader += "uniform float bgPrecisionNorMax;\n";
+ }
+ if(properties.REQUIREBBOXCOL) {
+ shader += "uniform float bgPrecisionColMax;\n";
+ }
+ if(properties.REQUIREBBOXTEX) {
+ shader += "uniform float bgPrecisionTexMax;\n";
+ }
+
+
+ /*******************************************************************************
+ * Generate main function
+ ********************************************************************************/
+ shader += "void main(void) {\n";
+
+ //Set point size
+ shader += "gl_PointSize = 2.0;\n";
+
+ /*******************************************************************************
+ * Start of ImageGeometry switch
+ ********************************************************************************/
+ if(properties.IMAGEGEOMETRY) {
+ //Indices
+ if(properties.IG_INDEXED) {
+ shader += "vec2 halfPixel = vec2(0.5/IG_indexTextureWidth,0.5/IG_indexTextureHeight);\n";
+ shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_indexTextureWidth), position.y*(IG_implicitMeshSize.y/IG_indexTextureHeight)) + halfPixel;\n";
+ shader += "vec2 IG_indices = texture2D( IG_index, IG_texCoord ).rg;\n";
+ shader += "halfPixel = vec2(0.5/IG_coordTextureWidth,0.5/IG_coordTextureHeight);\n";
+ shader += "IG_texCoord = (IG_indices * 0.996108948) + halfPixel;\n";
+ } else {
+ shader += "vec2 halfPixel = vec2(0.5/IG_coordTextureWidth, 0.5/IG_coordTextureHeight);\n";
+ shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_coordTextureWidth), position.y*(IG_implicitMeshSize.y/IG_coordTextureHeight)) + halfPixel;\n";
+ }
+
+ //Positions
+ shader += "vec3 temp = vec3(0.0, 0.0, 0.0);\n";
+ shader += "vec3 vertPosition = vec3(0.0, 0.0, 0.0);\n";
+
+ for(var i=0; i<properties.IG_PRECISION; i++) {
+ shader += "temp = 255.0 * texture2D( IG_coords" + i + ", IG_texCoord ).rgb;\n";
+ shader += "vertPosition *= 256.0;\n";
+ shader += "vertPosition += temp;\n";
+ }
+
+ shader += "vertPosition /= (pow(2.0, 8.0 * " + properties.IG_PRECISION + ".0) - 1.0);\n";
+ shader += "vertPosition = vertPosition * (IG_bboxMax - IG_bboxMin) + IG_bboxMin;\n";
+
+ //Normals
+ if(!properties.POINTLINE2D) {
+ shader += "vec3 vertNormal = texture2D( IG_normals, IG_texCoord ).rgb;\n";
+ shader += "vertNormal = vertNormal * 2.0 - 1.0;\n";
+ }
+
+ //Colors
+ if(properties.VERTEXCOLOR) {
+ if(properties.COLCOMPONENTS == 3) {
+ shader += "vec3 vertColor = texture2D( IG_colors, IG_texCoord ).rgb;";
+ } else if(properties.COLCOMPONENTS == 4) {
+ shader += "vec4 vertColor = texture2D( IG_colors, IG_texCoord ).rgba;";
+ }
+ }
+
+ //TexCoords
+ if(properties.TEXTURED) {
+ shader += "vec4 IG_doubleTexCoords = texture2D( IG_texCoords, IG_texCoord );\n";
+ shader += "vec2 vertTexCoord;";
+ shader += "vertTexCoord.r = (IG_doubleTexCoords.r * 0.996108948) + (IG_doubleTexCoords.b * 0.003891051);\n";
+ shader += "vertTexCoord.g = (IG_doubleTexCoords.g * 0.996108948) + (IG_doubleTexCoords.a * 0.003891051);\n";
+ }
+ } else {
+ //Positions
+ shader += "vec3 vertPosition = position.xyz;\n";
+
+ if (properties.POPGEOMETRY) {
+ //compute offset using bounding box and test if vertPosition <= PG_bbMaxModF
+ shader += "vec3 offsetVec = step(vertPosition / bgPrecisionMax, PG_bbMaxModF) * PG_bboxShiftVec;\n";
+
+ //coordinate truncation, computation of current maximum possible value
+ //PG_vertexID currently mimics use of gl_VertexID
+ shader += "if ((PG_precisionLevel <= 2.0) || PG_vertexID >= PG_numAnchorVertices) {\n";
+ shader += " vertPosition = floor(vertPosition / PG_powPrecision) * PG_powPrecision;\n";
+ shader += " vertPosition /= (65536.0 - PG_powPrecision);\n";
+ shader += "}\n";
+ shader += "else {\n";
+ shader += " vertPosition /= bgPrecisionMax;\n";
+ shader += "}\n";
+
+ //translate coordinates, where PG_bbMin := floor(bbMin / size)
+ shader += "vertPosition = (vertPosition + offsetVec + PG_bbMin) * PG_maxBBSize;\n";
+ }
+ else if(properties.REQUIREBBOX) {
+ shader += "vertPosition = bgCenter + bgSize * vertPosition / bgPrecisionMax;\n";
+ }
+
+ //Normals
+ if(!properties.POINTLINE2D) {
+ if (properties.NORCOMPONENTS == 2) {
+ if (properties.POSCOMPONENTS == 4) {
+ // (theta, phi) encoded in low/high byte of position.w
+ shader += "vec3 vertNormal = vec3(position.w / 256.0); \n";
+ shader += "vertNormal.x = floor(vertNormal.x) / 255.0; \n";
+ shader += "vertNormal.y = fract(vertNormal.y) * 1.00392156862745; \n"; //256.0 / 255.0
+ } else if (properties.REQUIREBBOXNOR) {
+ shader += "vec3 vertNormal = vec3(normal.xy, 0.0) / bgPrecisionNorMax;\n";
+ } else {
+ shader += "vec3 vertNormal = vec3(normal.xy, 0.0);\n";
+ }
+
+ shader += "vec2 thetaPhi = 3.14159265358979 * vec2(vertNormal.x, vertNormal.y*2.0-1.0); \n";
+
+ // Doing approximation with Taylor series and using cos(x) = sin(x+PI/2)
+ shader += "vec4 sinCosThetaPhi = vec4(thetaPhi, thetaPhi + 1.5707963267949); \n";
+
+ shader += "vec4 thetaPhiPow2 = sinCosThetaPhi * sinCosThetaPhi; \n";
+ shader += "vec4 thetaPhiPow3 = thetaPhiPow2 * sinCosThetaPhi; \n";
+ shader += "vec4 thetaPhiPow5 = thetaPhiPow3 * thetaPhiPow2; \n";
+ shader += "vec4 thetaPhiPow7 = thetaPhiPow5 * thetaPhiPow2; \n";
+ shader += "vec4 thetaPhiPow9 = thetaPhiPow7 * thetaPhiPow2; \n";
+
+ shader += "sinCosThetaPhi += -0.16666666667 * thetaPhiPow3; \n";
+ shader += "sinCosThetaPhi += 0.00833333333 * thetaPhiPow5; \n";
+ shader += "sinCosThetaPhi += -0.000198412698 * thetaPhiPow7; \n";
+ shader += "sinCosThetaPhi += 0.0000027557319 * thetaPhiPow9; \n";
+
+ shader += "vertNormal.x = sinCosThetaPhi.x * sinCosThetaPhi.w; \n";
+ shader += "vertNormal.y = sinCosThetaPhi.x * sinCosThetaPhi.y; \n";
+ shader += "vertNormal.z = sinCosThetaPhi.z; \n";
+ } else {
+ shader += "vec3 vertNormal = normal;\n";
+ if (properties.REQUIREBBOXNOR) {
+ shader += "vertNormal = vertNormal / bgPrecisionNorMax;\n";
+ }
+ if (properties.POPGEOMETRY) {
+ shader += "vertNormal = 2.0*vertNormal - 1.0;\n";
+ }
+ }
+ }
+
+ //Colors
+ if(properties.VERTEXCOLOR) {
+ if(properties.COLCOMPONENTS == 3) {
+ shader += "vec3 vertColor = color;";
+ } else if(properties.COLCOMPONENTS == 4) {
+ shader += "vec4 vertColor = color;";
+ }
+ if(properties.REQUIREBBOXCOL) {
+ shader += "vertColor = vertColor / bgPrecisionColMax;\n";
+ }
+ }
+
+ //TexCoords
+ if(properties.TEXTURED) {
+ shader += "vec2 vertTexCoord = texcoord;\n";
+ if(properties.REQUIREBBOXTEX) {
+ shader += "vertTexCoord = vertTexCoord / bgPrecisionTexMax;\n";
+ }
+ }
+ }
+ /*******************************************************************************
+ * End of ImageGeometry switch
+ ********************************************************************************/
+
+ //positions to model-view-space
+ shader += "vec3 positionMV = (modelViewMatrix * vec4(vertPosition, 1.0)).xyz;\n";
+
+ //normals to model-view-space
+ if(!properties.POINTLINE2D) {
+ shader += "vec3 normalMV = normalize( (normalMatrix * vec4(vertNormal, 0.0)).xyz );\n";
+ }
+
+ shader += "vec3 eye = -positionMV;\n";
+
+ //Colors
+ if (properties.VERTEXCOLOR) {
+ shader += "vec3 rgb = vertColor.rgb;\n";
+ if(properties.COLCOMPONENTS == 4) {
+ shader += "float alpha = vertColor.a;\n";
+ } else if(properties.COLCOMPONENTS == 3) {
+ shader += "float alpha = 1.0 - transparency;\n";
+ }
+ } else {
+ shader += "vec3 rgb = diffuseColor;\n";
+ shader += "float alpha = 1.0 - transparency;\n";
+ }
+
+ //Calc TexCoords
+ if(properties.TEXTURED){
+ if(properties.CUBEMAP) {
+ shader += "fragViewDir = viewMatrix[3].xyz;\n";
+ shader += "fragNormal = normalMV;\n";
+ } else if(properties.SPHEREMAPPING) {
+ shader += " fragTexcoord = 0.5 + normalMV.xy / 2.0;\n";
+ } else if(properties.TEXTRAFO) {
+ shader += " fragTexcoord = (texTrafoMatrix * vec4(vertTexCoord, 1.0, 1.0)).xy;\n";
+ } else {
+ shader += " fragTexcoord = vertTexCoord;\n";
+
+ // LOD LUT HACK ###
+ if (properties.POPGEOMETRY && x3dom.debug.usePrecisionLevelAsTexCoord === true)
+ // remap texCoords to texel middle with w = 16 and tc' := 1 / (2 * w) + tc * (w - 1) / w
+ shader += "fragTexcoord = vec2(0.03125 + 0.9375 * (PG_precisionLevel / 16.0), 1.0);";
+ // LOD LUT HACK ###
+ }
+ }
+
+ //calc lighting
+ if(properties.LIGHTS) {
+ shader += "vec3 ambient = vec3(0.0, 0.0, 0.0);\n";
+ shader += "vec3 diffuse = vec3(0.0, 0.0, 0.0);\n";
+ shader += "vec3 specular = vec3(0.0, 0.0, 0.0);\n";
+ shader += "float _shininess = shininess;\n";
+ shader += "vec3 _specularColor = specularColor;\n";
+ shader += "vec3 _emissiveColor = emissiveColor;\n";
+ shader += "float _ambientIntensity = ambientIntensity;\n";
+
+ //Solid
+ if(!properties.SOLID || properties.TWOSIDEDMAT) {
+ shader += "if (dot(normalMV, eye) < 0.0) {\n";
+ shader += " normalMV *= -1.0;\n";
+ if(properties.SEPARATEBACKMAT) {
+ shader += " rgb = backDiffuseColor;\n";
+ shader += " alpha = 1.0 - backTransparency;\n";
+ shader += " _shininess = backShininess;\n";
+ shader += " _emissiveColor = backEmissiveColor;\n";
+ shader += " _specularColor = backSpecularColor;\n";
+ shader += " _ambientIntensity = backAmbientIntensity;\n";
+ }
+ shader += " }\n";
+ }
+
+ //Calculate lighting
+ if (properties.LIGHTS) {
+ shader += "vec3 ads;\n";
+
+ for(var l=0; l<properties.LIGHTS; l++) {
+ var lightCol = "light"+l+"_Color";
+ shader += "ads = lighting(light"+l+"_Type, " +
+ "light"+l+"_Location, " +
+ "light"+l+"_Direction, " +
+ lightCol + ", " +
+ "light"+l+"_Attenuation, " +
+ "light"+l+"_Radius, " +
+ "light"+l+"_Intensity, " +
+ "light"+l+"_AmbientIntensity, " +
+ "light"+l+"_BeamWidth, " +
+ "light"+l+"_CutOffAngle, " +
+ "normalMV, eye, _shininess, _ambientIntensity);\n";
+ shader += " ambient += " + lightCol + " * ads.r;\n" +
+ " diffuse += " + lightCol + " * ads.g;\n" +
+ " specular += " + lightCol + " * ads.b;\n";
+ }
+
+ shader += "ambient = max(ambient, 0.0);\n";
+ shader += "diffuse = max(diffuse, 0.0);\n";
+ shader += "specular = max(specular, 0.0);\n";
+ }
+
+ //Textures & blending
+ if(properties.TEXTURED && !properties.BLENDING) {
+ shader += "fragAmbient = ambient;\n";
+ shader += "fragDiffuse = diffuse;\n";
+ shader += "fragColor.rgb = (_emissiveColor + specular*_specularColor);\n";
+ shader += "fragColor.a = alpha;\n";
+ } else {
+ shader += "fragColor.rgb = (_emissiveColor + max(ambient + diffuse, 0.0) * rgb + specular*_specularColor);\n";
+ shader += "fragColor.a = alpha;\n";
+ }
+ } else {
+ if (properties.APPMAT && !properties.VERTEXCOLOR) {
+ shader += "rgb = vec3(0.0, 0.0, 0.0);\n";
+ }
+ if(properties.TEXTURED && !properties.BLENDING) {
+ shader += "fragAmbient = vec3(0.0);\n";
+ shader += "fragDiffuse = vec3(1.0);\n";
+ shader += "fragColor.rgb = vec3(0.0);\n";
+ shader += "fragColor.a = alpha;\n";
+ } else if(!properties.VERTEXCOLOR && properties.POINTLINE2D){
+ shader += "fragColor.rgb = emissiveColor;\n";
+ shader += "fragColor.a = alpha;\n";
+ } else {
+ shader += "fragColor.rgb = rgb + emissiveColor;\n";
+ shader += "fragColor.a = alpha;\n";
+ }
+ }
+
+ //Fog
+ if(properties.FOG) {
+ shader += "float f0 = calcFog(-positionMV);\n";
+ shader += "fragColor.rgb = fogColor * (1.0-f0) + f0 * (fragColor.rgb);\n";
+ }
+
+ //Output
+ shader += "gl_Position = modelViewProjectionMatrix * vec4(vertPosition, 1.0);\n";
+
+ //End of shader
+ shader += "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[DynamicMobileShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.DynamicMobileShader.prototype.generateFragmentShader = function(gl, properties)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ /*******************************************************************************
+ * Generate dynamic uniforms & varyings
+ ********************************************************************************/
+ //Colors
+ shader += "varying vec4 fragColor;\n";
+
+ //Textures
+ if(properties.TEXTURED) {
+ if(properties.CUBEMAP) {
+ shader += "uniform samplerCube cubeMap;\n";
+ shader += "varying vec3 fragViewDir;\n";
+ shader += "varying vec3 fragNormal;\n";
+ shader += "uniform mat4 modelViewMatrixInverse;\n";
+ } else {
+ shader += "uniform sampler2D diffuseMap; \n";
+ shader += "varying vec2 fragTexcoord; \n";
+ }
+ if(!properties.BLENDING) {
+ shader += "varying vec3 fragAmbient;\n";
+ shader += "varying vec3 fragDiffuse;\n";
+ }
+ }
+
+ /*******************************************************************************
+ * Generate main function
+ ********************************************************************************/
+ shader += "void main(void) {\n";
+
+ //Colors
+ shader += "vec4 color = fragColor;\n";
+
+ //Textures
+ if(properties.TEXTURED){
+ if(properties.CUBEMAP) {
+ shader += "vec3 normal = normalize(fragNormal);\n";
+ shader += "vec3 viewDir = normalize(fragViewDir);\n";
+ shader += "vec3 reflected = reflect(viewDir, normal);\n";
+ shader += "reflected = (modelViewMatrixInverse * vec4(reflected,0.0)).xyz;\n";
+ shader += "vec4 texColor = textureCube(cubeMap, reflected);\n";
+ } else {
+ shader += "vec4 texColor = texture2D(diffuseMap, vec2(fragTexcoord.s, 1.0-fragTexcoord.t));\n";
+ }
+ if(properties.BLENDING) {
+ if(properties.CUBEMAP) {
+ shader += "color.rgb = mix(color.rgb, texColor.rgb, vec3(0.75));\n";
+ shader += "color.a = texColor.a;\n";
+ } else {
+ shader += "color.rgb *= texColor.rgb;\n";
+ shader += "color.a *= texColor.a;\n";
+ }
+ } else {
+ shader += "color.rgb += max(fragAmbient + fragDiffuse, 0.0) * texColor.rgb;\n";
+ shader += "color.a *= texColor.a;\n";
+ }
+ }
+
+ //Kill pixel
+ if(properties.TEXT) {
+ shader += "if (color.a <= 0.5) discard;\n";
+ } else {
+ shader += "if (color.a <= 0.1) discard;\n";
+ }
+
+ //Output
+ shader += "gl_FragColor = clamp(color, 0.0, 1.0);\n";
+
+ //End of shader
+ shader += "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[DynamicMobileShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final Shader program
+ */
+x3dom.shader.DynamicShaderPicking = function(gl, properties, pickMode)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl, properties, pickMode);
+ var fragmentShader = this.generateFragmentShader(gl, properties, pickMode);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.DynamicShaderPicking.prototype.generateVertexShader = function(gl, properties, pickMode)
+{
+ var shader = "";
+
+ /*******************************************************************************
+ * Generate dynamic attributes & uniforms & varyings
+ ********************************************************************************/
+
+ //Default Matrices
+ shader += "uniform mat4 modelMatrix;\n";
+ shader += "uniform mat4 modelViewProjectionMatrix;\n";
+
+ shader += "attribute vec3 position;\n";
+ shader += "uniform vec3 from;\n";
+ shader += "varying vec3 worldCoord;\n";
+
+ if(pickMode == 1) { // Color Picking
+ shader += "attribute vec3 color;\n";
+ shader += "varying vec3 fragColor;\n";
+ } else if(pickMode == 2){ //TexCoord Picking
+ shader += "attribute vec2 texcoord;\n";
+ shader += "varying vec3 fragColor;\n";
+ }
+
+ //Bounding stuff
+ if(properties.REQUIREBBOX) {
+ shader += "uniform vec3 bgCenter;\n";
+ shader += "uniform vec3 bgSize;\n";
+ shader += "uniform float bgPrecisionMax;\n";
+ }
+ if(properties.REQUIREBBOXCOL) {
+ shader += "uniform float bgPrecisionColMax;\n";
+ }
+ if(properties.REQUIREBBOXTEX) {
+ shader += "uniform float bgPrecisionTexMax;\n";
+ }
+
+ //ShadowID stuff
+ if(properties.VERTEXID) {
+ shader += "uniform float shadowIDs;\n";
+
+ if (pickMode == 3) { //24bit
+ shader += "varying vec3 idCoord;\n";
+ } else {
+ shader += "varying vec2 idCoord;\n";
+ }
+ shader += "varying float fragID;\n";
+ shader += "attribute float id;\n";
+ }
+
+ //ImageGeometry stuff
+ if(properties.IMAGEGEOMETRY) {
+ shader += "uniform vec3 IG_bboxMin;\n";
+ shader += "uniform vec3 IG_bboxMax;\n";
+ shader += "uniform float IG_coordTextureWidth;\n";
+ shader += "uniform float IG_coordTextureHeight;\n";
+ shader += "uniform vec2 IG_implicitMeshSize;\n";
+
+ for( var i = 0; i < properties.IG_PRECISION; i++ ) {
+ shader += "uniform sampler2D IG_coords" + i + "\n;";
+ }
+
+ if(properties.IG_INDEXED) {
+ shader += "uniform sampler2D IG_index;\n";
+ shader += "uniform float IG_indexTextureWidth;\n";
+ shader += "uniform float IG_indexTextureHeight;\n";
+ }
+ }
+
+ //PopGeometry
+ if (properties.POPGEOMETRY) {
+ shader += "uniform float PG_precisionLevel;\n";
+ shader += "uniform float PG_powPrecision;\n";
+ shader += "uniform vec3 PG_maxBBSize;\n";
+ shader += "uniform vec3 PG_bbMin;\n";
+ shader += "uniform vec3 PG_bbMaxModF;\n";
+ shader += "uniform vec3 PG_bboxShiftVec;\n";
+ shader += "uniform float PG_numAnchorVertices;\n";
+ shader += "attribute float PG_vertexID;\n";
+ }
+
+ //ClipPlane stuff
+ if(properties.CLIPPLANES) {
+ shader += "uniform mat4 modelViewMatrix;\n";
+ shader += "varying vec4 fragPosition;\n";
+ }
+
+
+ /*******************************************************************************
+ * Generate main function
+ ********************************************************************************/
+
+ shader += "void main(void) {\n";
+
+ shader += "gl_PointSize = 2.0;\n";
+ shader += "vec3 pos = position;\n";
+
+
+ if(properties.VERTEXID) {
+ if(pickMode == 0) { //Default Picking
+ shader += "idCoord = vec2((id + shadowIDs) / 256.0);\n";
+ shader += "idCoord.x = floor(idCoord.x) / 255.0;\n";
+ shader += "idCoord.y = fract(idCoord.y) * 1.00392156862745;\n";
+ shader += "fragID = id;\n";
+ } else if(pickMode == 3) { //Picking with 24bit precision
+ //composed id is at least 32 (= 2*16) bit + num bits for max-orig-shape-id
+ shader += "float ID = id + shadowIDs;\n";
+ //however, let's ignore this and assume a maximum of 24 bits for all id's
+ shader += "float h = floor(ID / 256.0);\n";
+ shader += "idCoord.x = ID - (h * 256.0);\n";
+ shader += "idCoord.z = floor(h / 256.0);\n";
+ shader += "idCoord.y = h - (idCoord.z * 256.0);\n";
+ shader += "idCoord = idCoord.zyx / 255.0;\n";
+ shader += "fragID = id;\n";
+ } else if(pickMode == 4) { //Picking with 32bit precision
+ shader += "idCoord = vec2((id + shadowIDs) / 256.0);\n";
+ shader += "idCoord.x = floor(idCoord.x) / 255.0;\n";
+ shader += "idCoord.y = fract(idCoord.y) * 1.00392156862745;\n";
+ shader += "fragID = id;\n";
+ }
+ }
+
+ /*******************************************************************************
+ * Start of special Geometry switch
+ ********************************************************************************/
+ if(properties.IMAGEGEOMETRY) { //ImageGeometry
+ if(properties.IG_INDEXED) {
+ shader += "vec2 halfPixel = vec2(0.5/IG_indexTextureWidth,0.5/IG_indexTextureHeight);\n";
+ shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_indexTextureWidth), position.y*(IG_implicitMeshSize.y/IG_indexTextureHeight)) + halfPixel;\n";
+ shader += "vec2 IG_indices = texture2D( IG_index, IG_texCoord ).rg;\n";
+ shader += "halfPixel = vec2(0.5/IG_coordTextureWidth,0.5/IG_coordTextureHeight);\n";
+ shader += "IG_texCoord = (IG_indices * 0.996108948) + halfPixel;\n";
+ } else {
+ shader += "vec2 halfPixel = vec2(0.5/IG_coordTextureWidth, 0.5/IG_coordTextureHeight);\n";
+ shader += "vec2 IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_coordTextureWidth), position.y*(IG_implicitMeshSize.y/IG_coordTextureHeight)) + halfPixel;\n";
+ }
+
+ shader += "pos = texture2D( IG_coordinateTexture, IG_texCoord ).rgb;\n";
+ shader += "pos = pos * (IG_bboxMax - IG_bboxMin) + IG_bboxMin;\n";
+ } else if (properties.POPGEOMETRY) { //PopGeometry
+ shader += "vec3 offsetVec = step(pos / bgPrecisionMax, PG_bbMaxModF) * PG_bboxShiftVec;\n";
+ shader += "if (PG_precisionLevel <= 2.0) {\n";
+ shader += "pos = floor(pos / PG_powPrecision) * PG_powPrecision;\n";
+ shader += "pos /= (65536.0 - PG_powPrecision);\n";
+ shader += "}\n";
+ shader += "else {\n";
+ shader += "pos /= bgPrecisionMax;\n";
+ shader += "}\n";
+ shader += "pos = (pos + offsetVec + PG_bbMin) * PG_maxBBSize;\n";
+ } else {
+
+ if(properties.REQUIREBBOX) {
+ shader += "pos = bgCenter + bgSize * pos / bgPrecisionMax;\n";
+ }
+
+ if(pickMode == 1 && !properties.REQUIREBBOXCOL) { //Color Picking
+ shader += "fragColor = color;\n";
+ } else if(pickMode == 1 && properties.REQUIREBBOXCOL) { //Color Picking
+ shader += "fragColor = color / bgPrecisionColMax;\n";
+ } else if(pickMode == 2 && !properties.REQUIREBBOXTEX) { //TexCoord Picking
+ shader += "fragColor = vec3(abs(texcoord.x), abs(texcoord.y), 0.0);\n";
+ } else if(pickMode == 2 && properties.REQUIREBBOXTEX) { //TexCoord Picking
+ shader += "vec2 texCoord = texcoord / bgPrecisionTexMax;\n";
+ shader += "fragColor = vec3(abs(texCoord.x), abs(texCoord.y), 0.0);\n";
+ }
+ }
+
+ if(properties.CLIPPLANES) {
+ shader += "fragPosition = (modelViewMatrix * vec4(pos, 1.0));\n";
+ }
+
+ shader += "worldCoord = (modelMatrix * vec4(pos, 1.0)).xyz - from;\n";
+ shader += "gl_Position = modelViewProjectionMatrix * vec4(pos, 1.0);\n";
+
+
+ //END OF SHADER
+ shader += "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logInfo("VERTEX:\n" + shader);
+ x3dom.debug.logError("VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.DynamicShaderPicking.prototype.generateFragmentShader = function(gl, properties, pickMode)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += " precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ /*******************************************************************************
+ * Generate dynamic uniforms & varyings
+ ********************************************************************************/
+
+ shader += "uniform float highBit;\n";
+ shader += "uniform float lowBit;\n";
+ shader += "uniform float sceneSize;\n";
+ shader += "varying vec3 worldCoord;\n";
+
+ if(pickMode == 1 || pickMode == 2) {
+ shader += "varying vec3 fragColor;\n";
+ }
+
+ //ShadowID stuff
+ if(properties.VERTEXID) {
+ if (pickMode == 3) { //24bit
+ shader += "varying vec3 idCoord;\n";
+ } else {
+ shader += "varying vec2 idCoord;\n";
+ }
+ shader += "varying float fragID;\n";
+ }
+
+ //ClipPlane stuff
+ if(properties.CLIPPLANES) {
+ shader += "uniform mat4 viewMatrixInverse;\n";
+ shader += "varying vec4 fragPosition;\n";
+ }
+
+ if (properties.MULTIVISMAP) {
+ shader += "uniform sampler2D multiVisibilityMap;\n";
+ shader += "uniform float multiVisibilityWidth;\n";
+ shader += "uniform float multiVisibilityHeight;\n";
+ }
+
+ if(properties.CLIPPLANES) {
+ shader += x3dom.shader.clipPlanes(properties.CLIPPLANES);
+ }
+
+ /*******************************************************************************
+ * Generate main function
+ ********************************************************************************/
+ shader += "void main(void) {\n";
+
+ if(properties.CLIPPLANES)
+ {
+ shader += "calculateClipPlanes();\n";
+ }
+
+ if(pickMode == 1 || pickMode == 2) { //Picking Color || Picking TexCoord
+ shader += "vec4 color = vec4(fragColor, lowBit);\n";
+ } else if(pickMode == 4) { //Picking with 32bit precision
+ shader += "vec4 color = vec4(highBit, lowBit, 0.0, 0.0);\n";
+ } else {
+ shader += "vec4 color = vec4(0.0, 0.0, highBit, lowBit);\n";
+ }
+
+ if(properties.VERTEXID) {
+ if(pickMode == 0 || pickMode == 4) { //Default Picking || Picking with 32bit precision
+ shader += "color.ba = idCoord;\n";
+ } else if(pickMode == 3) { //Picking with 24bit precision
+ shader += "color.gba = idCoord;\n";
+ }
+
+ if (properties.MULTIVISMAP) {
+ shader += "vec2 idTexCoord;\n";
+ shader += "float roundedID = floor(fragID+0.5);\n";
+ shader += "idTexCoord.x = (mod(roundedID, multiVisibilityWidth)) * (1.0 / multiVisibilityWidth) + (0.5 / multiVisibilityWidth);\n";
+ shader += "idTexCoord.y = (floor(roundedID / multiVisibilityHeight)) * (1.0 / multiVisibilityHeight) + (0.5 / multiVisibilityHeight);\n";
+ shader += "vec4 visibility = texture2D( multiVisibilityMap, idTexCoord );\n";
+ shader += "if (visibility.r < 1.0) discard; \n";
+ }
+ }
+
+ if(pickMode != 1 && pickMode != 2) {
+ shader += "float d = length(worldCoord) / sceneSize;\n";
+ }
+
+ if(pickMode == 0) { //Default Picking
+ shader += "vec2 comp = fract(d * vec2(256.0, 1.0));\n";
+ shader += "color.rg = comp - (comp.rr * vec2(0.0, 1.0/256.0));\n";
+ } else if(pickMode == 3) { //Picking with 24bit precision
+ shader += "color.r = d;\n";
+ }
+
+ shader += "gl_FragColor = color;\n";
+
+ //END OF SHADER
+ shader += "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logInfo("FRAGMENT:\n" + shader);
+ x3dom.debug.logError("FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final Shader program
+ */
+x3dom.shader.ComposedShader = function(gl, shape)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl, shape);
+ var fragmentShader = this.generateFragmentShader(gl, shape);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.ComposedShader.prototype.generateVertexShader = function(gl, shape)
+{
+ var shader = shape._cf.appearance.node._shader._vertex._vf.url[0];
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[ComposedShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.ComposedShader.prototype.generateFragmentShader = function(gl, shape)
+{
+ var shader = shape._cf.appearance.node._shader._fragment._vf.url[0];
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[ComposedShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final Shader program
+ */
+x3dom.shader.NormalShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.NormalShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "attribute vec3 position;\n" +
+ "attribute vec3 normal;\n" +
+ "uniform vec3 bgCenter;\n" +
+ "uniform vec3 bgSize;\n" +
+ "uniform float bgPrecisionMax;\n" +
+ "uniform float bgPrecisionNorMax;\n" +
+ "uniform mat4 normalMatrix;\n" +
+ "uniform mat4 modelViewProjectionMatrix;\n" +
+ "varying vec3 fragNormal;\n" +
+
+ "void main(void) {\n" +
+ " vec3 pos = bgCenter + bgSize * position / bgPrecisionMax;\n" +
+ " fragNormal = (normalMatrix * vec4(normal / bgPrecisionNorMax, 0.0)).xyz;\n" +
+ //" fragNormal = normal;\n" +
+ " gl_Position = modelViewProjectionMatrix * vec4(pos, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[NormalShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.NormalShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "varying vec3 fragNormal;\n" +
+
+ "void main(void) {\n" +
+ " gl_FragColor = vec4(normalize(fragNormal) / 2.0 + 0.5, 1.0);\n" +
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[NormalShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final ShadowShader program
+ */
+x3dom.shader.FrontgroundTextureShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.FrontgroundTextureShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "attribute vec3 position;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " vec2 texCoord = (position.xy + 1.0) * 0.5;\n" +
+ " fragTexCoord = texCoord;\n" +
+ " gl_Position = vec4(position.xy, 0.0, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[FrontgroundTextureShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.FrontgroundTextureShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "uniform sampler2D tex;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " vec4 col = texture2D(tex, fragTexCoord);\n" +
+ " gl_FragColor = vec4(col.rgb, 1.0);\n" +
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[FrontgroundTextureShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final ShadowShader program
+ */
+x3dom.shader.BackgroundTextureShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.BackgroundTextureShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "attribute vec3 position;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " vec2 texCoord = (position.xy + 1.0) * 0.5;\n" +
+ " fragTexCoord = texCoord;\n" +
+ " gl_Position = vec4(position.xy, 0.0, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BackgroundTextureShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.BackgroundTextureShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "uniform sampler2D tex;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " gl_FragColor = texture2D(tex, fragTexCoord);\n" +
+ "}";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BackgroundTextureShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final ShadowShader program
+ */
+x3dom.shader.BackgroundSkyTextureShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.BackgroundSkyTextureShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "attribute vec3 position;\n" +
+ "attribute vec2 texcoord;\n" +
+ "uniform mat4 modelViewProjectionMatrix;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " fragTexCoord = texcoord;\n" +
+ " gl_Position = modelViewProjectionMatrix * vec4(position, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BackgroundSkyTextureShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.BackgroundSkyTextureShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "uniform sampler2D tex;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " gl_FragColor = texture2D(tex, fragTexCoord);\n" +
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BackgroundSkyTextureShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final ShadowShader program
+ */
+x3dom.shader.BackgroundCubeTextureShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.BackgroundCubeTextureShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "attribute vec3 position;\n" +
+ "uniform mat4 modelViewProjectionMatrix;\n" +
+ "varying vec3 fragNormal;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " fragNormal = normalize(position);\n" +
+ " gl_Position = modelViewProjectionMatrix * vec4(position, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BackgroundCubeTextureShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.BackgroundCubeTextureShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "uniform samplerCube tex;\n" +
+ "varying vec3 fragNormal;\n" +
+ "\n" +
+ "float magn(float val) {\n" +
+ " return ((val >= 0.0) ? val : -1.0 * val);\n" +
+ "}" +
+ "\n" +
+ "void main(void) {\n" +
+ " vec3 normal = -reflect(normalize(fragNormal), vec3(0.0,0.0,1.0));\n" +
+ " if (magn(normal.y) >= magn(normal.x) && magn(normal.y) >= magn(normal.z))\n" +
+ " normal.xz = -normal.xz;\n" +
+ " gl_FragColor = textureCube(tex, normal);\n" +
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BackgroundCubeTextureShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final ShadowShader program
+ */
+x3dom.shader.ShadowShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.ShadowShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "";
+ if (!x3dom.caps.MOBILE) {
+
+ shader += "attribute vec3 position;\n" +
+ "uniform mat4 modelViewProjectionMatrix;\n" +
+ "varying vec4 projCoords;\n" +
+ //image geometry
+ "uniform float imageGeometry;\n" +
+ "uniform vec3 IG_bboxMin;\n" +
+ "uniform vec3 IG_bboxMax;\n" +
+ "uniform float IG_coordTextureWidth;\n" +
+ "uniform float IG_coordTextureHeight;\n" +
+ "uniform float IG_indexTextureWidth;\n" +
+ "uniform float IG_indexTextureHeight;\n" +
+ "uniform sampler2D IG_indexTexture;\n" +
+ "uniform sampler2D IG_coordinateTexture;\n" +
+ "uniform vec2 IG_implicitMeshSize;\n" +
+ //pop geometry
+ "uniform vec3 bgCenter;\n" +
+ "uniform vec3 bgSize;\n" +
+ "uniform float bgPrecisionMax;\n" +
+ "uniform float popGeometry;\n" +
+ "uniform float PG_precisionLevel;\n" +
+ "uniform float PG_powPrecision;\n" +
+ "uniform vec3 PG_maxBBSize;\n" +
+ "uniform vec3 PG_bbMin;\n" +
+ "uniform vec3 PG_bbMaxModF;\n" +
+ "uniform vec3 PG_bboxShiftVec;\n" +
+
+ //MAIN
+ "void main(void) {\n" +
+ " vec3 pos;\n" +
+ " if (imageGeometry != 0.0) {\n" +
+ //IG
+ " vec2 IG_texCoord;\n" +
+ " if(imageGeometry == 1.0) {\n" +
+ " vec2 halfPixel = vec2(0.5/IG_indexTextureWidth,0.5/IG_indexTextureHeight);\n" +
+ " IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_indexTextureWidth), position.y*(IG_implicitMeshSize.y/IG_indexTextureHeight)) + halfPixel;\n" +
+ " vec2 IG_index = texture2D( IG_indexTexture, IG_texCoord ).rg;\n" +
+ " IG_texCoord = IG_index * 0.996108948;\n" +
+ " } else {\n" +
+ " vec2 halfPixel = vec2(0.5/IG_coordTextureWidth, 0.5/IG_coordTextureHeight);\n" +
+ " IG_texCoord = vec2(position.x*(IG_implicitMeshSize.x/IG_coordTextureWidth), position.y*(IG_implicitMeshSize.y/IG_coordTextureHeight)) + halfPixel;\n" +
+ " }\n" +
+ " pos = texture2D( IG_coordinateTexture, IG_texCoord ).rgb;\n" +
+ " pos = pos * (IG_bboxMax - IG_bboxMin) + IG_bboxMin;\n" +
+ " } else if (popGeometry != 0.0){\n" +
+ //PG
+ " pos = position;\n" +
+ " vec3 offsetVec = step(pos / bgPrecisionMax, PG_bbMaxModF) * PG_bboxShiftVec;\n" +
+ " if (PG_precisionLevel <= 2.0) {\n" +
+ " pos = floor(pos / PG_powPrecision) * PG_powPrecision;\n" +
+ " pos /= (65536.0 - PG_powPrecision);\n" +
+ " }\n" +
+ " else {\n" +
+ " pos /= bgPrecisionMax;\n" +
+ " }\n" +
+ " pos = (pos + offsetVec + PG_bbMin) * PG_maxBBSize;\n" +
+ " } else {\n" +
+ //BG
+ " pos = bgCenter + bgSize * position / bgPrecisionMax;\n" +
+ " }\n" +
+ " projCoords = modelViewProjectionMatrix * vec4(pos, 1.0);\n" +
+ " gl_Position = projCoords;\n" +
+ "}\n";
+ } else {
+ shader = "attribute vec3 position;\n" +
+ "uniform vec3 bgCenter;\n" +
+ "uniform vec3 bgSize;\n" +
+ "uniform float bgPrecisionMax;\n" +
+ "uniform mat4 modelViewProjectionMatrix;\n" +
+ "varying vec4 projCoords;\n" +
+
+ "void main(void) {\n" +
+ " vec3 pos = bgCenter + bgSize * position / bgPrecisionMax;\n" +
+ " projCoords = modelViewProjectionMatrix * vec4(pos, 1.0);\n" +
+ " gl_Position = projCoords;\n" +
+ "}\n";
+ }
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[ShadowShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.ShadowShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "varying vec4 projCoords;\n" +
+ "uniform float offset;\n" +
+ "uniform bool cameraView;\n";
+ if(!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE)
+ shader += x3dom.shader.rgbaPacking();
+
+ shader += "void main(void) {\n" +
+ " vec3 proj = (projCoords.xyz / projCoords.w);\n";
+
+ if(!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE) {
+ shader += "gl_FragColor = packDepth(proj.z);\n";
+ } else {
+ //use variance shadow maps, when not rendering from camera view
+ //shader += "if (!cameraView) proj.z = exp((1.0-offset)*80.0*proj.z);\n";
+ shader += " if (!cameraView){\n" +
+ " proj.z = (proj.z + 1.0)*0.5;\n" +
+ " proj.y = proj.z * proj.z;\n" +
+ " }\n";
+ shader += " gl_FragColor = vec4(proj, 1.0);\n";
+ }
+ shader += "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[ShadowShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final Shader program
+ */
+x3dom.shader.ShadowRenderingShader = function(gl,shadowedLights)
+{
+ this.program = gl.createProgram();
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl,shadowedLights);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.ShadowRenderingShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "";
+ shader += "attribute vec2 position;\n";
+
+ shader += "varying vec2 vPosition;\n";
+
+ shader += "void main(void) {\n";
+ shader += " vPosition = position;\n";
+ shader += " gl_Position = vec4(position, -1.0, 1.0);\n";
+ shader += "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[ShadowRendering] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.ShadowRenderingShader.prototype.generateFragmentShader = function(gl,shadowedLights)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "uniform mat4 inverseViewProj;\n";
+ shader += "uniform mat4 inverseProj;\n";
+ shader += "varying vec2 vPosition;\n";
+ shader += "uniform sampler2D sceneMap;\n";
+ for (var i=0; i<5; i++)
+ shader += "uniform float cascade"+i+"_Depth;\n";
+
+
+ for(var l=0; l<shadowedLights.length; l++) {
+ shader += "uniform float light"+l+"_On;\n" +
+ "uniform float light"+l+"_Type;\n" +
+ "uniform vec3 light"+l+"_Location;\n" +
+ "uniform vec3 light"+l+"_Direction;\n" +
+ "uniform vec3 light"+l+"_Attenuation;\n" +
+ "uniform float light"+l+"_Radius;\n" +
+ "uniform float light"+l+"_BeamWidth;\n" +
+ "uniform float light"+l+"_CutOffAngle;\n" +
+ "uniform float light"+l+"_ShadowIntensity;\n" +
+ "uniform float light"+l+"_ShadowOffset;\n" +
+ "uniform mat4 light"+l+"_ViewMatrix;\n";
+ for (var j=0; j<6; j++){
+ shader += "uniform mat4 light"+l+"_"+j+"_Matrix;\n";
+ shader += "uniform sampler2D light"+l+"_"+j+"_ShadowMap;\n";
+ }
+ for (var j=0; j<5; j++)
+ shader += "uniform float light"+l+"_"+j+"_Split;\n";
+
+
+ }
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE)
+ shader += x3dom.shader.rgbaPacking();
+
+ shader += x3dom.shader.shadowRendering();
+
+ shader += x3dom.shader.gammaCorrectionDecl({}); //TODO shader properties?
+
+ shader += "void main(void) {\n" +
+ " float shadowValue = 1.0;\n" +
+ " vec2 texCoordsSceneMap = (vPosition + 1.0)*0.5;\n" +
+ " vec4 projCoords = texture2D(sceneMap, texCoordsSceneMap);\n" +
+ " if (projCoords != vec4(1.0,1.0,1.0,0.0)){\n";
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE){
+ shader += " projCoords.z = unpackDepth(projCoords);\n" +
+ " projCoords.w = 1.0;\n";
+ }
+
+ //reconstruct world and view coordinates from scene map
+ shader += " projCoords = projCoords / projCoords.w;\n" +
+ " projCoords.xy = vPosition;\n" +
+ " vec4 eyeCoords = inverseProj*projCoords;\n" +
+ " vec4 worldCoords = inverseViewProj*projCoords;\n" +
+ " float lightInfluence = 0.0;\n";
+
+ for(var l=0; l<shadowedLights.length; l++) {
+ shader +=
+ " lightInfluence = getLightInfluence(light"+l+"_Type, light"+l+"_ShadowIntensity, light"+l+"_On, light"+l+"_Location, light"+l+"_Direction, " +
+ "light"+l+"_CutOffAngle, light"+l+"_BeamWidth, light"+l+"_Attenuation, light"+l+"_Radius, eyeCoords.xyz/eyeCoords.w);\n" +
+ " if (lightInfluence != 0.0){\n" +
+ " vec4 shadowMapValues;\n" +
+ " float viewSampleDepth;\n";
+
+
+ if (!x3dom.isa(shadowedLights[l], x3dom.nodeTypes.PointLight)){
+ shader += " getShadowValuesCascaded(shadowMapValues, viewSampleDepth, worldCoords, -eyeCoords.z/eyeCoords.w,"+
+ "light"+l+"_0_Matrix,light"+l+"_1_Matrix,light"+l+"_2_Matrix,light"+l+"_3_Matrix,light"+l+"_4_Matrix,light"+l+"_5_Matrix,"+
+ "light"+l+"_0_ShadowMap,light"+l+"_1_ShadowMap,light"+l+"_2_ShadowMap,light"+l+"_3_ShadowMap,"+
+ "light"+l+"_4_ShadowMap,light"+l+"_5_ShadowMap, light"+l+"_0_Split, light"+l+"_1_Split, light"+l+"_2_Split, light"+l+"_3_Split, \n"+
+ "light"+l+"_4_Split);\n";
+ } else {
+ shader += " getShadowValuesPointLight(shadowMapValues, viewSampleDepth, light"+l+"_Location, worldCoords, light"+l+"_ViewMatrix, "+
+ "light"+l+"_0_Matrix,light"+l+"_1_Matrix,light"+l+"_2_Matrix,light"+l+"_3_Matrix,light"+l+"_4_Matrix,light"+l+"_5_Matrix,"+
+ "light"+l+"_0_ShadowMap,light"+l+"_1_ShadowMap,light"+l+"_2_ShadowMap,light"+l+"_3_ShadowMap,"+
+ "light"+l+"_4_ShadowMap,light"+l+"_5_ShadowMap);\n";
+ }
+
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE)
+ shader += " shadowValue *= clamp(ESM(shadowMapValues.z, viewSampleDepth, light"+l+"_ShadowOffset), "+
+ " 1.0 - light"+l+"_ShadowIntensity*lightInfluence, 1.0);\n";
+ else
+ shader += " shadowValue *= clamp(VSM(shadowMapValues.zy, viewSampleDepth, light"+l+"_ShadowOffset), "+
+ " 1.0 - light"+l+"_ShadowIntensity*lightInfluence, 1.0);\n";
+ shader += " }\n";
+
+ }
+
+ shader += "}\n" +
+ // In principle we should fix the place where this is multplied in instead
+ // of overcompensating for the subsequent error from here. This way of doing
+ // gamma correction explots the rule that (a*b)^x = a^x * b^x (x being the
+ // gamma coefficient), i.e. the umbra is corrected for now, the penumbra
+ // is incorrect and full light is zero here so unaffected as well.
+ " gl_FragColor = " + x3dom.shader.encodeGamma({}, "vec4(shadowValue, shadowValue, shadowValue, 1.0)") + ";\n" +
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[ShadowRendering] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final shader program
+ */
+x3dom.shader.TextureRefinementShader = function (gl) {
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.TextureRefinementShader.prototype.generateVertexShader = function (gl) {
+ var shader = "attribute vec2 position;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " fragTexCoord = (position.xy + 1.0) / 2.0;\n" +
+ " gl_Position = vec4(position, -1.0, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
+ x3dom.debug.logError("[TextureRefinementShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.TextureRefinementShader.prototype.generateFragmentShader = function (gl) {
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n" +
+ " precision highp float;\n" +
+ "#else\n" +
+ " precision mediump float;\n" +
+ "#endif\n\n";
+
+ shader += "uniform sampler2D stamp;\n" +
+ "uniform sampler2D lastTex;\n" +
+ "uniform sampler2D curTex;\n" +
+ "uniform int mode;\n" +
+ "uniform vec2 repeat;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void init(void);\n" +
+ "void refine(void);\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " if (mode == 0) { init(); }\n" +
+ " else { refine(); }\n" +
+ "}\n" +
+ "\n" +
+ "void init(void) {\n" +
+ " gl_FragColor = texture2D(curTex, fragTexCoord);\n" +
+ "}\n" +
+ "\n" +
+ "void refine(void) {\n" +
+ " vec3 red = texture2D(stamp, repeat * fragTexCoord).rgb;\n" +
+ " vec3 v1 = texture2D(lastTex, fragTexCoord).rgb;\n" +
+ " vec3 v2 = texture2D(curTex, fragTexCoord).rgb;\n" +
+ " if (red.r <= 0.5) {\n" +
+ " gl_FragColor = vec4(v1, 1.0);\n" +
+ " }\n" +
+ " else {\n" +
+ " gl_FragColor = vec4(v2, 1.0);\n" +
+ " }\n" +
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
+ x3dom.debug.logError("[TextureRefinementShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/**
+ * Generate the final BlurShader program
+ * (gaussian blur for 3x3, 5x5 and 7x7 kernels)
+ */
+x3dom.shader.BlurShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.BlurShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "";
+ shader += "attribute vec2 position;\n";
+
+ shader += "varying vec2 vPosition;\n";
+
+ shader += "void main(void) {\n";
+ shader += " vPosition = position;\n";
+ shader += " gl_Position = vec4(position, -1.0, 1.0);\n";
+ shader += "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BlurShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.BlurShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "varying vec2 vPosition;\n" +
+ "uniform sampler2D texture;\n" +
+ "uniform bool horizontal;\n" +
+ "uniform float pixelSizeHor;\n" +
+ "uniform float pixelSizeVert;\n" +
+ "uniform int filterSize;\n";
+
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE){
+ shader += x3dom.shader.rgbaPacking() +
+
+ "void main(void) {\n" +
+ " vec2 texCoords = (vPosition + 1.0)*0.5;\n" +
+ " vec2 offset;\n" +
+ " if (horizontal) offset = vec2(pixelSizeHor, 0.0);\n" +
+ " else offset = vec2(0.0, pixelSizeVert);\n" +
+ " float depth = unpackDepth(texture2D(texture, texCoords));\n" +
+ " if (filterSize == 3){\n" +
+ " depth = depth * 0.3844;\n" +
+ " depth += 0.3078*unpackDepth(texture2D(texture, texCoords-offset));\n" +
+ " depth += 0.3078*unpackDepth(texture2D(texture, texCoords+offset));\n" +
+ " } else if (filterSize == 5){\n" +
+ " depth = depth * 0.2921;\n" +
+ " depth += 0.2339*unpackDepth(texture2D(texture, texCoords-offset));\n" +
+ " depth += 0.2339*unpackDepth(texture2D(texture, texCoords+offset));\n" +
+ " depth += 0.1201*unpackDepth(texture2D(texture, texCoords-2.0*offset));\n" +
+ " depth += 0.1201*unpackDepth(texture2D(texture, texCoords+2.0*offset));\n" +
+ " } else if (filterSize == 7){\n" +
+ " depth = depth * 0.2161;\n" +
+ " depth += 0.1907*unpackDepth(texture2D(texture, texCoords-offset));\n" +
+ " depth += 0.1907*unpackDepth(texture2D(texture, texCoords+offset));\n" +
+ " depth += 0.1311*unpackDepth(texture2D(texture, texCoords-2.0*offset));\n" +
+ " depth += 0.1311*unpackDepth(texture2D(texture, texCoords+2.0*offset));\n" +
+ " depth += 0.0702*unpackDepth(texture2D(texture, texCoords-3.0*offset));\n" +
+ " depth += 0.0702*unpackDepth(texture2D(texture, texCoords+3.0*offset));\n" +
+ " }\n" +
+ " gl_FragColor = packDepth(depth);\n" +
+ "}\n";
+ } else{
+ shader += "void main(void) {\n" +
+ " vec2 texCoords = (vPosition + 1.0)*0.5;\n" +
+ " vec2 offset;\n" +
+ " if (horizontal) offset = vec2(pixelSizeHor, 0.0);\n" +
+ " else offset = vec2(0.0, pixelSizeVert);\n" +
+ " vec4 color = texture2D(texture, texCoords);\n" +
+ " if (filterSize == 3){\n" +
+ " color = color * 0.3844;\n" +
+ " color += 0.3078*texture2D(texture, texCoords-offset);\n" +
+ " color += 0.3078*texture2D(texture, texCoords+offset);\n" +
+ " } else if (filterSize == 5){\n" +
+ " color = color * 0.2921;\n" +
+ " color += 0.2339*texture2D(texture, texCoords-offset);\n" +
+ " color += 0.2339*texture2D(texture, texCoords+offset);\n" +
+ " color += 0.1201*texture2D(texture, texCoords-2.0*offset);\n" +
+ " color += 0.1201*texture2D(texture, texCoords+2.0*offset);\n" +
+ " } else if (filterSize == 7){\n" +
+ " color = color * 0.2161;\n" +
+ " color += 0.1907*texture2D(texture, texCoords-offset);\n" +
+ " color += 0.1907*texture2D(texture, texCoords+offset);\n" +
+ " color += 0.1311*texture2D(texture, texCoords-2.0*offset);\n" +
+ " color += 0.1311*texture2D(texture, texCoords+2.0*offset);\n" +
+ " color += 0.0702*texture2D(texture, texCoords-3.0*offset);\n" +
+ " color += 0.0702*texture2D(texture, texCoords+3.0*offset);\n" +
+ " }\n" +
+ " gl_FragColor = color;\n" +
+ "}\n";
+ }
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[BlurShader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+/**
+ * Generate the final ShadowShader program
+ */
+x3dom.shader.SSAOShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.SSAOShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "attribute vec3 position;\n" +
+ "varying vec2 depthTexCoord;\n" +
+ "varying vec2 randomTexCoord;\n"+
+ "uniform vec2 randomTextureTilingFactor;\n"+
+ "\n" +
+ "void main(void) {\n" +
+ " vec2 texCoord = (position.xy + 1.0) * 0.5;\n" +
+ " depthTexCoord = texCoord;\n" +
+ " randomTexCoord = randomTextureTilingFactor*texCoord;\n"+
+ " gl_Position = vec4(position.xy, 0.0, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[SSAOShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Returns the code for a function "getDepth(vec2 depthTexCoord)" that returns the linear depth.
+ * It also introduces two uniform floats depthReconstructionConstantA and depthReconstructionConstantB,
+ * which are needed for the depth reconstruction.
+ */
+x3dom.shader.SSAOShader.depthReconsructionFunctionCode = function()
+{
+ var code = "uniform float depthReconstructionConstantA;\n"+
+ "uniform float depthReconstructionConstantB;\n";
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE)
+ code += x3dom.shader.rgbaPacking();
+
+ code+= "float getDepth(vec2 depthTexCoord) {\n"+
+ " vec4 col = texture2D(depthTexture, depthTexCoord);\n"+
+ " float d;\n";
+
+ if (!x3dom.caps.FP_TEXTURES || x3dom.caps.MOBILE){
+ code+=" d = unpackDepth(col);\n";
+ } else {
+ code+=" d = col.b;\n"
+ }
+ code+= " return depthReconstructionConstantB/(depthReconstructionConstantA+d);\n";
+ code+= "}\n";
+ return code;
+}
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.SSAOShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+ shader += "uniform sampler2D depthTexture;\n" +
+ "uniform sampler2D randomTexture;\n"+
+ "uniform float nearPlane;\n"+
+ "uniform float farPlane;\n"+
+ "uniform float radius;\n"+
+ "uniform float depthBufferEpsilon;\n"+
+ "uniform vec3 samples[16];\n"+
+ "varying vec2 depthTexCoord;\n" +
+ "varying vec2 randomTexCoord;\n";
+
+ shader += x3dom.shader.SSAOShader.depthReconsructionFunctionCode();
+
+ shader+= "void main(void) {\n" +
+ " float referenceDepth = getDepth(depthTexCoord);\n" +
+ " if(referenceDepth == 1.0)\n"+ //background
+ " {\n"+
+ " gl_FragColor = vec4(1.0,1.0,1.0, 1.0);\n"+
+ " return;\n"+
+ " }\n"+
+ " int numOcclusions = 0;\n"+
+ " for(int i = 0; i<16; ++i){\n"+
+ " float scale = 1.0/referenceDepth;\n"+
+ " vec3 samplepos = reflect(samples[i],texture2D(randomTexture,randomTexCoord).xyz*2.0-vec3(1.0,1.0,1.0));\n"+
+ " float sampleDepth = getDepth(depthTexCoord+samplepos.xy*scale*radius);\n"+
+ " //if(abs(sampleDepth-referenceDepth)<=radius*(1.0/nearPlane))\n"+ //leads to bright halos
+ " if( sampleDepth < referenceDepth-depthBufferEpsilon) {\n"+
+ " ++numOcclusions;\n"+
+ " }\n"+
+ " }\n"+
+ " float r = 1.0-float(numOcclusions)/16.0;\n"+
+ " r*=2.0;\n"+
+ " gl_FragColor = vec4(r,r,r, 1.0);\n" +
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[SSAOhader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+
+/**
+ * Generate the final ShadowShader program
+ */
+x3dom.shader.SSAOBlurShader = function(gl)
+{
+ this.program = gl.createProgram();
+
+ var vertexShader = this.generateVertexShader(gl);
+ var fragmentShader = this.generateFragmentShader(gl);
+
+ gl.attachShader(this.program, vertexShader);
+ gl.attachShader(this.program, fragmentShader);
+
+ // optional, but position should be at location 0 for performance reasons
+ gl.bindAttribLocation(this.program, 0, "position");
+
+ gl.linkProgram(this.program);
+ return this.program;
+};
+
+/**
+ * Generate the vertex shader
+ */
+x3dom.shader.SSAOBlurShader.prototype.generateVertexShader = function(gl)
+{
+ var shader = "attribute vec3 position;\n" +
+ "varying vec2 fragTexCoord;\n" +
+ "\n" +
+ "void main(void) {\n" +
+ " vec2 texCoord = (position.xy + 1.0) * 0.5;\n" +
+ " fragTexCoord = texCoord;\n" +
+ " gl_Position = vec4(position.xy, 0.0, 1.0);\n" +
+ "}\n";
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, shader);
+ gl.compileShader(vertexShader);
+
+ if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[SSAOShader] VertexShader " + gl.getShaderInfoLog(vertexShader));
+ }
+
+ return vertexShader;
+};
+
+/**
+ * Generate the fragment shader
+ */
+x3dom.shader.SSAOBlurShader.prototype.generateFragmentShader = function(gl)
+{
+ var shader = "#ifdef GL_FRAGMENT_PRECISION_HIGH\n";
+ shader += "precision highp float;\n";
+ shader += "#else\n";
+ shader += " precision mediump float;\n";
+ shader += "#endif\n\n";
+
+
+ shader += "uniform sampler2D SSAOTexture;\n" +
+ "uniform sampler2D depthTexture;\n" +
+ "uniform float nearPlane;\n"+
+ "uniform float farPlane;\n"+
+ "uniform float amount;\n"+
+ "uniform vec2 pixelSize;\n"+
+ "uniform float depthThreshold;\n"+
+ "varying vec2 fragTexCoord;\n";
+
+
+ shader += x3dom.shader.SSAOShader.depthReconsructionFunctionCode();
+
+ shader+="void main(void) {\n" +
+ " float sum = 0.0;\n"+
+ " float numSamples = 0.0;\n"+
+ " float referenceDepth = getDepth(fragTexCoord);\n"+
+ " for(int i = -2; i<2;i++){\n"+
+ " for(int j = -2; j<2;j++){\n"+
+ " vec2 sampleTexCoord = fragTexCoord+vec2(pixelSize.x*float(i),pixelSize.y*float(j));\n"+
+ " if(abs(referenceDepth - getDepth(sampleTexCoord))<depthThreshold){\n"+
+ " sum+= texture2D(SSAOTexture,sampleTexCoord).r;\n"+
+ " numSamples++;\n"+
+ " }}}\n"+
+ " float intensity = mix(1.0,sum/numSamples,amount);\n"+
+ " gl_FragColor = vec4(intensity,intensity,intensity,1.0);\n"+
+ "}\n";
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, shader);
+ gl.compileShader(fragmentShader);
+
+ if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)){
+ x3dom.debug.logError("[SSAOhader] FragmentShader " + gl.getShaderInfoLog(fragmentShader));
+ }
+
+ return fragmentShader;
+};
+
+
+x3dom.SSAO = {};
+x3dom.SSAO.isEnabled = function(scene){return scene.getEnvironment()._vf.SSAO};
+
+/**
+ * Reinitializes the shaders if they were not created yet or need to be updated.
+ */
+x3dom.SSAO.reinitializeShadersIfNecessary = function(gl){
+ if(x3dom.SSAO.shaderProgram === undefined){
+ x3dom.SSAO.shaderProgram = x3dom.Utils.wrapProgram(gl, new x3dom.shader.SSAOShader(gl), "ssao");
+ }
+ if(x3dom.SSAO.blurShaderProgram === undefined){
+ x3dom.SSAO.blurShaderProgram = x3dom.Utils.wrapProgram(gl, new x3dom.shader.SSAOBlurShader(gl), "ssao-blur");
+ }
+};
+
+/**
+ * Reinitializes the random Texture if it was not created yet or if it's size changed.
+ */
+x3dom.SSAO.reinitializeRandomTextureIfNecessary = function(gl,scene){
+ var sizeHasChanged = scene.getEnvironment()._vf.SSAOrandomTextureSize != x3dom.SSAO.currentRandomTextureSize;
+
+ if(x3dom.SSAO.randomTexture === undefined){
+ //create random texture
+ x3dom.SSAO.randomTexture = gl.createTexture();
+ }
+
+ if(x3dom.SSAO.randomTexture === undefined || sizeHasChanged){
+ gl.bindTexture(gl.TEXTURE_2D,x3dom.SSAO.randomTexture);
+ var rTexSize = x3dom.SSAO.currentRandomTextureSize = scene.getEnvironment()._vf.SSAOrandomTextureSize;
+ var randomImageBuffer = new ArrayBuffer(rTexSize*rTexSize*4); //rTexSize^2 pixels with 4 bytes each
+ var randomImageView = new Uint8Array(randomImageBuffer);
+ //fill the image with random unit Vectors in the z-y-plane:
+ for(var i = 0; i<rTexSize*rTexSize;++i){
+ var x = Math.random()*2.0-1.0;
+ var y = Math.random()*2.0-1.0;
+ var z = 0;
+ var length = Math.sqrt(x*x+y*y+z*z);
+ x /=length;
+ y /=length;
+ randomImageView[4*i] = (x+1.0)*0.5*255.0;
+ randomImageView[4*i+1] = (y+1.0)*0.5*255.0;
+ randomImageView[4*i+2] = (z+1.0)*0.5*255.0;
+ randomImageView[4*i+3] = 255;
+ }
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,rTexSize,rTexSize,0, gl.RGBA,gl.UNSIGNED_BYTE, randomImageView);
+ gl.bindTexture(gl.TEXTURE_2D,null);
+ }
+};
+
+/**
+ * Reinitializes the FBO render target for the SSAO if it wasn't created yet or if the canvas size changed.
+ */
+x3dom.SSAO.reinitializeFBOIfNecessary = function(gl,canvas){
+
+ var dimensionsHaveChanged =
+ x3dom.SSAO.currentFBOWidth != canvas.width ||
+ x3dom.SSAO.currentFBOHeight != canvas.height;
+
+ if(x3dom.SSAO.fbo === undefined || dimensionsHaveChanged)
+ {
+ x3dom.SSAO.currentFBOWidth = canvas.width;
+ x3dom.SSAO.currentFBOHeight = canvas.height;
+ var oldfbo = gl.getParameter(gl.FRAMEBUFFER_BINDING);
+ if(x3dom.SSAO.fbo === undefined){
+ //create framebuffer
+ x3dom.SSAO.fbo = gl.createFramebuffer();
+ }
+ gl.bindFramebuffer(gl.FRAMEBUFFER, x3dom.SSAO.fbo);
+ if(x3dom.SSAO.fbotex === undefined){
+ //create render texture
+ x3dom.SSAO.fbotex = gl.createTexture();
+ }
+ gl.bindTexture(gl.TEXTURE_2D,x3dom.SSAO.fbotex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,x3dom.SSAO.currentFBOWidth,
+ x3dom.SSAO.currentFBOHeight,0, gl.RGBA,gl.UNSIGNED_BYTE, null);
+ gl.bindTexture(gl.TEXTURE_2D,null);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER,
+ gl.COLOR_ATTACHMENT0,
+ gl.TEXTURE_2D,
+ x3dom.SSAO.fbotex,
+ 0);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, oldfbo);
+ }
+};
+
+/*
+ * Renders a sparsely sampled Screen-Space Ambient Occlusion Factor.
+ * @param stateManager x3dom webgl stateManager
+ * @param gl WebGL context
+ * @param scene Scene Node
+ * @param tex depth texture
+ * @param canvas Canvas the scene is rendered on (needed for dimensions)
+ * @param fbo FrameBufferObject handle that should be used as a target (null to use curent fbo)
+ */
+x3dom.SSAO.render = function(stateManager,gl,scene,tex,canvas,fbo) {
+ //save previous fbo
+ var oldfbo = gl.getParameter(gl.FRAMEBUFFER_BINDING);
+ if(fbo != null){
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ }
+
+ stateManager.frontFace(gl.CCW);
+ stateManager.disable(gl.CULL_FACE);
+ stateManager.disable(gl.DEPTH_TEST);
+
+ var sp = x3dom.SSAO.shaderProgram;
+
+ stateManager.useProgram(sp);
+
+ //set up uniforms
+ sp.depthTexture = 0;
+ sp.randomTexture = 1;
+ sp.radius = scene.getEnvironment()._vf.SSAOradius;
+ sp.randomTextureTilingFactor = [canvas.width/x3dom.SSAO.currentRandomTextureSize,canvas.height/x3dom.SSAO.currentRandomTextureSize];
+
+ var viewpoint = scene.getViewpoint();
+ var nearPlane = viewpoint.getNear();
+ var farPlane = viewpoint.getFar();
+ sp.nearPlane = nearPlane;
+ sp.farPlane = farPlane;
+ sp.depthReconstructionConstantA = (farPlane+nearPlane)/(nearPlane-farPlane);
+ sp.depthReconstructionConstantB = (2.0*farPlane*nearPlane)/(nearPlane-farPlane);
+ sp.depthBufferEpsilon = 0.0001*(farPlane-nearPlane);
+ //16 samples with a well distributed pseudo random opposing-pairs sampling pattern:
+ sp.samples = [0.03800223814729654,0.10441029119843426,-0.04479934806797181,
+ -0.03800223814729654,-0.10441029119843426,0.04479934806797181,
+ -0.17023209847088397,0.1428416910414532,0.6154407640895228,
+ 0.17023209847088397,-0.1428416910414532,-0.6154407640895228,
+ -0.288675134594813,-0.16666666666666646,-0.3774214123135722,
+ 0.288675134594813,0.16666666666666646,0.3774214123135722,
+ 0.07717696785196887,-0.43769233467209245,-0.5201284112706428,
+ -0.07717696785196887,0.43769233467209245,0.5201284112706428,
+ 0.5471154183401156,-0.09647120981496134,-0.15886420745887797,
+ -0.5471154183401156,0.09647120981496134,0.15886420745887797,
+ 0.3333333333333342,0.5773502691896253,-0.8012446019636266,
+ -0.3333333333333342,-0.5773502691896253,0.8012446019636266,
+ -0.49994591864508653,0.5958123446480936,-0.15385106176844343,
+ 0.49994591864508653,-0.5958123446480936,0.15385106176844343,
+ -0.8352823295874743,-0.3040179051783715,0.7825440557226517,
+ 0.8352823295874743,0.3040179051783715,-0.7825440557226517];
+ if (!sp.tex) {
+ sp.tex = 0;
+ }
+
+ //depth texture
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ //random texture:
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, x3dom.SSAO.randomTexture);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, scene._fgnd._webgl.buffers[0]);
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._fgnd._webgl.buffers[1]);
+ gl.vertexAttribPointer(sp.position, 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ gl.drawElements(scene._fgnd._webgl.primType, scene._fgnd._webgl.indexes.length, gl.UNSIGNED_SHORT, 0);
+
+ gl.disableVertexAttribArray(sp.position);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ //restore prevoius fbo
+ if(fbo != null){
+ gl.bindFramebuffer(gl.FRAMEBUFFER, oldfbo);
+ }
+};
+
+/**
+ * Applies a depth-aware averaging filter.
+ * @param stateManager x3dom webgl stateManager
+ * @param gl WebGL context
+ * @param scene Scene Node
+ * @param ssaoTexture texture that contains the SSAO factor
+ * @param depthTexture depth texture
+ * @param canvas Canvas the scene is rendered on (needed for dimensions)
+ * @param fbo FrameBufferObject handle that should be used as a target (null to use curent fbo)
+ */
+x3dom.SSAO.blur = function(stateManager,gl,scene,ssaoTexture,depthTexture,canvas,fbo) {
+
+ //save previous fbo
+ var oldfbo = gl.getParameter(gl.FRAMEBUFFER_BINDING);
+ if(fbo != null){
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ }
+
+ stateManager.frontFace(gl.CCW);
+ stateManager.disable(gl.CULL_FACE);
+ stateManager.disable(gl.DEPTH_TEST);
+
+ var sp = x3dom.SSAO.blurShaderProgram;
+
+ stateManager.useProgram(sp);
+
+ sp.SSAOTexture = 0;
+ sp.depthTexture = 1;
+
+ sp.depthThreshold = scene.getEnvironment()._vf.SSAOblurDepthTreshold;
+
+ var viewpoint = scene.getViewpoint();
+ var nearPlane = viewpoint.getNear();
+ var farPlane = viewpoint.getFar();
+ sp.nearPlane = nearPlane;
+ sp.farPlane = farPlane;
+ sp.depthReconstructionConstantA = (farPlane+nearPlane)/(nearPlane-farPlane);
+ sp.depthReconstructionConstantB = (2.0*farPlane*nearPlane)/(nearPlane-farPlane);
+ sp.pixelSize = [1.0/canvas.width,1.0/canvas.height];
+ sp.amount = scene.getEnvironment()._vf.SSAOamount;
+
+ //ssao texture
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, ssaoTexture);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ //depth texture
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, depthTexture);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, scene._fgnd._webgl.buffers[0]);
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._fgnd._webgl.buffers[1]);
+ gl.vertexAttribPointer(sp.position, 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ gl.drawElements(scene._fgnd._webgl.primType, scene._fgnd._webgl.indexes.length, gl.UNSIGNED_SHORT, 0);
+
+ gl.disableVertexAttribArray(sp.position);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ //restore previous fbo
+ if(fbo != null){
+ gl.bindFramebuffer(gl.FRAMEBUFFER, oldfbo);
+ }
+};
+
+/**
+ * Renders Screen-Space Ambeint Occlusion multiplicatively on top of the scene.
+ * @param stateManager state manager for the WebGL context
+ * @param gl WebGL context
+ * @param scene current scene
+ * @param canvas canvas that the scene is rendered to
+ */
+x3dom.SSAO.renderSSAO = function(stateManager, gl, scene, canvas) {
+
+ //set up resources if they are non-existent or if they are outdated:
+ this.reinitializeShadersIfNecessary(gl);
+ this.reinitializeRandomTextureIfNecessary(gl,scene);
+ this.reinitializeFBOIfNecessary(gl,canvas);
+
+ stateManager.viewport(0,0,canvas.width, canvas.height);
+
+ //render SSAO into fbo
+ this.render(stateManager,gl, scene, scene._webgl.fboScene.tex,canvas,x3dom.SSAO.fbo);
+ //render blurred SSAO multiplicatively
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA);
+ this.blur(stateManager,gl, scene, x3dom.SSAO.fbotex,scene._webgl.fboScene.tex,canvas,null);
+ gl.disable(gl.BLEND);
+};
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+x3dom.gfx_webgl = (function () {
+ "use strict";
+
+ /*****************************************************************************
+ * Context constructor
+ *****************************************************************************/
+ function Context(ctx3d, canvas, name, x3dElem) {
+ this.ctx3d = ctx3d;
+ this.canvas = canvas;
+ this.name = name;
+ this.x3dElem = x3dElem;
+ this.IG_PositionBuffer = null;
+ this.cache = new x3dom.Cache();
+ this.stateManager = new x3dom.StateManager(ctx3d);
+ }
+
+
+ /*****************************************************************************
+ * Return context name
+ *****************************************************************************/
+ Context.prototype.getName = function () {
+ return this.name;
+ };
+
+
+ /*****************************************************************************
+ * Setup the 3D context and init some things
+ *****************************************************************************/
+ function setupContext(canvas, forbidMobileShaders, forceMobileShaders, tryWebGL2, x3dElem) {
+ var validContextNames = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d'];
+
+ if (tryWebGL2) {
+ validContextNames = ['experimental-webgl2'].concat(validContextNames);
+ }
+
+ var ctx = null;
+
+ // TODO; FIXME; this is an ugly hack, don't look for elements like this
+ // (e.g., Bindable nodes may only exist in backend etc.)
+ var envNodes = x3dElem.getElementsByTagName("Environment");
+ var ssaoEnabled = (envNodes && envNodes[0] && envNodes[0].hasAttribute("SSAO") &&
+ envNodes[0].getAttribute("SSAO").toLowerCase() === 'true') ? true : false;
+
+ // Context creation params
+ var ctxAttribs = {
+ alpha: true,
+ depth: true,
+ stencil: true,
+ antialias: !ssaoEnabled,
+ premultipliedAlpha: false,
+ preserveDrawingBuffer: true,
+ failIfMajorPerformanceCaveat : true
+ };
+
+ for (var i = 0; i < validContextNames.length; i++) {
+ try {
+ ctx = canvas.getContext(validContextNames[i], ctxAttribs);
+
+ //If context creation fails, retry the creation with failIfMajorPerformanceCaveat = false
+ if ( !ctx ) {
+ x3dom.caps.RENDERMODE = "SOFTWARE";
+ ctxAttribs.failIfMajorPerformanceCaveat = false;
+ ctx = canvas.getContext(validContextNames[i], ctxAttribs);
+ }
+
+ if (ctx) {
+ var newCtx = new Context(ctx, canvas, 'webgl', x3dElem);
+
+ try {
+ //Save CAPS
+ x3dom.caps.VENDOR = ctx.getParameter(ctx.VENDOR);
+ x3dom.caps.VERSION = ctx.getParameter(ctx.VERSION);
+ x3dom.caps.RENDERER = ctx.getParameter(ctx.RENDERER);
+ x3dom.caps.SHADING_LANGUAGE_VERSION = ctx.getParameter(ctx.SHADING_LANGUAGE_VERSION);
+ x3dom.caps.RED_BITS = ctx.getParameter(ctx.RED_BITS);
+ x3dom.caps.GREEN_BITS = ctx.getParameter(ctx.GREEN_BITS);
+ x3dom.caps.BLUE_BITS = ctx.getParameter(ctx.BLUE_BITS);
+ x3dom.caps.ALPHA_BITS = ctx.getParameter(ctx.ALPHA_BITS);
+ x3dom.caps.DEPTH_BITS = ctx.getParameter(ctx.DEPTH_BITS);
+ x3dom.caps.MAX_VERTEX_ATTRIBS = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS);
+ x3dom.caps.MAX_VERTEX_TEXTURE_IMAGE_UNITS = ctx.getParameter(ctx.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+ x3dom.caps.MAX_VARYING_VECTORS = ctx.getParameter(ctx.MAX_VARYING_VECTORS);
+ x3dom.caps.MAX_VERTEX_UNIFORM_VECTORS = ctx.getParameter(ctx.MAX_VERTEX_UNIFORM_VECTORS);
+ x3dom.caps.MAX_COMBINED_TEXTURE_IMAGE_UNITS = ctx.getParameter(ctx.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ x3dom.caps.MAX_TEXTURE_SIZE = ctx.getParameter(ctx.MAX_TEXTURE_SIZE);
+ x3dom.caps.MAX_TEXTURE_IMAGE_UNITS = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS);
+ x3dom.caps.MAX_CUBE_MAP_TEXTURE_SIZE = ctx.getParameter(ctx.MAX_CUBE_MAP_TEXTURE_SIZE);
+ x3dom.caps.COMPRESSED_TEXTURE_FORMATS = ctx.getParameter(ctx.COMPRESSED_TEXTURE_FORMATS);
+ x3dom.caps.MAX_RENDERBUFFER_SIZE = ctx.getParameter(ctx.MAX_RENDERBUFFER_SIZE);
+ x3dom.caps.MAX_VIEWPORT_DIMS = ctx.getParameter(ctx.MAX_VIEWPORT_DIMS);
+ x3dom.caps.ALIASED_LINE_WIDTH_RANGE = ctx.getParameter(ctx.ALIASED_LINE_WIDTH_RANGE);
+ x3dom.caps.ALIASED_POINT_SIZE_RANGE = ctx.getParameter(ctx.ALIASED_POINT_SIZE_RANGE);
+ x3dom.caps.SAMPLES = ctx.getParameter(ctx.SAMPLES);
+ x3dom.caps.INDEX_UINT = ctx.getExtension("OES_element_index_uint");
+ x3dom.caps.FP_TEXTURES = ctx.getExtension("OES_texture_float");
+ x3dom.caps.FPL_TEXTURES = ctx.getExtension("OES_texture_float_linear");
+ x3dom.caps.STD_DERIVATIVES = ctx.getExtension("OES_standard_derivatives");
+ x3dom.caps.DRAW_BUFFERS = ctx.getExtension("WEBGL_draw_buffers");
+ x3dom.caps.DEBUGRENDERINFO = ctx.getExtension("WEBGL_debug_renderer_info");
+ x3dom.caps.EXTENSIONS = ctx.getSupportedExtensions();
+
+ if ( x3dom.caps.DEBUGRENDERINFO ) {
+ x3dom.caps.UNMASKED_RENDERER_WEBGL = ctx.getParameter( x3dom.caps.DEBUGRENDERINFO.UNMASKED_RENDERER_WEBGL );
+ x3dom.caps.UNMASKED_VENDOR_WEBGL = ctx.getParameter( x3dom.caps.DEBUGRENDERINFO.UNMASKED_VENDOR_WEBGL );
+ } else {
+ x3dom.caps.UNMASKED_RENDERER_WEBGL = "";
+ x3dom.caps.UNMASKED_VENDOR_WEBGL = "";
+ }
+
+ var extString = x3dom.caps.EXTENSIONS.toString().replace(/,/g, ", ");
+ x3dom.debug.logInfo(validContextNames[i] + " context found\nVendor: " + x3dom.caps.VENDOR +
+ " " + x3dom.caps.UNMASKED_VENDOR_WEBGL + ", Renderer: " + x3dom.caps.RENDERER +
+ " " + x3dom.caps.UNMASKED_RENDERER_WEBGL + ", " + "Version: " + x3dom.caps.VERSION + ", " +
+ "ShadingLangV.: " + x3dom.caps.SHADING_LANGUAGE_VERSION
+ + ", MSAA samples: " + x3dom.caps.SAMPLES + "\nExtensions: " + extString);
+
+ if (x3dom.caps.INDEX_UINT) {
+ x3dom.Utils.maxIndexableCoords = 4294967295;
+ }
+
+ x3dom.caps.MOBILE = (function (a) {
+ return (/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4)))
+ })(navigator.userAgent || navigator.vendor || window.opera);
+
+ // explicitly disable for iPad and the like
+ if (x3dom.caps.RENDERER.indexOf("PowerVR") >= 0 ||
+ navigator.appVersion.indexOf("Mobile") > -1 ||
+ // coarse guess to find out old SM 2.0 hardware (e.g. Intel):
+ x3dom.caps.MAX_VARYING_VECTORS <= 8 ||
+ x3dom.caps.MAX_VERTEX_TEXTURE_IMAGE_UNITS < 2) {
+ x3dom.caps.MOBILE = true;
+ }
+
+ if (x3dom.caps.MOBILE) {
+ if (forbidMobileShaders) {
+ x3dom.caps.MOBILE = false;
+ x3dom.debug.logWarning("Detected mobile graphics card! " +
+ "But being forced to desktop shaders which might not work!");
+ }
+ else {
+ x3dom.debug.logWarning("Detected mobile graphics card! " +
+ "Using low quality shaders without ImageGeometry support!");
+ }
+ }
+ else {
+ if (forceMobileShaders) {
+ x3dom.caps.MOBILE = true;
+ x3dom.debug.logWarning("Detected desktop graphics card! " +
+ "But being forced to mobile shaders with lower quality!");
+ }
+ }
+ }
+ catch (ex) {
+ x3dom.debug.logWarning(
+ "Your browser probably supports an older WebGL version. " +
+ "Please try the old mobile runtime instead:\n" +
+ "http://www.x3dom.org/x3dom/src_mobile/x3dom.js");
+ newCtx = null;
+ }
+
+ return newCtx;
+ }
+ }
+ catch (e) { x3dom.debug.logWarning(e); }
+ }
+ return null;
+ }
+
+
+ /*****************************************************************************
+ * Setup GL objects for given shape
+ *****************************************************************************/
+ Context.prototype.setupShape = function (gl, drawable, viewarea) {
+ var q = 0, q6;
+ var textures, t;
+ var vertices, positionBuffer;
+ var texCoordBuffer, normalBuffer, colorBuffer;
+ var indicesBuffer, indexArray;
+
+ var shape = drawable.shape;
+ var geoNode = shape._cf.geometry.node;
+
+ if (shape._webgl !== undefined) {
+ var needFullReInit = false;
+
+ // TODO; do same for texcoords etc.!
+ if (shape._dirty.colors === true &&
+ shape._webgl.shader.color === undefined && geoNode._mesh._colors[0].length) {
+ // required since otherwise shape._webgl.shader.color stays undefined
+ // and thus the wrong shader will be chosen although there are colors
+ needFullReInit = true;
+ }
+
+ // cleanup vertex buffer objects
+ if (needFullReInit && shape._cleanupGLObjects) {
+ shape._cleanupGLObjects(true, false);
+ }
+
+ //Check for dirty Textures
+ if (shape._dirty.texture === true) {
+ //Check for Texture add or remove
+ if (shape._webgl.texture.length != shape.getTextures().length) {
+ //Delete old Textures
+ for (t = 0; t < shape._webgl.texture.length; ++t) {
+ shape._webgl.texture.pop();
+ }
+
+ //Generate new Textures
+ textures = shape.getTextures();
+
+ for (t = 0; t < textures.length; ++t) {
+ shape._webgl.texture.push(new x3dom.Texture(gl, shape._nameSpace.doc, this.cache, textures[t]));
+ }
+
+ //Set dirty shader
+ shape._dirty.shader = true;
+
+ //Set dirty texture Coordinates
+ if (shape._webgl.shader.texcoord === undefined)
+ shape._dirty.texcoords = true;
+ }
+ else {
+ //If someone remove and append at the same time, texture count don't change
+ //and we have to check if all nodes the same as before
+ textures = shape.getTextures();
+
+ for (t = 0; t < textures.length; ++t) {
+ if (textures[t] === shape._webgl.texture[t].node) {
+ //only update the texture
+ shape._webgl.texture[t].update();
+ }
+ else {
+ //Set texture to null for recreation
+ shape._webgl.texture[t].texture = null;
+
+ //Set new node
+ shape._webgl.texture[t].node = textures[t];
+
+ //Update new node
+ shape._webgl.texture[t].update();
+ }
+ }
+ }
+ shape._dirty.texture = false;
+ }
+
+ //Check if we need a new shader
+ shape._webgl.shader = this.cache.getShaderByProperties(gl, shape, shape.getShaderProperties(viewarea));
+
+ if (!needFullReInit && shape._webgl.binaryGeometry == 0) // THINKABOUTME: What about PopGeo & Co.?
+ {
+ for (q = 0; q < shape._webgl.positions.length; q++)
+ {
+ q6 = 6 * q;
+
+ if (shape._dirty.positions == true || shape._dirty.indexes == true) {
+ if (shape._webgl.shader.position !== undefined) {
+ shape._webgl.indexes[q] = geoNode._mesh._indices[q];
+
+ gl.deleteBuffer(shape._webgl.buffers[q6]);
+
+ indicesBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6] = indicesBuffer;
+
+ // explicitly check first positions array for consistency
+ if (x3dom.caps.INDEX_UINT && (geoNode._mesh._positions[0].length / 3 > 65535)) {
+ indexArray = new Uint32Array(shape._webgl.indexes[q]);
+ shape._webgl.indexType = gl.UNSIGNED_INT;
+ }
+ else {
+ indexArray = new Uint16Array(shape._webgl.indexes[q]);
+ shape._webgl.indexType = gl.UNSIGNED_SHORT;
+ }
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexArray, gl.STATIC_DRAW);
+
+ indexArray = null;
+
+ // vertex positions
+ shape._webgl.positions[q] = geoNode._mesh._positions[q];
+
+ // TODO; don't delete VBO but use glMapBuffer() and DYNAMIC_DRAW
+ gl.deleteBuffer(shape._webgl.buffers[q6 + 1]);
+
+ positionBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 1] = positionBuffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, shape._webgl.buffers[q6]);
+
+ vertices = new Float32Array(shape._webgl.positions[q]);
+
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ gl.vertexAttribPointer(shape._webgl.shader.position,
+ geoNode._mesh._numPosComponents,
+ shape._webgl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+
+ vertices = null;
+ }
+
+ shape._dirty.positions = false;
+ shape._dirty.indexes = false;
+ }
+
+ if (shape._dirty.colors == true) {
+ if (shape._webgl.shader.color !== undefined) {
+ shape._webgl.colors[q] = geoNode._mesh._colors[q];
+
+ gl.deleteBuffer(shape._webgl.buffers[q6 + 4]);
+
+ colorBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 4] = colorBuffer;
+
+ colors = new Float32Array(shape._webgl.colors[q]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(shape._webgl.shader.color,
+ geoNode._mesh._numColComponents,
+ shape._webgl.colorType, false,
+ shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+
+ colors = null;
+ }
+
+ shape._dirty.colors = false;
+ }
+
+ if (shape._dirty.normals == true) {
+ if (shape._webgl.shader.normal !== undefined) {
+ shape._webgl.normals[q] = geoNode._mesh._normals[q];
+
+ gl.deleteBuffer(shape._webgl.buffers[q6 + 2]);
+
+ normalBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 2] = normalBuffer;
+
+ normals = new Float32Array(shape._webgl.normals[q]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(shape._webgl.shader.normal,
+ geoNode._mesh._numNormComponents,
+ shape._webgl.normalType, false,
+ shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+
+ normals = null;
+ }
+
+ shape._dirty.normals = false;
+ }
+
+ if (shape._dirty.texcoords == true) {
+ if (shape._webgl.shader.texcoord !== undefined) {
+ shape._webgl.texcoords[q] = geoNode._mesh._texCoords[q];
+
+ gl.deleteBuffer(shape._webgl.buffers[q6 + 3]);
+
+ texCoordBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 3] = texCoordBuffer;
+
+ texCoords = new Float32Array(shape._webgl.texcoords[q]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(shape._webgl.shader.texCoord,
+ geoNode._mesh._numTexComponents,
+ shape._webgl.texCoordType, false,
+ shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+
+ texCoords = null;
+ }
+
+ shape._dirty.texcoords = false;
+ }
+
+ if (shape._dirty.specialAttribs == true) {
+ if (shape._webgl.shader.particleSize !== undefined) {
+ var szArr = geoNode._vf.size.toGL();
+
+ if (szArr.length) {
+ gl.deleteBuffer(shape._webgl.buffers[q6 + 5]);
+ shape._webgl.buffers[q6 + 5] = gl.createBuffer();
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, shape._webgl.buffers[q6 + 5]);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(szArr), gl.STATIC_DRAW);
+ }
+
+ shape._dirty.specialAttribs = false;
+ }
+ // Maybe other special attribs here, though e.g. AFAIK only BG (which not handled here) has ids.
+ }
+ }
+ }
+ else
+ {
+ // TODO; does not yet work with shared objects
+ /*
+ var spOld = shape._webgl.shader;
+ if (shape._cleanupGLObjects && needFullReInit)
+ shape._cleanupGLObjects(true, false);
+
+ // complete setup is sort of brute force, thus optimize!
+ x3dom.BinaryContainerLoader.setupBinGeo(shape, spOld, gl, viewarea, this);
+ shape.unsetGeoDirty();
+ */
+ }
+
+ if (shape._webgl.imageGeometry != 0) {
+ for (t = 0; t < shape._webgl.texture.length; ++t) {
+ shape._webgl.texture[t].updateTexture();
+ }
+
+ geoNode.unsetGeoDirty();
+ shape.unsetGeoDirty();
+ }
+
+ if (!needFullReInit) {
+ // we're done
+ return;
+ }
+ }
+ else if (!(x3dom.isa(geoNode, x3dom.nodeTypes.Text) ||
+ x3dom.isa(geoNode, x3dom.nodeTypes.BinaryGeometry) ||
+ x3dom.isa(geoNode, x3dom.nodeTypes.PopGeometry) ||
+ x3dom.isa(geoNode, x3dom.nodeTypes.ExternalGeometry)) &&
+ (!geoNode || geoNode._mesh._positions[0].length < 1))
+ {
+ if (x3dom.caps.MAX_VERTEX_TEXTURE_IMAGE_UNITS < 2 &&
+ x3dom.isa(geoNode, x3dom.nodeTypes.ImageGeometry)) {
+ x3dom.debug.logError("Can't render ImageGeometry nodes with only " +
+ x3dom.caps.MAX_VERTEX_TEXTURE_IMAGE_UNITS +
+ " vertex texture units. Please upgrade your GPU!");
+ }
+ else {
+ x3dom.debug.logError("NO VALID MESH OR NO VERTEX POSITIONS SET!");
+ }
+ return;
+ }
+
+ // we're on init, thus reset all dirty flags
+ shape.unsetDirty();
+
+ // dynamically attach clean-up method for GL objects
+ if (!shape._cleanupGLObjects)
+ {
+ shape._cleanupGLObjects = function (force, delGL)
+ {
+ // FIXME; what if complete tree is removed? Then _parentNodes.length may be greater 0.
+ if (this._webgl && ((arguments.length > 0 && force) || this._parentNodes.length == 0))
+ {
+ var sp = this._webgl.shader;
+
+ for (var q = 0; q < this._webgl.positions.length; q++) {
+ var q6 = 6 * q;
+
+ if (sp.position !== undefined) {
+ gl.deleteBuffer(this._webgl.buffers[q6 + 1]);
+ gl.deleteBuffer(this._webgl.buffers[q6]);
+ }
+
+ if (sp.normal !== undefined) {
+ gl.deleteBuffer(this._webgl.buffers[q6 + 2]);
+ }
+
+ if (sp.texcoord !== undefined) {
+ gl.deleteBuffer(this._webgl.buffers[q6 + 3]);
+ }
+
+ if (sp.color !== undefined) {
+ gl.deleteBuffer(this._webgl.buffers[q6 + 4]);
+ }
+
+ if (sp.id !== undefined) {
+ gl.deleteBuffer(this._webgl.buffers[q6 + 5]);
+ }
+ }
+
+ for (var df = 0; df < this._webgl.dynamicFields.length; df++) {
+ var attrib = this._webgl.dynamicFields[df];
+
+ if (sp[attrib.name] !== undefined) {
+ gl.deleteBuffer(attrib.buf);
+ }
+ }
+
+ if (delGL === undefined)
+ delGL = true;
+
+ if (delGL) {
+ delete this._webgl;
+
+ // be optimistic, one shape removed makes room for another one
+ x3dom.BinaryContainerLoader.outOfMemory = false;
+ }
+ }
+ }; // shape._cleanupGLObjects()
+ }
+
+
+ shape._webgl = {
+ positions: geoNode._mesh._positions,
+ normals: geoNode._mesh._normals,
+ texcoords: geoNode._mesh._texCoords,
+ colors: geoNode._mesh._colors,
+ indexes: geoNode._mesh._indices,
+ //indicesBuffer,positionBuffer,normalBuffer,texcBuffer,colorBuffer
+ //buffers: [{},{},{},{},{}],
+ indexType: gl.UNSIGNED_SHORT,
+ coordType: gl.FLOAT,
+ normalType: gl.FLOAT,
+ texCoordType: gl.FLOAT,
+ colorType: gl.FLOAT,
+ texture: [],
+ dirtyLighting: x3dom.Utils.checkDirtyLighting(viewarea),
+ imageGeometry: 0, // 0 := no IG, 1 := indexed IG, -1 := non-indexed IG
+ binaryGeometry: 0, // 0 := no BG, 1 := indexed BG, -1 := non-indexed BG
+ popGeometry: 0, // 0 : no PG, 1 : indexed PG, -1 : non-indexed PG
+ externalGeometry: 0 // 0 : no EG, 1 : indexed EG, -1 : non-indexed EG
+ };
+
+ //Set Textures
+ textures = shape.getTextures();
+ for (t = 0; t < textures.length; ++t) {
+ shape._webgl.texture.push(new x3dom.Texture(gl, shape._nameSpace.doc, this.cache, textures[t]));
+ }
+
+ //Set Shader
+ //shape._webgl.shader = this.cache.getDynamicShader(gl, viewarea, shape);
+ //shape._webgl.shader = this.cache.getShaderByProperties(gl, drawable.properties);
+ shape._webgl.shader = this.cache.getShaderByProperties(gl, shape, shape.getShaderProperties(viewarea));
+
+ // init vertex attribs
+ var sp = shape._webgl.shader;
+ var currAttribs = 0;
+
+ shape._webgl.buffers = [];
+ shape._webgl.dynamicFields = [];
+
+ //Set Geometry Primitive Type
+ if (x3dom.isa(geoNode, x3dom.nodeTypes.X3DBinaryContainerGeometryNode))
+ {
+ shape._webgl.primType = [];
+
+ for (var primCnt = 0; primCnt < geoNode._vf.primType.length; ++primCnt)
+ {
+ shape._webgl.primType.push(x3dom.Utils.primTypeDic(gl, geoNode._vf.primType[primCnt]));
+ }
+ }
+ else
+ {
+ shape._webgl.primType = x3dom.Utils.primTypeDic(gl, geoNode._mesh._primType);
+ }
+
+ // Binary container geometries need special handling
+ if (x3dom.isa(geoNode, x3dom.nodeTypes.ExternalGeometry))
+ {
+ geoNode.updateRenderData(shape, sp, gl, viewarea, this);
+ }
+ else if (x3dom.isa(geoNode, x3dom.nodeTypes.BinaryGeometry))
+ {
+ x3dom.BinaryContainerLoader.setupBinGeo(shape, sp, gl, viewarea, this);
+ }
+ else if (x3dom.isa(geoNode, x3dom.nodeTypes.PopGeometry))
+ {
+ x3dom.BinaryContainerLoader.setupPopGeo(shape, sp, gl, viewarea, this);
+ }
+ else if (x3dom.isa(geoNode, x3dom.nodeTypes.ImageGeometry))
+ {
+ x3dom.BinaryContainerLoader.setupImgGeo(shape, sp, gl, viewarea, this);
+ }
+ else // No special BinaryMesh, but IFS or similar
+ {
+ for (q = 0; q < shape._webgl.positions.length; q++)
+ {
+ q6 = 6 * q;
+
+ if (sp.position !== undefined) {
+ // bind indices for drawElements() call
+ indicesBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6] = indicesBuffer;
+
+ // explicitly check first positions array for consistency
+ if (x3dom.caps.INDEX_UINT && (shape._webgl.positions[0].length / 3 > 65535)) {
+ indexArray = new Uint32Array(shape._webgl.indexes[q]);
+ shape._webgl.indexType = gl.UNSIGNED_INT;
+ }
+ else {
+ indexArray = new Uint16Array(shape._webgl.indexes[q]);
+ shape._webgl.indexType = gl.UNSIGNED_SHORT;
+ }
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexArray, gl.STATIC_DRAW);
+
+ indexArray = null;
+
+ positionBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 1] = positionBuffer;
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ vertices = new Float32Array(shape._webgl.positions[q]);
+
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ gl.vertexAttribPointer(sp.position,
+ geoNode._mesh._numPosComponents,
+ shape._webgl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ vertices = null;
+ }
+ if (sp.normal !== undefined || shape._webgl.normals[q]) {
+ normalBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 2] = normalBuffer;
+
+ var normals = new Float32Array(shape._webgl.normals[q]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.normal,
+ geoNode._mesh._numNormComponents,
+ shape._webgl.normalType, false,
+ shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.normal);
+
+ normals = null;
+ }
+ if (sp.texcoord !== undefined) {
+ var texcBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 3] = texcBuffer;
+
+ var texCoords = new Float32Array(shape._webgl.texcoords[q]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, texcBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.texcoord,
+ geoNode._mesh._numTexComponents,
+ shape._webgl.texCoordType, false,
+ shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.texcoord);
+
+ texCoords = null;
+ }
+ if (sp.color !== undefined) {
+ colorBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 4] = colorBuffer;
+
+ var colors = new Float32Array(shape._webgl.colors[q]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.color,
+ geoNode._mesh._numColComponents,
+ shape._webgl.colorType, false,
+ shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.color);
+
+ colors = null;
+ }
+ if (sp.particleSize !== undefined) {
+ var sizeArr = geoNode._vf.size.toGL();
+
+ if (sizeArr.length) {
+ var sizeBuffer = gl.createBuffer();
+ shape._webgl.buffers[q6 + 5] = sizeBuffer;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, sizeBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(sizeArr), gl.STATIC_DRAW);
+ }
+ }
+ }
+
+ // TODO; FIXME; handle geometry with split mesh that has dynamic fields!
+ for (var df in geoNode._mesh._dynamicFields)
+ {
+ if (!geoNode._mesh._dynamicFields.hasOwnProperty(df))
+ continue;
+
+ var attrib = geoNode._mesh._dynamicFields[df];
+
+ shape._webgl.dynamicFields[currAttribs] = {
+ buf: {}, name: df, numComponents: attrib.numComponents };
+
+ if (sp[df] !== undefined) {
+ var attribBuffer = gl.createBuffer();
+ shape._webgl.dynamicFields[currAttribs++].buf = attribBuffer;
+
+ var attribs = new Float32Array(attrib.value);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, attribBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, attribs, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp[df], attrib.numComponents, gl.FLOAT, false, 0, 0);
+
+ attribs = null;
+ }
+ }
+ } // Standard geometry
+ };
+
+
+ /*****************************************************************************
+ * Mainly manages rendering of backgrounds and buffer clearing
+ *****************************************************************************/
+ Context.prototype.setupScene = function (gl, bgnd) {
+ var sphere = null;
+ var texture = null;
+
+ var that = this;
+
+ if (bgnd._webgl !== undefined) {
+ if (!bgnd._dirty) {
+ return;
+ }
+
+ if (bgnd._webgl.texture !== undefined && bgnd._webgl.texture) {
+ gl.deleteTexture(bgnd._webgl.texture);
+ }
+ if (bgnd._cleanupGLObjects) {
+ bgnd._cleanupGLObjects();
+ }
+ bgnd._webgl = {};
+ }
+
+ bgnd._dirty = false;
+
+ var url = bgnd.getTexUrl();
+ var i = 0;
+ var w = 1, h = 1;
+
+ if (url.length > 0 && url[0].length > 0) {
+ if (url.length >= 6 && url[1].length > 0 && url[2].length > 0 &&
+ url[3].length > 0 && url[4].length > 0 && url[5].length > 0) {
+ sphere = new x3dom.nodeTypes.Sphere();
+
+ bgnd._webgl = {
+ positions: sphere._mesh._positions[0],
+ indexes: sphere._mesh._indices[0],
+ buffers: [
+ {}, {}
+ ]
+ };
+
+ bgnd._webgl.primType = gl.TRIANGLES;
+
+ bgnd._webgl.shader = this.cache.getShader(gl, x3dom.shader.BACKGROUND_CUBETEXTURE);
+
+ bgnd._webgl.texture = x3dom.Utils.createTextureCube(gl, bgnd._nameSpace.doc, url,
+ true, bgnd._vf.crossOrigin, true, false);
+ }
+ else {
+ bgnd._webgl = {
+ positions: [-w, -h, 0, -w, h, 0, w, -h, 0, w, h, 0],
+ indexes: [0, 1, 2, 3],
+ buffers: [
+ {}, {}
+ ]
+ };
+
+ url = bgnd._nameSpace.getURL(url[0]);
+
+ bgnd._webgl.texture = x3dom.Utils.createTexture2D(gl, bgnd._nameSpace.doc, url,
+ true, bgnd._vf.crossOrigin, true, false);
+
+ bgnd._webgl.primType = gl.TRIANGLE_STRIP;
+
+ bgnd._webgl.shader = this.cache.getShader(gl, x3dom.shader.BACKGROUND_TEXTURE);
+ }
+ }
+ else {
+ if (bgnd.getSkyColor().length > 1 || bgnd.getGroundColor().length) {
+ sphere = new x3dom.nodeTypes.Sphere();
+ texture = gl.createTexture();
+
+ bgnd._webgl = {
+ positions: sphere._mesh._positions[0],
+ texcoords: sphere._mesh._texCoords[0],
+ indexes: sphere._mesh._indices[0],
+ buffers: [
+ {}, {}, {}
+ ],
+ texture: texture,
+ primType: gl.TRIANGLES
+ };
+
+ var N = x3dom.Utils.nextHighestPowerOfTwo(
+ bgnd.getSkyColor().length + bgnd.getGroundColor().length + 2);
+ N = (N < 512) ? 512 : N;
+
+ var n = bgnd._vf.groundAngle.length;
+ var tmp = [], arr = [];
+ var colors = [], sky = [0];
+
+ for (i = 0; i < bgnd._vf.skyColor.length; i++) {
+ colors[i] = bgnd._vf.skyColor[i];
+ }
+
+ for (i = 0; i < bgnd._vf.skyAngle.length; i++) {
+ sky[i + 1] = bgnd._vf.skyAngle[i];
+ }
+
+ if (n > 0 || bgnd._vf.groundColor.length == 1) {
+ if (sky[sky.length - 1] < Math.PI / 2) {
+ sky[sky.length] = Math.PI / 2 - x3dom.fields.Eps;
+ colors[colors.length] = colors[colors.length - 1];
+ }
+
+ for (i = n - 1; i >= 0; i--) {
+ if ((i == n - 1) && (Math.PI - bgnd._vf.groundAngle[i] <= Math.PI / 2)) {
+ sky[sky.length] = Math.PI / 2;
+ colors[colors.length] = bgnd._vf.groundColor[bgnd._vf.groundColor.length - 1];
+ }
+ sky[sky.length] = Math.PI - bgnd._vf.groundAngle[i];
+ colors[colors.length] = bgnd._vf.groundColor[i + 1];
+ }
+
+ if (n == 0 && bgnd._vf.groundColor.length == 1) {
+ sky[sky.length] = Math.PI / 2;
+ colors[colors.length] = bgnd._vf.groundColor[0];
+ }
+ sky[sky.length] = Math.PI;
+ colors[colors.length] = bgnd._vf.groundColor[0];
+ }
+ else {
+ if (sky[sky.length - 1] < Math.PI) {
+ sky[sky.length] = Math.PI;
+ colors[colors.length] = colors[colors.length - 1];
+ }
+ }
+
+ for (i = 0; i < sky.length; i++) {
+ sky[i] /= Math.PI;
+ }
+
+ if (sky.length != colors.length) {
+ x3dom.debug.logError("Number of background colors and corresponding angles are different!");
+ var minArrayLength = (sky.length < colors.length) ? sky.length : colors.length;
+ sky.length = minArrayLength;
+ colors.length = minArrayLength;
+ }
+
+ var interp = new x3dom.nodeTypes.ColorInterpolator();
+
+ interp._vf.key = new x3dom.fields.MFFloat(sky);
+ interp._vf.keyValue = new x3dom.fields.MFColor(colors);
+
+ for (i = 0; i < N; i++) {
+ interp._vf.set_fraction = i / (N - 1.0);
+
+ interp.fieldChanged("set_fraction");
+ tmp[i] = interp._vf.value_changed;
+ }
+
+ tmp.reverse();
+
+ var alpha = Math.floor((1.0 - bgnd.getTransparency()) * 255);
+
+ for (i = 0; i < tmp.length; i++) {
+ arr.push(Math.floor(tmp[i].r * 255),
+ Math.floor(tmp[i].g * 255),
+ Math.floor(tmp[i].b * 255),
+ alpha);
+ }
+
+ var pixels = new Uint8Array(arr);
+ var format = gl.RGBA;
+
+ N = pixels.length / 4;
+
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, 1, N, 0, format, gl.UNSIGNED_BYTE, pixels);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ bgnd._webgl.shader = this.cache.getShader(gl, x3dom.shader.BACKGROUND_SKYTEXTURE);
+ }
+ else {
+ // Impl. gradient bg etc., e.g. via canvas 2d? But can be done via CSS anyway...
+ bgnd._webgl = {};
+ }
+ }
+
+ if (bgnd._webgl.shader) {
+ var sp = bgnd._webgl.shader;
+
+ var positionBuffer = gl.createBuffer();
+ bgnd._webgl.buffers[1] = positionBuffer;
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ var vertices = new Float32Array(bgnd._webgl.positions);
+
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ gl.vertexAttribPointer(sp.position, 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ var indicesBuffer = gl.createBuffer();
+ bgnd._webgl.buffers[0] = indicesBuffer;
+
+ var indexArray = new Uint16Array(bgnd._webgl.indexes);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexArray, gl.STATIC_DRAW);
+
+ vertices = null;
+ indexArray = null;
+
+ if (sp.texcoord !== undefined) {
+ var texcBuffer = gl.createBuffer();
+ bgnd._webgl.buffers[2] = texcBuffer;
+
+ var texcoords = new Float32Array(bgnd._webgl.texcoords);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, texcBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, texcoords, gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(sp.texcoord, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.texcoord);
+
+ texcoords = null;
+ }
+
+ bgnd._cleanupGLObjects = function () {
+ var sp = this._webgl.shader;
+
+ if (sp.position !== undefined) {
+ gl.deleteBuffer(this._webgl.buffers[0]);
+ gl.deleteBuffer(this._webgl.buffers[1]);
+ }
+ if (sp.texcoord !== undefined) {
+ gl.deleteBuffer(this._webgl.buffers[2]);
+ }
+ };
+ }
+
+ bgnd._webgl.render = function (gl, mat_view, mat_proj)
+ {
+ var sp = bgnd._webgl.shader;
+ var alpha = 1.0 - bgnd.getTransparency();
+
+ var mat_scene = null;
+ var projMatrix_22 = mat_proj._22,
+ projMatrix_23 = mat_proj._23;
+ var camPos = mat_view.e3();
+
+ if ((sp !== undefined && sp !== null) &&
+ (sp.texcoord !== undefined && sp.texcoord !== null) &&
+ (bgnd._webgl.texture !== undefined && bgnd._webgl.texture !== null)) {
+ gl.clearColor(0, 0, 0, alpha);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ that.stateManager.frontFace(gl.CCW);
+ that.stateManager.disable(gl.CULL_FACE);
+ that.stateManager.disable(gl.DEPTH_TEST);
+ that.stateManager.disable(gl.BLEND);
+
+ that.stateManager.useProgram(sp);
+
+ if (!sp.tex) {
+ sp.tex = 0;
+ }
+
+ // adapt projection matrix to better near/far
+ mat_proj._22 = 100001 / 99999;
+ mat_proj._23 = 200000 / 99999;
+ // center viewpoint
+ mat_view._03 = 0;
+ mat_view._13 = 0;
+ mat_view._23 = 0;
+
+ mat_scene = mat_proj.mult(mat_view);
+ sp.modelViewProjectionMatrix = mat_scene.toGL();
+
+ mat_view._03 = camPos.x;
+ mat_view._13 = camPos.y;
+ mat_view._23 = camPos.z;
+
+ mat_proj._22 = projMatrix_22;
+ mat_proj._23 = projMatrix_23;
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, bgnd._webgl.texture);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bgnd._webgl.buffers[0]);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, bgnd._webgl.buffers[1]);
+ gl.vertexAttribPointer(sp.position, 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, bgnd._webgl.buffers[2]);
+ gl.vertexAttribPointer(sp.texcoord, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.texcoord);
+
+ gl.drawElements(bgnd._webgl.primType, bgnd._webgl.indexes.length, gl.UNSIGNED_SHORT, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ gl.disableVertexAttribArray(sp.position);
+ gl.disableVertexAttribArray(sp.texcoord);
+
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+ }
+ else if (!sp || !bgnd._webgl.texture ||
+ (bgnd._webgl.texture.textureCubeReady !== undefined &&
+ bgnd._webgl.texture.textureCubeReady !== true)) {
+ var bgCol = bgnd.getSkyColor().toGL();
+
+ gl.clearColor(bgCol[0], bgCol[1], bgCol[2], alpha);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+ }
+ else {
+ gl.clearColor(0, 0, 0, alpha);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ that.stateManager.frontFace(gl.CCW);
+ that.stateManager.disable(gl.CULL_FACE);
+ that.stateManager.disable(gl.DEPTH_TEST);
+ that.stateManager.disable(gl.BLEND);
+
+ that.stateManager.useProgram(sp);
+
+ if (!sp.tex) {
+ sp.tex = 0;
+ }
+
+ if (bgnd._webgl.texture.textureCubeReady) {
+ // adapt projection matrix to better near/far
+ mat_proj._22 = 100001 / 99999;
+ mat_proj._23 = 200000 / 99999;
+ // center viewpoint
+ mat_view._03 = 0;
+ mat_view._13 = 0;
+ mat_view._23 = 0;
+
+ mat_scene = mat_proj.mult(mat_view);
+ sp.modelViewProjectionMatrix = mat_scene.toGL();
+
+ mat_view._03 = camPos.x;
+ mat_view._13 = camPos.y;
+ mat_view._23 = camPos.z;
+
+ mat_proj._22 = projMatrix_22;
+ mat_proj._23 = projMatrix_23;
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, bgnd._webgl.texture);
+
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ }
+ else {
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, bgnd._webgl.texture);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ }
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bgnd._webgl.buffers[0]);
+ gl.bindBuffer(gl.ARRAY_BUFFER, bgnd._webgl.buffers[1]);
+ gl.vertexAttribPointer(sp.position, 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ gl.drawElements(bgnd._webgl.primType, bgnd._webgl.indexes.length, gl.UNSIGNED_SHORT, 0);
+
+ gl.disableVertexAttribArray(sp.position);
+
+ gl.activeTexture(gl.TEXTURE0);
+ if (bgnd._webgl.texture.textureCubeReady) {
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+ }
+ else {
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+
+ gl.clear(gl.DEPTH_BUFFER_BIT);
+ }
+ };
+ };
+
+
+ /*****************************************************************************
+ * Setup Frontgrounds
+ *****************************************************************************/
+ Context.prototype.setupFgnds = function (gl, scene) {
+ if (scene._fgnd !== undefined) {
+ return;
+ }
+
+ var that = this;
+
+ var w = 1, h = 1;
+ scene._fgnd = {};
+
+ scene._fgnd._webgl = {
+ positions: [-w, -h, 0, -w, h, 0, w, -h, 0, w, h, 0],
+ indexes: [0, 1, 2, 3],
+ buffers: [
+ {}, {}
+ ]
+ };
+
+ scene._fgnd._webgl.primType = gl.TRIANGLE_STRIP;
+
+ scene._fgnd._webgl.shader = this.cache.getShader(gl, x3dom.shader.FRONTGROUND_TEXTURE);
+
+ var sp = scene._fgnd._webgl.shader;
+
+ var positionBuffer = gl.createBuffer();
+ scene._fgnd._webgl.buffers[1] = positionBuffer;
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ var vertices = new Float32Array(scene._fgnd._webgl.positions);
+
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+
+ gl.vertexAttribPointer(sp.position, 3, gl.FLOAT, false, 0, 0);
+
+ var indicesBuffer = gl.createBuffer();
+ scene._fgnd._webgl.buffers[0] = indicesBuffer;
+
+ var indexArray = new Uint16Array(scene._fgnd._webgl.indexes);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexArray, gl.STATIC_DRAW);
+
+ vertices = null;
+ indexArray = null;
+
+ scene._fgnd._webgl.render = function (gl, tex) {
+ scene._fgnd._webgl.texture = tex;
+
+ that.stateManager.frontFace(gl.CCW);
+ that.stateManager.disable(gl.CULL_FACE);
+ that.stateManager.disable(gl.DEPTH_TEST);
+
+ that.stateManager.useProgram(sp);
+
+ if (!sp.tex) {
+ sp.tex = 0;
+ }
+
+ //this.stateManager.enable(gl.TEXTURE_2D);
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, scene._fgnd._webgl.texture);
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, scene._fgnd._webgl.buffers[0]);
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._fgnd._webgl.buffers[1]);
+ gl.vertexAttribPointer(sp.position, 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ gl.drawElements(scene._fgnd._webgl.primType, scene._fgnd._webgl.indexes.length, gl.UNSIGNED_SHORT, 0);
+
+ gl.disableVertexAttribArray(sp.position);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ //this.stateManager.disable(gl.TEXTURE_2D);
+ };
+ };
+
+
+ /*****************************************************************************
+ * Render Shadow-Pass
+ *****************************************************************************/
+ Context.prototype.renderShadowPass = function (gl, viewarea, mat_scene, mat_view, targetFbo, camOffset, isCameraView)
+ {
+ var scene = viewarea._scene;
+ var sp = scene._webgl.shadowShader;
+
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, targetFbo.fbo);
+ this.stateManager.viewport(0, 0, targetFbo.width, targetFbo.height);
+
+ this.stateManager.useProgram(sp);
+
+ sp.cameraView = isCameraView;
+ sp.offset = camOffset;
+
+ // workaround for old graphics cards/ drivers
+ {
+ sp.PG_precisionLevel = 1.0;
+ sp.PG_powPrecision = 1.0;
+ sp.PG_maxBBSize = [0, 0, 0];
+ sp.PG_bbMin = [0, 0, 0];
+ sp.PG_bbMaxModF = [0, 0, 0];
+ sp.PG_bboxShiftVec = [0, 0, 0];
+ }
+
+ gl.clearColor(1.0, 1.0, 1.0, 0.0);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ this.stateManager.depthFunc(gl.LEQUAL);
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.enable(gl.CULL_FACE);
+ this.stateManager.disable(gl.BLEND);
+
+ var bgCenter = x3dom.fields.SFVec3f.NullVector.toGL();
+ var bgSize = x3dom.fields.SFVec3f.OneVector.toGL();
+
+ var env = scene.getEnvironment();
+ var excludeTrans = env._vf.shadowExcludeTransparentObjects;
+
+ var i, n = scene.drawableCollection.length;
+
+ for (i = 0; i < n; i++)
+ {
+ var drawable = scene.drawableCollection.get(i);
+ var trafo = drawable.transform;
+ var shape = drawable.shape;
+
+ var s_gl = shape._webgl;
+
+ if (!s_gl || (excludeTrans && drawable.sortType == 'transparent')) {
+ continue;
+ }
+
+ var s_geo = shape._cf.geometry.node;
+ var s_msh = s_geo._mesh;
+
+ sp.modelViewProjectionMatrix = mat_scene.mult(trafo).toGL();
+
+ //Set ImageGeometry switch
+ sp.imageGeometry = s_gl.imageGeometry;
+ sp.popGeometry = s_gl.popGeometry;
+
+ if (s_gl.coordType != gl.FLOAT) {
+ if (!s_gl.popGeometry && (x3dom.Utils.isUnsignedType(s_geo._vf.coordType))) {
+ sp.bgCenter = s_geo.getMin().toGL();
+ }
+ else {
+ sp.bgCenter = s_geo._vf.position.toGL();
+ }
+ sp.bgSize = s_geo._vf.size.toGL();
+ sp.bgPrecisionMax = s_geo.getPrecisionMax('coordType');
+ }
+ else {
+ sp.bgCenter = bgCenter;
+ sp.bgSize = bgSize;
+ sp.bgPrecisionMax = 1;
+ }
+
+ if (s_gl.colorType != gl.FLOAT) {
+ sp.bgPrecisionColMax = s_geo.getPrecisionMax('colorType');
+ }
+
+ if (s_gl.texCoordType != gl.FLOAT) {
+ sp.bgPrecisionTexMax = s_geo.getPrecisionMax('texCoordType');
+ }
+
+ if (s_gl.imageGeometry != 0 && !x3dom.caps.MOBILE) // FIXME: mobile errors
+ {
+ sp.IG_bboxMin = s_geo.getMin().toGL();
+ sp.IG_bboxMax = s_geo.getMax().toGL();
+ sp.IG_implicitMeshSize = s_geo._vf.implicitMeshSize.toGL(); // FIXME
+
+ var coordTex = x3dom.Utils.findTextureByName(s_gl.texture, "IG_coords0");
+ if (coordTex) {
+ sp.IG_coordTextureWidth = coordTex.texture.width;
+ sp.IG_coordTextureHeight = coordTex.texture.height;
+ }
+
+ if (s_gl.imageGeometry == 1) {
+ var indexTex = x3dom.Utils.findTextureByName(s_gl.texture, "IG_index");
+ if (indexTex) {
+ sp.IG_indexTextureWidth = indexTex.texture.width;
+ sp.IG_indexTextureHeight = indexTex.texture.height;
+ }
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, indexTex.texture);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, coordTex.texture);
+ }
+ else {
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, coordTex.texture);
+ }
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+
+ var texUnit = 0;
+ if (s_geo.getIndexTexture()) {
+ if (!sp.IG_indexTexture) {
+ sp.IG_indexTexture = texUnit++;
+ }
+ }
+ if (s_geo.getCoordinateTexture(0)) {
+ if (!sp.IG_coordinateTexture) {
+ sp.IG_coordinateTexture = texUnit++;
+ }
+ }
+ }
+
+ if (shape.isSolid()) {
+ this.stateManager.enable(gl.CULL_FACE);
+
+ if (shape.isCCW()) {
+ this.stateManager.frontFace(gl.CCW);
+ }
+ else {
+ this.stateManager.frontFace(gl.CW);
+ }
+ }
+ else {
+ this.stateManager.disable(gl.CULL_FACE);
+ }
+
+ //PopGeometry: adapt LOD and set shader variables
+ if (s_gl.popGeometry) {
+ var model_view = mat_view.mult(trafo);
+ this.updatePopState(drawable, s_geo, sp, s_gl, scene, model_view, viewarea, this.x3dElem.runtime.fps);
+ }
+
+ var q_n;
+ if (s_gl.externalGeometry != 0)
+ {
+ q_n = s_gl.primType.length;
+ }
+ else
+ {
+ q_n = s_gl.positions.length;
+ }
+ for (var q = 0; q < q_n; q++) {
+ var q6 = 6 * q;
+ var v, v_n, offset;
+
+ if ( !(sp.position !== undefined && s_gl.buffers[q6 + 1] && (s_gl.indexes[q] || s_gl.externalGeometry != 0)) )
+ continue;
+
+ // set buffers
+ if (s_gl.buffers[q6]) {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, s_gl.buffers[q6]);
+ }
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 1]);
+
+ gl.vertexAttribPointer(sp.position,
+ s_msh._numPosComponents, s_gl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ if (s_gl.binaryGeometry > 0 || s_gl.popGeometry > 0) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType[v], s_geo._vf.vertexCount[v], s_gl.indexType,
+ x3dom.Utils.getByteAwareOffset(offset, s_gl.indexType, gl));
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ else if (s_gl.binaryGeometry < 0 || s_gl.popGeometry < 0 || s_gl.imageGeometry) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawArrays(s_gl.primType[v], offset, s_geo._vf.vertexCount[v]);
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ //ExternalGeometry: indexed rendering (shadow pass)
+ else if (s_gl.externalGeometry == 1)
+ {
+ gl.drawElements(s_gl.primType[q], s_gl.drawCount[q], s_gl.indexType, s_gl.indexOffset[q]);
+ }
+ //ExternalGeometry: non-indexed rendering (shadow pass)
+ else if (s_gl.externalGeometry == -1)
+ {
+ gl.drawArrays(s_gl.primType[q], 0, s_gl.drawCount[q]);
+ }
+ else if (s_geo.hasIndexOffset()) {
+ var indOff = shape.tessellationProperties();
+ for (v = 0, v_n = indOff.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType, indOff[v].count, s_gl.indexType,
+ indOff[v].offset * x3dom.Utils.getOffsetMultiplier(s_gl.indexType, gl));
+ }
+ }
+ else if (s_gl.indexes[q].length == 0) {
+ gl.drawArrays(s_gl.primType, 0, s_gl.positions[q].length / 3);
+ }
+ else {
+ gl.drawElements(s_gl.primType, s_gl.indexes[q].length, s_gl.indexType, 0);
+ }
+
+ gl.disableVertexAttribArray(sp.position);
+ }
+
+ //Clean Texture units for IG
+ if (s_gl.imageGeometry != 0 && !x3dom.caps.MOBILE) {
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ if (s_gl.imageGeometry == 1) {
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+ }
+ }
+
+ gl.flush();
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, null);
+ };
+
+ /*****************************************************************************
+ * Render Picking-Pass
+ *****************************************************************************/
+ Context.prototype.renderPickingPass = function (gl, scene, mat_view, mat_scene, from, sceneSize,
+ pickMode, lastX, lastY, width, height)
+ {
+ var ps = scene._webgl.pickScale;
+ var bufHeight = scene._webgl.fboPick.height;
+ var x = lastX * ps;
+ var y = (bufHeight - 1) - lastY * ps;
+
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, scene._webgl.fboPick.fbo);
+ this.stateManager.viewport(0, 0, scene._webgl.fboPick.width, bufHeight);
+
+ //gl.scissor(x, y, width, height);
+ //gl.enable(gl.SCISSOR_TEST);
+
+ gl.clearColor(0.0, 0.0, 0.0, 0.0);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ var viewarea = scene.drawableCollection.viewarea;
+ var env = scene.getEnvironment();
+ var n = scene.drawableCollection.length;
+
+ if (env._vf.smallFeatureCulling && env._lowPriorityThreshold < 1 && viewarea.isMovingOrAnimating()) {
+ n = Math.floor(n * env._lowPriorityThreshold);
+ if (!n && scene.drawableCollection.length)
+ n = 1; // render at least one object
+ }
+
+ var bgCenter = x3dom.fields.SFVec3f.NullVector.toGL();
+ var bgSize = x3dom.fields.SFVec3f.OneVector.toGL();
+
+ this.stateManager.depthFunc(gl.LEQUAL);
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.enable(gl.CULL_FACE);
+ this.stateManager.disable(gl.BLEND);
+
+ if (x3dom.Utils.needLineWidth) {
+ this.stateManager.lineWidth(2); // bigger lines for better picking
+ }
+
+ for (var i = 0; i < n; i++)
+ {
+ var drawable = scene.drawableCollection.get(i);
+ var trafo = drawable.transform;
+ var shape = drawable.shape;
+ var s_gl = shape._webgl;
+
+ if (!s_gl || shape._objectID < 1 || !shape._vf.isPickable) {
+ continue;
+ }
+
+ var s_geo = shape._cf.geometry.node;
+ var s_app = shape._cf.appearance.node;
+ var s_msh = s_geo._mesh;
+
+ //Get shapes shader properties
+ var properties = shape.getShaderProperties(viewarea);
+
+ //Generate Dynamic picking shader
+ var sp = this.cache.getShaderByProperties(gl, shape, properties, pickMode);
+
+ if (!sp) { // error
+ return;
+ }
+
+ //Bind shader
+ this.stateManager.useProgram(sp);
+
+ sp.modelMatrix = trafo.toGL();
+ sp.modelViewProjectionMatrix = mat_scene.mult(trafo).toGL();
+
+ sp.lowBit = (shape._objectID & 255) / 255.0;
+ sp.highBit = (shape._objectID >>> 8) / 255.0;
+
+ sp.from = from.toGL();
+ sp.sceneSize = sceneSize;
+
+ // Set shadow ids if available
+ if(s_gl.binaryGeometry != 0 && s_geo._vf.idsPerVertex) {
+ sp.shadowIDs = (shape._vf.idOffset + x3dom.nodeTypes.Shape.objectID + 2);
+ }
+
+ // BoundingBox stuff
+ if (s_gl.coordType != gl.FLOAT) {
+ if (!s_gl.popGeometry && (x3dom.Utils.isUnsignedType(s_geo._vf.coordType))) {
+ sp.bgCenter = s_geo.getMin().toGL();
+ }
+ else {
+ sp.bgCenter = s_geo._vf.position.toGL();
+ }
+ sp.bgSize = s_geo._vf.size.toGL();
+ sp.bgPrecisionMax = s_geo.getPrecisionMax('coordType');
+ }
+
+ if (pickMode == 1 && s_gl.colorType != gl.FLOAT) {
+ sp.bgPrecisionColMax = s_geo.getPrecisionMax('colorType');
+ }
+
+ if (pickMode == 2 && s_gl.texCoordType != gl.FLOAT) {
+ sp.bgPrecisionTexMax = s_geo.getPrecisionMax('texCoordType');
+ }
+
+ //===========================================================================
+ // Set ClipPlanes
+ //===========================================================================
+ if (shape._clipPlanes) {
+ sp.modelViewMatrix = mat_view.mult(trafo).toGL();
+ sp.viewMatrixInverse = mat_view.inverse().toGL();
+ for (var cp = 0; cp < shape._clipPlanes.length; cp++) {
+ var clip_plane = shape._clipPlanes[cp].plane;
+ var clip_trafo = shape._clipPlanes[cp].trafo;
+
+ sp['clipPlane' + cp + '_Plane'] = clip_trafo.multMatrixPlane(clip_plane._vf.plane).toGL();
+ sp['clipPlane' + cp + '_CappingStrength'] = clip_plane._vf.cappingStrength;
+ sp['clipPlane' + cp + '_CappingColor'] = clip_plane._vf.cappingColor.toGL();
+ }
+ }
+
+ //ImageGeometry stuff
+ if (s_gl.imageGeometry != 0 && !x3dom.caps.MOBILE) // FIXME: mobile errors
+ {
+ sp.IG_bboxMin = s_geo.getMin().toGL();
+ sp.IG_bboxMax = s_geo.getMax().toGL();
+ sp.IG_implicitMeshSize = s_geo._vf.implicitMeshSize.toGL(); // FIXME
+
+ var coordTex = x3dom.Utils.findTextureByName(s_gl.texture, "IG_coords0");
+ if (coordTex) {
+ sp.IG_coordTextureWidth = coordTex.texture.width;
+ sp.IG_coordTextureHeight = coordTex.texture.height;
+ }
+
+ if (s_gl.imageGeometry == 1) {
+ var indexTex = x3dom.Utils.findTextureByName(s_gl.texture, "IG_index");
+ if (indexTex) {
+ sp.IG_indexTextureWidth = indexTex.texture.width;
+ sp.IG_indexTextureHeight = indexTex.texture.height;
+ }
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, indexTex.texture);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, coordTex.texture);
+ }
+ else {
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, coordTex.texture);
+ }
+
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+
+ var texUnit = 0;
+ if (s_geo.getIndexTexture()) {
+ if (!sp.IG_indexTexture) {
+ sp.IG_indexTexture = texUnit++;
+ }
+ }
+ if (s_geo.getCoordinateTexture(0)) {
+ if (!sp.IG_coordinateTexture) {
+ sp.IG_coordinateTexture = texUnit++;
+ }
+ }
+ }
+ else if (s_gl.binaryGeometry != 0 && s_geo._vf.idsPerVertex) { //MultiPart
+ var shader = s_app._shader;
+ if(shader && x3dom.isa(s_app._shader, x3dom.nodeTypes.CommonSurfaceShader)) {
+ if (shader.getMultiVisibilityMap()) {
+ sp.multiVisibilityMap = 0;
+ var visTex = x3dom.Utils.findTextureByName(s_gl.texture, "multiVisibilityMap");
+ sp.multiVisibilityWidth = visTex.texture.width;
+ sp.multiVisibilityHeight = visTex.texture.height;
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, visTex.texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ }
+ }
+ }
+
+ if (shape.isSolid()) {
+ this.stateManager.enable(gl.CULL_FACE);
+
+ if (shape.isCCW()) {
+ this.stateManager.frontFace(gl.CCW);
+ }
+ else {
+ this.stateManager.frontFace(gl.CW);
+ }
+ }
+ else {
+ this.stateManager.disable(gl.CULL_FACE);
+ }
+
+
+ //===========================================================================
+ // Set DepthMode
+ //===========================================================================
+ var depthMode = s_app ? s_app._cf.depthMode.node : null;
+ if (depthMode)
+ {
+ if (depthMode._vf.enableDepthTest)
+ {
+ //Enable Depth Test
+ this.stateManager.enable(gl.DEPTH_TEST);
+
+ //Set Depth Mask
+ this.stateManager.depthMask(!depthMode._vf.readOnly);
+
+ //Set Depth Function
+ this.stateManager.depthFunc(x3dom.Utils.depthFunc(gl, depthMode._vf.depthFunc));
+
+ //Set Depth Range
+ this.stateManager.depthRange(depthMode._vf.zNearRange, depthMode._vf.zFarRange);
+ }
+ else
+ {
+ //Disable Depth Test
+ this.stateManager.disable(gl.DEPTH_TEST);
+ }
+ }
+ else //Set Defaults
+ {
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.depthMask(true);
+ this.stateManager.depthFunc(gl.LEQUAL);
+ }
+
+ //PopGeometry: adapt LOD and set shader variables
+ if (s_gl.popGeometry) {
+ var model_view = mat_view.mult(trafo);
+ // FIXME; viewarea's width/height twice as big as render buffer size, which leads to too high precision
+ // the correct viewarea here would be one that holds this half-sized render buffer
+ this.updatePopState(drawable, s_geo, sp, s_gl, scene, model_view, viewarea, this.x3dElem.runtime.fps);
+ }
+
+ var q_n;
+ if (s_gl.externalGeometry != 0)
+ {
+ q_n = s_gl.primType.length;
+ }
+ else
+ {
+ q_n = s_gl.positions.length;
+ }
+ for (var q = 0; q < q_n; q++) {
+ var q6 = 6 * q;
+ var v, v_n, offset;
+
+ if ( !(sp.position !== undefined && s_gl.buffers[q6 + 1] && (s_gl.indexes[q] || s_gl.externalGeometry != 0)) )
+ continue;
+
+ // set buffers
+ if (s_gl.buffers[q6]) {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, s_gl.buffers[q6]);
+ }
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 1]);
+
+ gl.vertexAttribPointer(sp.position,
+ s_msh._numPosComponents, s_gl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ if (pickMode == 1 && sp.color !== undefined && s_gl.buffers[q6 + 4]) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 4]);
+
+ gl.vertexAttribPointer(sp.color,
+ s_msh._numColComponents, s_gl.colorType, false,
+ shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.color);
+ }
+
+ if (pickMode == 2 && sp.texcoord !== undefined && s_gl.buffers[q6 + 3]) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 3]);
+
+ gl.vertexAttribPointer(sp.texcoord,
+ s_msh._numTexComponents, s_gl.texCoordType, false,
+ shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.texcoord);
+ }
+
+ if (sp.id !== undefined && s_gl.buffers[q6 + 5]) {
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 5]);
+ //texture coordinate hack for IDs
+ if (s_gl.binaryGeometry != 0 && s_geo._vf["idsPerVertex"] == true)
+ {
+ gl.vertexAttribPointer(sp.id,
+ 1, gl.FLOAT, false,
+ 4, 0);
+ gl.enableVertexAttribArray(sp.id);
+ }
+ else
+ {
+ /*
+ gl.vertexAttribPointer(sp.id,
+ 1, gl.FLOAT, false,
+ shape._idStrideOffset[0], shape._idStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.id);
+ */
+ }
+ }
+
+ // render mesh
+ if (s_gl.binaryGeometry > 0 || s_gl.popGeometry > 0) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType[v], s_geo._vf.vertexCount[v], s_gl.indexType,
+ x3dom.Utils.getByteAwareOffset(offset, s_gl.indexType, gl));
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ else if (s_gl.binaryGeometry < 0 || s_gl.popGeometry < 0 || s_gl.imageGeometry) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawArrays(s_gl.primType[v], offset, s_geo._vf.vertexCount[v]);
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ //ExternalGeometry: indexed rendering (picking pass)
+ else if (s_gl.externalGeometry == 1)
+ {
+ gl.drawElements(s_gl.primType[q], s_gl.drawCount[q], s_gl.indexType, s_gl.indexOffset[q]);
+ }
+ //ExternalGeometry: non-indexed rendering (picking pass)
+ else if (s_gl.externalGeometry == -1)
+ {
+ gl.drawArrays(s_gl.primType[q], 0, s_gl.drawCount[q]);
+ }
+ else if (s_geo.hasIndexOffset()) {
+ var indOff = shape.tessellationProperties();
+ for (v = 0, v_n = indOff.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType, indOff[v].count, s_gl.indexType,
+ indOff[v].offset * x3dom.Utils.getOffsetMultiplier(s_gl.indexType, gl));
+ }
+ }
+ else if (s_gl.indexes[q].length == 0) {
+ gl.drawArrays(s_gl.primType, 0, s_gl.positions[q].length / 3);
+ }
+ else {
+ gl.drawElements(s_gl.primType, s_gl.indexes[q].length, s_gl.indexType, 0);
+ }
+
+ gl.disableVertexAttribArray(sp.position);
+
+ if (sp.texcoord !== undefined && s_gl.buffers[q6 + 3]) {
+ gl.disableVertexAttribArray(sp.texcoord);
+ }
+ if (sp.color !== undefined && s_gl.buffers[q6 + 4]) {
+ gl.disableVertexAttribArray(sp.color);
+ }
+ if (sp.id !== undefined && s_gl.buffers[q6 + 5]) {
+ gl.disableVertexAttribArray(sp.id);
+ }
+ }
+
+ //Clean Texture units for IG
+ if (s_gl.imageGeometry != 0 && !x3dom.caps.MOBILE) {
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ if (s_gl.imageGeometry == 1) {
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+ }
+ }
+
+ if (x3dom.Utils.needLineWidth) {
+ this.stateManager.lineWidth(1);
+ }
+
+ if (depthMode) {
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.depthMask(true);
+ this.stateManager.depthFunc(gl.LEQUAL);
+ this.stateManager.depthRange(0, 1);
+ }
+
+ gl.flush();
+
+ try {
+ // 4 = 1 * 1 * 4; then take width x height window (exception pickRect)
+ var data = new Uint8Array(4 * width * height);
+
+ gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
+
+ scene._webgl.fboPick.pixelData = data;
+ }
+ catch (se) {
+ scene._webgl.fboPick.pixelData = [];
+ // No Exception on file:// when starting with additional flags:
+ // chrome.exe --disable-web-security
+ x3dom.debug.logException(se + " (cannot pick)");
+ }
+
+ //gl.disable(gl.SCISSOR_TEST);
+
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, null);
+ };
+
+ /*****************************************************************************
+ * Render single Shape
+ *****************************************************************************/
+ Context.prototype.renderShape = function (drawable, viewarea, slights, numLights, mat_view, mat_scene,
+ mat_light, mat_proj, gl)
+ {
+ var shape = drawable.shape;
+ var transform = drawable.transform;
+
+ if (!shape || !shape._webgl || !transform) {
+ x3dom.debug.logError("[Context|RenderShape] No valid Shape!");
+ return;
+ }
+
+ var s_gl = shape._webgl;
+ var sp = s_gl.shader;
+
+ if (!sp) {
+ x3dom.debug.logError("[Context|RenderShape] No Shader is set!");
+ return;
+ }
+
+ var changed = this.stateManager.useProgram(sp);
+
+ //===========================================================================
+ // Set special Geometry variables
+ //===========================================================================
+ var s_app = shape._cf.appearance.node;
+ var s_geo = shape._cf.geometry.node;
+ var s_msh = s_geo._mesh;
+
+ var scene = viewarea._scene;
+ var tex = null;
+
+ if (s_gl.coordType != gl.FLOAT) {
+ if (!s_gl.popGeometry && (x3dom.Utils.isUnsignedType(s_geo._vf.coordType))) {
+ sp.bgCenter = s_geo.getMin().toGL();
+ }
+ else {
+ sp.bgCenter = s_geo._vf.position.toGL();
+ }
+ sp.bgSize = s_geo._vf.size.toGL();
+ sp.bgPrecisionMax = s_geo.getPrecisionMax('coordType');
+ }
+ else {
+ sp.bgCenter = [0, 0, 0];
+ sp.bgSize = [1, 1, 1];
+ sp.bgPrecisionMax = 1;
+ }
+ if (s_gl.colorType != gl.FLOAT) {
+ sp.bgPrecisionColMax = s_geo.getPrecisionMax('colorType');
+ }
+ else {
+ sp.bgPrecisionColMax = 1;
+ }
+ if (s_gl.texCoordType != gl.FLOAT) {
+ sp.bgPrecisionTexMax = s_geo.getPrecisionMax('texCoordType');
+ }
+ else {
+ sp.bgPrecisionTexMax = 1;
+ }
+ if (s_gl.normalType != gl.FLOAT) {
+ sp.bgPrecisionNorMax = s_geo.getPrecisionMax('normalType');
+ }
+ else {
+ sp.bgPrecisionNorMax = 1;
+ }
+
+ if (s_gl.imageGeometry != 0) {
+ sp.IG_bboxMin = s_geo.getMin().toGL();
+ sp.IG_bboxMax = s_geo.getMax().toGL();
+ sp.IG_implicitMeshSize = s_geo._vf.implicitMeshSize.toGL(); // FIXME
+
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "IG_coords0");
+ if (tex) {
+ sp.IG_coordTextureWidth = tex.texture.width;
+ sp.IG_coordTextureHeight = tex.texture.height;
+ }
+
+ if (s_gl.imageGeometry == 1) {
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "IG_index");
+ if (tex) {
+ sp.IG_indexTextureWidth = tex.texture.width;
+ sp.IG_indexTextureHeight = tex.texture.height;
+ }
+ }
+ tex = null;
+ }
+
+ //===========================================================================
+ // Set fog
+ //===========================================================================
+ // TODO: when no state/shader switch happens, all light/fog/... uniforms don't need to be set again
+ var fog = scene.getFog();
+
+ // THINKABOUTME: changed flag only works as long as lights and fog are global
+ if (fog && changed) {
+ sp.fogColor = fog._vf.color.toGL();
+ sp.fogRange = fog._vf.visibilityRange;
+ sp.fogType = (fog._vf.fogType == "LINEAR") ? 0.0 : 1.0;
+ }
+
+ //===========================================================================
+ // Set Material
+ //===========================================================================
+ var mat = s_app ? s_app._cf.material.node : null;
+ var shader = s_app ? s_app._shader : null;
+ var twoSidedMat = false;
+
+ var isUserDefinedShader = shader && x3dom.isa(shader, x3dom.nodeTypes.ComposedShader);
+
+ if (s_gl.csshader) {
+ sp.diffuseColor = shader._vf.diffuseFactor.toGL();
+ sp.specularColor = shader._vf.specularFactor.toGL();
+ sp.emissiveColor = shader._vf.emissiveFactor.toGL();
+ sp.shininess = shader._vf.shininessFactor;
+ sp.ambientIntensity = (shader._vf.ambientFactor.x +
+ shader._vf.ambientFactor.y +
+ shader._vf.ambientFactor.z) / 3;
+ sp.transparency = 1.0 - shader._vf.alphaFactor;
+
+ if (shader.getDisplacementMap()) {
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "displacementMap");
+ sp.displacementWidth = tex.texture.width;
+ sp.displacementHeight = tex.texture.height;
+ sp.displacementFactor = shader._vf.displacementFactor;
+ sp.displacementAxis = (shader._vf.displacementAxis == "x") ? 0.0 :
+ (shader._vf.displacementAxis == "y") ? 1.0 : 2.0;
+ }
+ else if (shader.getDiffuseDisplacementMap()) {
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "diffuseDisplacementMap");
+ sp.displacementWidth = tex.texture.width;
+ sp.displacementHeight = tex.texture.height;
+ sp.displacementFactor = shader._vf.displacementFactor;
+ sp.displacementAxis = (shader._vf.displacementAxis == "x") ? 0.0 :
+ (shader._vf.displacementAxis == "y") ? 1.0 : 2.0;
+ }
+ if (shader.getMultiDiffuseAlphaMap()) {
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "multiDiffuseAlphaMap");
+ sp.multiDiffuseAlphaWidth = tex.texture.width;
+ sp.multiDiffuseAlphaHeight = tex.texture.height;
+ }
+ if (shader.getMultiEmissiveAmbientMap()) {
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "multiEmissiveAmbientMap");
+ sp.multiEmissiveAmbientWidth = tex.texture.width;
+ sp.multiEmissiveAmbientHeight = tex.texture.height;
+ }
+ if (shader.getMultiSpecularShininessMap()) {
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "multiSpecularShininessMap");
+ sp.multiSpecularShininessWidth = tex.texture.width;
+ sp.multiSpecularShininessHeight = tex.texture.height;
+ }
+ if (shader.getMultiVisibilityMap()) {
+ tex = x3dom.Utils.findTextureByName(s_gl.texture, "multiVisibilityMap");
+ sp.multiVisibilityWidth = tex.texture.width;
+ sp.multiVisibilityHeight = tex.texture.height;
+ }
+ }
+ else if (mat) {
+ sp.diffuseColor = mat._vf.diffuseColor.toGL();
+ sp.specularColor = mat._vf.specularColor.toGL();
+ sp.emissiveColor = mat._vf.emissiveColor.toGL();
+ sp.shininess = mat._vf.shininess;
+ sp.ambientIntensity = mat._vf.ambientIntensity;
+ sp.transparency = mat._vf.transparency;
+ if (x3dom.isa(mat, x3dom.nodeTypes.TwoSidedMaterial)) {
+ twoSidedMat = true;
+ sp.backDiffuseColor = mat._vf.backDiffuseColor.toGL();
+ sp.backSpecularColor = mat._vf.backSpecularColor.toGL();
+ sp.backEmissiveColor = mat._vf.backEmissiveColor.toGL();
+ sp.backShininess = mat._vf.backShininess;
+ sp.backAmbientIntensity = mat._vf.backAmbientIntensity;
+ sp.backTransparency = mat._vf.backTransparency;
+ }
+ }
+ else {
+ sp.diffuseColor = [1.0, 1.0, 1.0];
+ sp.specularColor = [0.0, 0.0, 0.0];
+ sp.emissiveColor = [0.0, 0.0, 0.0];
+ sp.shininess = 0.0;
+ sp.ambientIntensity = 1.0;
+ sp.transparency = 0.0;
+ }
+
+ //Look for user-defined shaders
+ if (shader) {
+ if (isUserDefinedShader) {
+ for (var fName in shader._vf) {
+ if (shader._vf.hasOwnProperty(fName) && fName !== 'language') {
+ var field = shader._vf[fName];
+ if (field) {
+ if (field.toGL) {
+ sp[fName] = field.toGL();
+ }
+ else {
+ sp[fName] = field;
+ }
+ }
+ }
+ }
+ }
+ else if (x3dom.isa(shader, x3dom.nodeTypes.CommonSurfaceShader)) {
+ s_gl.csshader = shader;
+ }
+ }
+
+ //===========================================================================
+ // Set Lights
+ //===========================================================================
+ for (var p = 0; p < numLights && changed; p++) {
+ // FIXME; getCurrentTransform() doesn't work for shared lights/objects!
+ var light_transform = mat_view.mult(slights[p].getCurrentTransform());
+
+ if (x3dom.isa(slights[p], x3dom.nodeTypes.DirectionalLight)) {
+ sp['light' + p + '_Type'] = 0.0;
+ sp['light' + p + '_On'] = (slights[p]._vf.on) ? 1.0 : 0.0;
+ sp['light' + p + '_Color'] = slights[p]._vf.color.toGL();
+ sp['light' + p + '_Intensity'] = slights[p]._vf.intensity;
+ sp['light' + p + '_AmbientIntensity'] = slights[p]._vf.ambientIntensity;
+ sp['light' + p + '_Direction'] = light_transform.multMatrixVec(slights[p]._vf.direction).toGL();
+ sp['light' + p + '_Attenuation'] = [1.0, 1.0, 1.0];
+ sp['light' + p + '_Location'] = [1.0, 1.0, 1.0];
+ sp['light' + p + '_Radius'] = 0.0;
+ sp['light' + p + '_BeamWidth'] = 0.0;
+ sp['light' + p + '_CutOffAngle'] = 0.0;
+ sp['light' + p + '_ShadowIntensity'] = slights[p]._vf.shadowIntensity;
+ }
+ else if (x3dom.isa(slights[p], x3dom.nodeTypes.PointLight)) {
+ sp['light' + p + '_Type'] = 1.0;
+ sp['light' + p + '_On'] = (slights[p]._vf.on) ? 1.0 : 0.0;
+ sp['light' + p + '_Color'] = slights[p]._vf.color.toGL();
+ sp['light' + p + '_Intensity'] = slights[p]._vf.intensity;
+ sp['light' + p + '_AmbientIntensity'] = slights[p]._vf.ambientIntensity;
+ sp['light' + p + '_Direction'] = [1.0, 1.0, 1.0];
+ sp['light' + p + '_Attenuation'] = slights[p]._vf.attenuation.toGL();
+ sp['light' + p + '_Location'] = light_transform.multMatrixPnt(slights[p]._vf.location).toGL();
+ sp['light' + p + '_Radius'] = slights[p]._vf.radius;
+ sp['light' + p + '_BeamWidth'] = 0.0;
+ sp['light' + p + '_CutOffAngle'] = 0.0;
+ sp['light' + p + '_ShadowIntensity'] = slights[p]._vf.shadowIntensity;
+ }
+ else if (x3dom.isa(slights[p], x3dom.nodeTypes.SpotLight)) {
+ sp['light' + p + '_Type'] = 2.0;
+ sp['light' + p + '_On'] = (slights[p]._vf.on) ? 1.0 : 0.0;
+ sp['light' + p + '_Color'] = slights[p]._vf.color.toGL();
+ sp['light' + p + '_Intensity'] = slights[p]._vf.intensity;
+ sp['light' + p + '_AmbientIntensity'] = slights[p]._vf.ambientIntensity;
+ sp['light' + p + '_Direction'] = light_transform.multMatrixVec(slights[p]._vf.direction).toGL();
+ sp['light' + p + '_Attenuation'] = slights[p]._vf.attenuation.toGL();
+ sp['light' + p + '_Location'] = light_transform.multMatrixPnt(slights[p]._vf.location).toGL();
+ sp['light' + p + '_Radius'] = slights[p]._vf.radius;
+ sp['light' + p + '_BeamWidth'] = slights[p]._vf.beamWidth;
+ sp['light' + p + '_CutOffAngle'] = slights[p]._vf.cutOffAngle;
+ sp['light' + p + '_ShadowIntensity'] = slights[p]._vf.shadowIntensity;
+ }
+ }
+
+ //===========================================================================
+ // Set HeadLight
+ //===========================================================================
+ var nav = scene.getNavigationInfo();
+
+ if (nav._vf.headlight && changed) {
+ numLights = (numLights) ? numLights : 0;
+ sp['light' + numLights + '_Type'] = 0.0;
+ sp['light' + numLights + '_On'] = 1.0;
+ sp['light' + numLights + '_Color'] = [1.0, 1.0, 1.0];
+ sp['light' + numLights + '_Intensity'] = 1.0;
+ sp['light' + numLights + '_AmbientIntensity'] = 0.0;
+ sp['light' + numLights + '_Direction'] = [0.0, 0.0, -1.0];
+ sp['light' + numLights + '_Attenuation'] = [1.0, 1.0, 1.0];
+ sp['light' + numLights + '_Location'] = [1.0, 1.0, 1.0];
+ sp['light' + numLights + '_Radius'] = 0.0;
+ sp['light' + numLights + '_BeamWidth'] = 0.0;
+ sp['light' + numLights + '_CutOffAngle'] = 0.0;
+ sp['light' + numLights + '_ShadowIntensity'] = 0.0;
+ }
+
+ //===========================================================================
+ // Set ClipPlanes
+ //===========================================================================
+ if (shape._clipPlanes) {
+ for (var cp = 0; cp < shape._clipPlanes.length; cp++) {
+ var clip_plane = shape._clipPlanes[cp].plane;
+ var clip_trafo = shape._clipPlanes[cp].trafo;
+
+ sp['clipPlane' + cp + '_Plane'] = clip_trafo.multMatrixPlane(clip_plane._vf.plane).toGL();
+ sp['clipPlane' + cp + '_CappingStrength'] = clip_plane._vf.cappingStrength;
+ sp['clipPlane' + cp + '_CappingColor'] = clip_plane._vf.cappingColor.toGL();
+ }
+ }
+
+
+ //===========================================================================
+ // Set DepthMode
+ //===========================================================================
+ var depthMode = s_app ? s_app._cf.depthMode.node : null;
+ if (depthMode)
+ {
+ if (depthMode._vf.enableDepthTest)
+ {
+ //Enable Depth Test
+ this.stateManager.enable(gl.DEPTH_TEST);
+
+ //Set Depth Mask
+ this.stateManager.depthMask(!depthMode._vf.readOnly);
+
+ //Set Depth Function
+ this.stateManager.depthFunc(x3dom.Utils.depthFunc(gl, depthMode._vf.depthFunc));
+
+ //Set Depth Range
+ this.stateManager.depthRange(depthMode._vf.zNearRange, depthMode._vf.zFarRange);
+ }
+ else
+ {
+ //Disable Depth Test
+ this.stateManager.disable(gl.DEPTH_TEST);
+ }
+ }
+ else //Set Defaults
+ {
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.depthMask(true);
+ this.stateManager.depthFunc(gl.LEQUAL);
+ }
+
+ //===========================================================================
+ // Set BlendMode
+ //===========================================================================
+ var blendMode = s_app ? s_app._cf.blendMode.node : null;
+ if (blendMode)
+ {
+ var srcFactor = x3dom.Utils.blendFunc(gl, blendMode._vf.srcFactor);
+ var destFactor = x3dom.Utils.blendFunc(gl, blendMode._vf.destFactor);
+
+ if (srcFactor && destFactor)
+ {
+ //Enable Blending
+ this.stateManager.enable(gl.BLEND);
+
+ //Set Blend Function
+ this.stateManager.blendFuncSeparate(srcFactor, destFactor, gl.ONE, gl.ONE);
+
+ //Set Blend Color
+ this.stateManager.blendColor(blendMode._vf.color.r,
+ blendMode._vf.color.g,
+ blendMode._vf.color.b,
+ 1.0 - blendMode._vf.colorTransparency);
+
+ //Set Blend Equation
+ this.stateManager.blendEquation(x3dom.Utils.blendEquation(gl, blendMode._vf.equation));
+ }
+ else
+ {
+ this.stateManager.disable(gl.BLEND);
+ }
+ }
+ else //Set Defaults
+ {
+ this.stateManager.enable(gl.BLEND);
+ this.stateManager.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
+ }
+
+ //===========================================================================
+ // Set ColorMaskMode
+ //===========================================================================
+ var colorMaskMode = s_app ? s_app._cf.colorMaskMode.node : null;
+ if (colorMaskMode)
+ {
+ this.stateManager.colorMask(colorMaskMode._vf.maskR,
+ colorMaskMode._vf.maskG,
+ colorMaskMode._vf.maskB,
+ colorMaskMode._vf.maskA);
+ }
+ else //Set Defaults
+ {
+ this.stateManager.colorMask(true, true, true, true);
+ }
+
+ //===========================================================================
+ // Set LineProperties (only linewidthScaleFactor, interpreted as lineWidth)
+ //===========================================================================
+ var lineProperties = s_app ? s_app._cf.lineProperties.node : null;
+ if (lineProperties)
+ {
+ this.stateManager.lineWidth(lineProperties._vf.linewidthScaleFactor);
+ }
+ else if (x3dom.Utils.needLineWidth) //Set Defaults
+ {
+ this.stateManager.lineWidth(1);
+ }
+
+ if (shape.isSolid() && !twoSidedMat) {
+ this.stateManager.enable(gl.CULL_FACE);
+
+ if (shape.isCCW()) {
+ this.stateManager.frontFace(gl.CCW);
+ }
+ else {
+ this.stateManager.frontFace(gl.CW);
+ }
+ }
+ else {
+ this.stateManager.disable(gl.CULL_FACE);
+ }
+
+
+ // transformation matrices
+ var model_view = mat_view.mult(transform);
+ var model_view_inv = model_view.inverse();
+
+ sp.modelViewMatrix = model_view.toGL();
+ sp.viewMatrix = mat_view.toGL();
+
+ sp.normalMatrix = model_view_inv.transpose().toGL();
+ sp.modelViewMatrixInverse = model_view_inv.toGL();
+
+ sp.modelViewProjectionMatrix = mat_scene.mult(transform).toGL();
+
+ if (isUserDefinedShader || shape._clipPlanes && shape._clipPlanes.length)
+ {
+ sp.viewMatrixInverse = mat_view.inverse().toGL();
+ }
+
+ // only calculate on "request" (maybe of interest for users)
+ if (isUserDefinedShader) {
+ sp.projectionMatrix = mat_proj.toGL();
+
+ sp.worldMatrix = transform.toGL();
+ sp.worldInverseTranspose = transform.inverse().transpose().toGL();
+
+ }
+
+ //PopGeometry: adapt LOD and set shader variables
+ if (s_gl.popGeometry) {
+ this.updatePopState(drawable, s_geo, sp, s_gl, scene, model_view, viewarea, this.x3dElem.runtime.fps);
+ }
+
+ for (var cnt = 0, cnt_n = s_gl.texture.length; cnt < cnt_n; cnt++) {
+ tex = s_gl.texture[cnt];
+
+ gl.activeTexture(gl.TEXTURE0 + cnt);
+ gl.bindTexture(tex.type, tex.texture);
+ gl.texParameteri(tex.type, gl.TEXTURE_WRAP_S, tex.wrapS);
+ gl.texParameteri(tex.type, gl.TEXTURE_WRAP_T, tex.wrapT);
+ gl.texParameteri(tex.type, gl.TEXTURE_MAG_FILTER, tex.magFilter);
+ gl.texParameteri(tex.type, gl.TEXTURE_MIN_FILTER, tex.minFilter);
+
+ if (!shader || !isUserDefinedShader) {
+ if (!sp[tex.samplerName])
+ sp[tex.samplerName] = cnt;
+ }
+ }
+
+ if (s_app && s_app._cf.textureTransform.node) {
+ var texTrafo = s_app.texTransformMatrix();
+ sp.texTrafoMatrix = texTrafo.toGL();
+ }
+
+
+ // TODO; FIXME; what if geometry with split mesh has dynamic fields?
+ var attrib = null;
+ var df, df_n = s_gl.dynamicFields.length;
+
+ for (df = 0; df < df_n; df++) {
+ attrib = s_gl.dynamicFields[df];
+
+ if (sp[attrib.name] !== undefined) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, attrib.buf);
+
+ gl.vertexAttribPointer(sp[attrib.name], attrib.numComponents, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp[attrib.name]);
+ }
+ }
+
+ // render object
+ var v, v_n, offset, q_n;
+ var isParticleSet = false;
+
+ if (x3dom.isa(s_geo, x3dom.nodeTypes.ParticleSet)) {
+ isParticleSet = true;
+ }
+
+ if (s_gl.externalGeometry != 0)
+ {
+ q_n = s_gl.primType.length;
+ }
+ else
+ {
+ q_n = s_gl.positions.length;
+ }
+
+ for (var q = 0; q < q_n; q++) {
+ var q6 = 6 * q;
+
+ if ( !(sp.position !== undefined && s_gl.buffers[q6 + 1] && (s_gl.indexes[q] || s_gl.externalGeometry != 0)) )
+ continue;
+
+ if (s_gl.buffers[q6]) {
+ if (isParticleSet && s_geo.drawOrder() != "any") { // sort
+ var indexArray, zPos = [];
+ var pnts = s_geo._cf.coord.node.getPoints();
+ var pn = (pnts.length == s_gl.indexes[q].length) ? s_gl.indexes[q].length : 0;
+
+ for (var i=0; i<pn; i++) {
+ var center = model_view.multMatrixPnt(pnts[i]);
+ zPos.push([i, center.z]);
+ }
+
+ if (s_geo.drawOrder() == "backtofront")
+ zPos.sort(function(a, b) { return a[1] - b[1]; });
+ else
+ zPos.sort(function(b, a) { return a[1] - b[1]; });
+
+ for (i=0; i<pn; i++) {
+ shape._webgl.indexes[q][i] = zPos[i][0];
+ }
+
+ if (x3dom.caps.INDEX_UINT && (pn > 65535)) {
+ indexArray = new Uint32Array(shape._webgl.indexes[q]);
+ shape._webgl.indexType = gl.UNSIGNED_INT;
+ }
+ else {
+ indexArray = new Uint16Array(shape._webgl.indexes[q]);
+ shape._webgl.indexType = gl.UNSIGNED_SHORT;
+ }
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, s_gl.buffers[q6]);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexArray, gl.DYNAMIC_DRAW);
+
+ indexArray = null;
+ }
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, s_gl.buffers[q6]);
+ }
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 1]);
+
+ gl.vertexAttribPointer(sp.position,
+ s_msh._numPosComponents, s_gl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ if (sp.normal !== undefined && s_gl.buffers[q6 + 2]) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 2]);
+
+ gl.vertexAttribPointer(sp.normal,
+ s_msh._numNormComponents, s_gl.normalType, false,
+ shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.normal);
+ }
+ if (sp.texcoord !== undefined && s_gl.buffers[q6 + 3]) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 3]);
+
+ gl.vertexAttribPointer(sp.texcoord,
+ s_msh._numTexComponents, s_gl.texCoordType, false,
+ shape._texCoordStrideOffset[0], shape._texCoordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.texcoord);
+ }
+ if (sp.color !== undefined && s_gl.buffers[q6 + 4]) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 4]);
+
+ gl.vertexAttribPointer(sp.color,
+ s_msh._numColComponents, s_gl.colorType, false,
+ shape._colorStrideOffset[0], shape._colorStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.color);
+ }
+ if ((sp.id !== undefined || sp.particleSize !== undefined) && s_gl.buffers[q6 + 5]) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 5]);
+
+ //texture coordinate hack for IDs
+ if (s_gl.binaryGeometry != 0 && s_geo._vf.idsPerVertex == true)
+ {
+ gl.vertexAttribPointer(sp.id,
+ 1, gl.FLOAT, false, 4, 0);
+ gl.enableVertexAttribArray(sp.id);
+ }
+ else if (isParticleSet)
+ {
+ gl.vertexAttribPointer(sp.particleSize,
+ 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.particleSize);
+ }
+ }
+ if (s_gl.popGeometry != 0 && s_gl.buffers[q6 + 5]) {
+ //special case: mimic gl_VertexID
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 5]);
+
+ gl.vertexAttribPointer(sp.PG_vertexID, 1, gl.FLOAT, false, 4, 0);
+ gl.enableVertexAttribArray(sp.PG_vertexID);
+ }
+
+ // TODO: implement surface with additional wireframe render mode (independent from poly mode)
+ var indOff, renderMode = viewarea.getRenderMode();
+
+ if (renderMode > 0) {
+ var polyMode = (renderMode == 1) ? gl.POINTS : gl.LINES;
+
+ if (s_gl.binaryGeometry > 0 || s_gl.popGeometry > 0) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawElements(polyMode, s_geo._vf.vertexCount[v], s_gl.indexType,
+ x3dom.Utils.getByteAwareOffset(offset, s_gl.indexType, gl));
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ else if (s_gl.binaryGeometry < 0 || s_gl.popGeometry < 0 || s_gl.imageGeometry) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawArrays(polyMode, offset, s_geo._vf.vertexCount[v]);
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ //ExternalGeometry: indexed rendering (standard pass, POINTS or LINES)
+ else if (s_gl.externalGeometry == 1)
+ {
+ gl.drawElements(polyMode, s_gl.drawCount[q], s_gl.indexType, s_gl.indexOffset[q]);
+ }
+ //ExternalGeometry: non-indexed rendering (standard pass, POINTS or LINES)
+ else if (s_gl.externalGeometry == -1)
+ {
+ gl.drawArrays(polyMode, 0, s_gl.drawCount[q]);
+ }
+ else if (s_geo.hasIndexOffset()) {
+ // IndexedTriangleStripSet with primType TRIANGLE_STRIP,
+ // and Patch geometry from external BVHRefiner component
+ indOff = shape.tessellationProperties();
+ for (v = 0, v_n = indOff.length; v < v_n; v++) {
+ gl.drawElements(polyMode, indOff[v].count, s_gl.indexType,
+ indOff[v].offset * x3dom.Utils.getOffsetMultiplier(s_gl.indexType, gl));
+ }
+ }
+ else if (s_gl.indexes[q].length == 0) {
+ gl.drawArrays(polyMode, 0, s_gl.positions[q].length / 3);
+ }
+ else {
+ gl.drawElements(polyMode, s_gl.indexes[q].length, s_gl.indexType, 0);
+ }
+ }
+ else {
+ if (s_gl.binaryGeometry > 0 || s_gl.popGeometry > 0) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType[v], s_geo._vf.vertexCount[v], s_gl.indexType,
+ x3dom.Utils.getByteAwareOffset(offset, s_gl.indexType, gl));
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ else if (s_gl.binaryGeometry < 0 || s_gl.popGeometry < 0 || s_gl.imageGeometry) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawArrays(s_gl.primType[v], offset, s_geo._vf.vertexCount[v]);
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ //ExternalGeometry: indexed rendering (standard pass)
+ else if (s_gl.externalGeometry == 1)
+ {
+ gl.drawElements(s_gl.primType[q], s_gl.drawCount[q], s_gl.indexType, s_gl.indexOffset[q]);
+ }
+ //ExternalGeometry: non-indexed rendering (standard pass)
+ else if (s_gl.externalGeometry == -1)
+ {
+ gl.drawArrays(s_gl.primType[q], 0, s_gl.drawCount[q]);
+ }
+ else if (s_geo.hasIndexOffset()) {
+ // IndexedTriangleStripSet with primType TRIANGLE_STRIP,
+ // and Patch geometry from external BVHRefiner component
+ indOff = shape.tessellationProperties();
+ for (v = 0, v_n = indOff.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType, indOff[v].count, s_gl.indexType,
+ indOff[v].offset * x3dom.Utils.getOffsetMultiplier(s_gl.indexType, gl));
+ }
+ }
+ else if (s_gl.indexes[q].length == 0) {
+ gl.drawArrays(s_gl.primType, 0, s_gl.positions[q].length / 3);
+ }
+ else {
+ gl.drawElements(s_gl.primType, s_gl.indexes[q].length, s_gl.indexType, 0);
+ }
+ }
+
+ // disable all used vertex attributes
+ gl.disableVertexAttribArray(sp.position);
+
+ if (sp.normal !== undefined) {
+ gl.disableVertexAttribArray(sp.normal);
+ }
+ if (sp.texcoord !== undefined) {
+ gl.disableVertexAttribArray(sp.texcoord);
+ }
+ if (sp.color !== undefined) {
+ gl.disableVertexAttribArray(sp.color);
+ }
+ if (s_gl.buffers[q6 + 5]) {
+ if (sp.id !== undefined)
+ gl.disableVertexAttribArray(sp.id);
+ else if (sp.particleSize !== undefined)
+ gl.disableVertexAttribArray(sp.particleSize);
+ }
+ if (s_gl.popGeometry != 0 && sp.PG_vertexID !== undefined) {
+ gl.disableVertexAttribArray(sp.PG_vertexID); // mimic gl_VertexID
+ }
+ } // end for loop over attrib arrays
+
+ for (df = 0; df < df_n; df++) {
+ attrib = s_gl.dynamicFields[df];
+
+ if (sp[attrib.name] !== undefined) {
+ gl.disableVertexAttribArray(sp[attrib.name]);
+ }
+ }
+
+ // update stats
+ if (s_gl.imageGeometry) {
+ v_n = s_geo._vf.vertexCount.length;
+ this.numDrawCalls += v_n;
+
+ for (v = 0; v < v_n; v++) {
+ if (s_gl.primType[v] == gl.TRIANGLE_STRIP)
+ this.numFaces += (s_geo._vf.vertexCount[v] - 2);
+ else
+ this.numFaces += (s_geo._vf.vertexCount[v] / 3);
+
+ this.numCoords += s_geo._vf.vertexCount[v];
+ }
+ }
+ else {
+ this.numCoords += s_msh._numCoords;
+ this.numFaces += s_msh._numFaces;
+
+ if (s_gl.binaryGeometry || s_gl.popGeometry) {
+ this.numDrawCalls += s_geo._vf.vertexCount.length;
+ }
+ else if (s_geo.hasIndexOffset()) {
+ this.numDrawCalls += shape.tessellationProperties().length;
+ }
+ else {
+ this.numDrawCalls += q_n;
+ }
+ }
+
+ // reset to default values for possibly user defined render states
+ if (depthMode) {
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.depthMask(true);
+ this.stateManager.depthFunc(gl.LEQUAL);
+ this.stateManager.depthRange(0, 1);
+ }
+
+ if (blendMode) {
+ this.stateManager.enable(gl.BLEND);
+ this.stateManager.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
+ this.stateManager.blendColor(1, 1, 1, 1);
+ this.stateManager.blendEquation(gl.FUNC_ADD);
+ }
+
+ if (colorMaskMode) {
+ this.stateManager.colorMask(true, true, true, true);
+ }
+
+ if (lineProperties) {
+ this.stateManager.lineWidth(1);
+ }
+
+ // cleanup textures
+ var s_gl_tex = s_gl.texture;
+ cnt_n = s_gl_tex ? s_gl_tex.length : 0;
+
+ for (cnt = 0; cnt < cnt_n; cnt++) {
+ if (!s_gl_tex[cnt])
+ continue;
+
+ if (s_app && s_app._cf.texture.node) {
+ tex = s_app._cf.texture.node.getTexture(cnt);
+ gl.activeTexture(gl.TEXTURE0 + cnt);
+
+ if (x3dom.isa(tex, x3dom.nodeTypes.X3DEnvironmentTextureNode)) {
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+ }
+ else {
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+ }
+ }
+ };
+
+ /*****************************************************************************
+ * PopGeometry: adapt LOD and set shader variables
+ *****************************************************************************/
+ Context.prototype.updatePopState = function (drawable, popGeo, sp, s_gl, scene, model_view, viewarea, currFps)
+ {
+ var tol = x3dom.nodeTypes.PopGeometry.ErrorToleranceFactor * popGeo._vf.precisionFactor;
+
+ if (currFps <= 1 || viewarea.isMovingOrAnimating()) {
+ tol *= x3dom.nodeTypes.PopGeometry.PrecisionFactorOnMove;
+ }
+
+ var currentLOD = 16;
+
+ if (tol > 0) {
+
+ //BEGIN CLASSIC CODE
+ var viewpoint = scene.getViewpoint();
+ var imgPlaneHeightAtDistOne = viewpoint.getImgPlaneHeightAtDistOne();
+ var near = viewpoint.getNear();
+ var center = model_view.multMatrixPnt(popGeo._vf.position);
+
+ var tightRad = model_view.multMatrixVec(popGeo._vf.size).length() * 0.5;
+ var largestRad = model_view.multMatrixVec(popGeo._vf.maxBBSize).length() * 0.5;
+
+ //distance is estimated conservatively using the bounding sphere
+ var dist = Math.max(-center.z - tightRad, near);
+ var projPixelLength = dist * (imgPlaneHeightAtDistOne / viewarea._height);
+
+ //compute LOD using bounding sphere
+ var arg = (2 * largestRad) / (tol * projPixelLength);
+ //END CLASSIC CODE
+
+ //BEGIN EXPERIMENTAL CODE
+ //compute LOD using screen-space coverage of bounding sphere
+ //@todo: the coverage should be distinct from priority
+ //var cov = drawable.priority;
+ //@todo: here, we need to decide whether we want to keep the ModF-encoding with
+ // respect to the largest bounding box... if not, change this and the shaders
+ //cov *= (popGeo._vf.maxBBSize.length() / popGeo._vf.size.length());
+ //var arg = cov / tol;
+ //END EXPERIMENTAL CODE
+
+ // use precomputed log(2.0) = 0.693147180559945
+ currentLOD = Math.ceil(Math.log(arg) / 0.693147180559945);
+ currentLOD = (currentLOD < 1) ? 1 : ((currentLOD > 16) ? 16 : currentLOD);
+ }
+
+ //take care of user-controlled min and max values
+ var minPrec = popGeo._vf.minPrecisionLevel, maxPrec = popGeo._vf.maxPrecisionLevel;
+
+ currentLOD = (minPrec != -1 && currentLOD < minPrec) ? minPrec : currentLOD;
+ currentLOD = (maxPrec != -1 && currentLOD > maxPrec) ? maxPrec : currentLOD;
+
+ //assign rendering resolution, according to currently loaded data and LOD
+ var currentLOD_min = (s_gl.levelsAvailable < currentLOD) ? s_gl.levelsAvailable : currentLOD;
+ currentLOD = currentLOD_min;
+
+ //@todo: only for demonstration purposes!!!
+ if (tol <= 1)
+ currentLOD = (currentLOD == popGeo.getNumLevels()) ? 16 : currentLOD;
+
+ //here, we tell X3DOM how many faces / vertices get displayed in the stats
+ var hasIndex = popGeo._vf.indexedRendering;
+ var p_msh = popGeo._mesh;
+
+ p_msh._numCoords = 0;
+ p_msh._numFaces = 0;
+
+ //@todo: this assumes pure TRIANGLES data (and gets overwritten from shadow/picking pass!!!)
+ for (var i = 0; i < currentLOD_min; ++i) { // currentLOD breaks loop
+ var numVerticesAtLevel_i = s_gl.numVerticesAtLevel[i];
+ p_msh._numCoords += numVerticesAtLevel_i;
+ p_msh._numFaces += (hasIndex ? popGeo.getNumIndicesByLevel(i) : numVerticesAtLevel_i) / 3;
+ }
+
+ x3dom.nodeTypes.PopGeometry.numRenderedVerts += p_msh._numCoords;
+ x3dom.nodeTypes.PopGeometry.numRenderedTris += p_msh._numFaces;
+
+ //this field is mainly thought for the use with external statistics
+ //@todo: does not work with instances
+ p_msh.currentLOD = currentLOD;
+
+ //here, we tell X3DOM how many vertices get rendered
+ //@todo: this assumes pure TRIANGLES data
+ popGeo.adaptVertexCount(hasIndex ? p_msh._numFaces * 3 : p_msh._numCoords);
+
+ // finally set shader variables...
+ sp.PG_maxBBSize = popGeo._vf.maxBBSize.toGL();
+
+ sp.PG_bbMin = popGeo._bbMinBySize; // floor(bbMin / maxBBSize)
+
+ sp.PG_numAnchorVertices = popGeo._vf.numAnchorVertices;
+
+ sp.PG_bbMaxModF = popGeo._vf.bbMaxModF.toGL();
+ sp.PG_bboxShiftVec = popGeo._vf.bbShiftVec.toGL();
+
+ sp.PG_precisionLevel = currentLOD;
+
+ //mimics Math.pow(2.0, 16.0 - currentLOD);
+ sp.PG_powPrecision = x3dom.nodeTypes.PopGeometry.powLUT[currentLOD - 1];
+ };
+
+
+ /*****************************************************************************
+ * Render ColorBuffer-Pass for picking
+ *****************************************************************************/
+ Context.prototype.pickValue = function (viewarea, x, y, buttonState, viewMat, sceneMat)
+ {
+ x3dom.Utils.startMeasure("picking");
+
+ var scene = viewarea._scene;
+
+ var gl = this.ctx3d;
+
+ // method requires that scene has already been rendered at least once
+ if (!gl || !scene || !scene._webgl || !scene.drawableCollection) {
+ return false;
+ }
+
+ var pm = scene._vf.pickMode.toLowerCase();
+ var pickMode = 0;
+
+ switch (pm) {
+ case "box": return false;
+ case "idbuf": pickMode = 0; break;
+ case "idbuf24": pickMode = 3; break;
+ case "idbufid": pickMode = 4; break;
+ case "color": pickMode = 1; break;
+ case "texcoord": pickMode = 2; break;
+ }
+
+
+ // ViewMatrix and ViewProjectionMatrix
+ var mat_view, mat_scene;
+
+ if (arguments.length > 4) {
+ mat_view = viewMat;
+ mat_scene = sceneMat;
+ }
+ else {
+ mat_view = viewarea._last_mat_view;
+ mat_scene = viewarea._last_mat_scene;
+ }
+
+ // remember correct scene bbox
+ var min = x3dom.fields.SFVec3f.copy(scene._lastMin);
+ var max = x3dom.fields.SFVec3f.copy(scene._lastMax);
+ // get current camera position
+ var from = mat_view.inverse().e3();
+
+ // get bbox of scene bbox and camera position
+ var _min = x3dom.fields.SFVec3f.copy(from);
+ var _max = x3dom.fields.SFVec3f.copy(from);
+
+ if (_min.x > min.x) { _min.x = min.x; }
+ if (_min.y > min.y) { _min.y = min.y; }
+ if (_min.z > min.z) { _min.z = min.z; }
+
+ if (_max.x < max.x) { _max.x = max.x; }
+ if (_max.y < max.y) { _max.y = max.y; }
+ if (_max.z < max.z) { _max.z = max.z; }
+
+ // temporarily set scene size to include camera
+ scene._lastMin.setValues(_min);
+ scene._lastMax.setValues(_max);
+
+ // get scalar scene size and adapted projection matrix
+ var sceneSize = scene._lastMax.subtract(scene._lastMin).length();
+ var cctowc = viewarea.getCCtoWCMatrix();
+
+ // restore correct scene bbox
+ scene._lastMin.setValues(min);
+ scene._lastMax.setValues(max);
+
+ // for deriving shadow ids together with shape ids
+ var baseID = x3dom.nodeTypes.Shape.objectID + 2;
+
+
+ // render to texture for reading pixel values
+ this.renderPickingPass(gl, scene, mat_view, mat_scene, from, sceneSize, pickMode, x, y, 2, 2);
+
+ // the pixel values under mouse cursor
+ var pixelData = scene._webgl.fboPick.pixelData;
+
+ if (pixelData && pixelData.length)
+ {
+ var pickPos = new x3dom.fields.SFVec3f(0, 0, 0);
+ var pickNorm = new x3dom.fields.SFVec3f(0, 0, 1);
+
+ var index = 0;
+ var objId = pixelData[index + 3], shapeId;
+
+ var pixelOffset = 1.0 / scene._webgl.pickScale;
+ var denom = 1.0 / 256.0;
+ var dist, line, lineoff, right, up;
+
+ if (pickMode == 0) {
+ objId += 256 * pixelData[index + 2];
+
+ dist = (pixelData[index ] / 255.0) * denom +
+ (pixelData[index + 1] / 255.0);
+
+ line = viewarea.calcViewRay(x, y, cctowc);
+
+ pickPos = line.pos.add(line.dir.multiply(dist * sceneSize));
+
+ index = 4; // get right pixel
+ dist = (pixelData[index ] / 255.0) * denom +
+ (pixelData[index + 1] / 255.0);
+
+ lineoff = viewarea.calcViewRay(x + pixelOffset, y, cctowc);
+
+ right = lineoff.pos.add(lineoff.dir.multiply(dist * sceneSize));
+ right = right.subtract(pickPos).normalize();
+
+ index = 8; // get top pixel
+ dist = (pixelData[index ] / 255.0) * denom +
+ (pixelData[index + 1] / 255.0);
+
+ lineoff = viewarea.calcViewRay(x, y - pixelOffset, cctowc);
+
+ up = lineoff.pos.add(lineoff.dir.multiply(dist * sceneSize));
+ up = up.subtract(pickPos).normalize();
+
+ pickNorm = right.cross(up).normalize();
+ }
+ else if (pickMode == 3) {
+ objId += 256 * pixelData[index + 2] +
+ 65536 * pixelData[index + 1];
+
+ dist = pixelData[index] / 255.0;
+
+ line = viewarea.calcViewRay(x, y, cctowc);
+
+ pickPos = line.pos.add(line.dir.multiply(dist * sceneSize));
+
+ index = 4; // get right pixel
+ dist = pixelData[index] / 255.0;
+
+ lineoff = viewarea.calcViewRay(x + pixelOffset, y, cctowc);
+
+ right = lineoff.pos.add(lineoff.dir.multiply(dist * sceneSize));
+ right = right.subtract(pickPos).normalize();
+
+ index = 8; // get top pixel
+ dist = pixelData[index] / 255.0;
+
+ lineoff = viewarea.calcViewRay(x, y - pixelOffset, cctowc);
+
+ up = lineoff.pos.add(lineoff.dir.multiply(dist * sceneSize));
+ up = up.subtract(pickPos).normalize();
+
+ pickNorm = right.cross(up).normalize();
+ }
+ else if (pickMode == 4) {
+ objId += 256 * pixelData[index + 2];
+
+ shapeId = pixelData[index + 1];
+ shapeId += 256 * pixelData[index ];
+
+ // check if standard shape picked without special shadow id
+ if (objId == 0 && (shapeId > 0 && shapeId < baseID)) {
+ objId = shapeId;
+ }
+ }
+ else {
+ pickPos.x = pixelData[index ];
+ pickPos.y = pixelData[index + 1];
+ pickPos.z = pixelData[index + 2];
+ }
+ //x3dom.debug.logInfo(pickPos + " / " + objId);
+
+ var eventType = "shadowObjectIdChanged";
+ var shadowObjectIdChanged, event;
+ var button = Math.max(buttonState >>> 8, buttonState & 255);
+
+ if (objId >= baseID) {
+ objId -= baseID;
+
+ var hitObject;
+
+ if (pickMode != 4) {
+ viewarea._pickingInfo.pickPos = pickPos;
+ viewarea._pick.setValues(pickPos);
+
+ viewarea._pickingInfo.pickNorm = pickNorm;
+ viewarea._pickNorm.setValues(pickNorm);
+
+ viewarea._pickingInfo.pickObj = null;
+ viewarea._pickingInfo.lastClickObj = null;
+
+ hitObject = scene._xmlNode;
+ }
+ else {
+ viewarea._pickingInfo.pickObj = x3dom.nodeTypes.Shape.idMap.nodeID[shapeId];
+
+ hitObject = viewarea._pickingInfo.pickObj._xmlNode;
+ }
+
+
+ //Check if there are MultiParts
+ if (scene._multiPartMap) {
+ var mp, multiPart;
+
+ //Find related MultiPart
+ for (mp=0; mp<scene._multiPartMap.multiParts.length; mp++)
+ {
+ multiPart = scene._multiPartMap.multiParts[mp];
+ if (objId >= multiPart._minId && objId <= multiPart._maxId)
+ {
+ hitObject = multiPart._xmlNode;
+
+ event = {
+ target: multiPart._xmlNode,
+ button: button, mouseup: ((buttonState >>> 8) > 0),
+ layerX: x, layerY: y,
+ pickedId: objId,
+ worldX: pickPos.x, worldY: pickPos.y, worldZ: pickPos.z,
+ normalX: pickNorm.x, normalY: pickNorm.y, normalZ: pickNorm.z,
+ hitPnt: pickPos.toGL(),
+ hitObject: hitObject,
+ cancelBubble: false,
+ stopPropagation: function () { this.cancelBubble = true; },
+ preventDefault: function () { this.cancelBubble = true; }
+ };
+
+ multiPart.handleEvents(event);
+ }
+ else
+ {
+ event = {
+ target: multiPart._xmlNode,
+ button: button, mouseup: ((buttonState >>> 8) > 0),
+ layerX: x, layerY: y,
+ pickedId: -1,
+ cancelBubble: false,
+ stopPropagation: function () { this.cancelBubble = true; },
+ preventDefault: function () { this.cancelBubble = true; }
+ };
+
+ multiPart.handleEvents(event);
+ }
+ }
+ }
+
+ shadowObjectIdChanged = (viewarea._pickingInfo.shadowObjectId != objId);
+ viewarea._pickingInfo.lastShadowObjectId = viewarea._pickingInfo.shadowObjectId;
+ viewarea._pickingInfo.shadowObjectId = objId;
+ //x3dom.debug.logInfo(baseID + " + " + objId);
+
+ if ((shadowObjectIdChanged || button) && scene._xmlNode &&
+ (scene._xmlNode["on" + eventType] || scene._xmlNode.hasAttribute("on" + eventType) ||
+ scene._listeners[eventType]))
+ {
+ event = {
+ target: scene._xmlNode,
+ type: eventType,
+ button: button, mouseup: ((buttonState >>> 8) > 0),
+ layerX: x, layerY: y,
+ shadowObjectId: objId,
+ worldX: pickPos.x, worldY: pickPos.y, worldZ: pickPos.z,
+ normalX: pickNorm.x, normalY: pickNorm.y, normalZ: pickNorm.z,
+ hitPnt: pickPos.toGL(),
+ hitObject: hitObject,
+ cancelBubble: false,
+ stopPropagation: function () { this.cancelBubble = true; },
+ preventDefault: function () { this.cancelBubble = true; }
+ };
+ scene.callEvtHandler(("on" + eventType), event);
+ }
+
+ if (scene._shadowIdMap && scene._shadowIdMap.mapping &&
+ objId < scene._shadowIdMap.mapping.length) {
+ var shIds = scene._shadowIdMap.mapping[objId].usage;
+ var n, c, shObj;
+
+ if (!line) {
+ line = viewarea.calcViewRay(x, y, cctowc);
+ }
+ // find corresponding dom tree object
+ for (c = 0; c < shIds.length; c++) {
+ shObj = scene._nameSpace.defMap[shIds[c]];
+ // FIXME; bbox test too coarse (+ should include trafo)
+ if (shObj && shObj.doIntersect(line)) {
+ viewarea._pickingInfo.pickObj = shObj;
+ break;
+ }
+ }
+ //Check for other namespaces e.g. Inline/Multipart (FIXME; check recursively)
+ for (n = 0; n<scene._nameSpace.childSpaces.length; n++)
+ {
+ for (c = 0; c < shIds.length; c++) {
+ shObj = scene._nameSpace.childSpaces[n].defMap[shIds[c]];
+ // FIXME; bbox test too coarse (+ should include trafo)
+ if (shObj && shObj.doIntersect(line)) {
+ viewarea._pickingInfo.pickObj = shObj;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ //Check if there are MultiParts
+ if (scene._multiPartMap) {
+
+ //Find related MultiPart
+ for (mp=0; mp<scene._multiPartMap.multiParts.length; mp++)
+ {
+ multiPart = scene._multiPartMap.multiParts[mp];
+
+ event = {
+ target: multiPart._xmlNode,
+ button: button, mouseup: ((buttonState >>> 8) > 0),
+ layerX: x, layerY: y,
+ pickedId: -1,
+ cancelBubble: false,
+ stopPropagation: function () { this.cancelBubble = true; },
+ preventDefault: function () { this.cancelBubble = true; }
+ };
+
+ multiPart.handleEvents(event);
+ }
+ }
+
+
+ shadowObjectIdChanged = (viewarea._pickingInfo.shadowObjectId != -1);
+ viewarea._pickingInfo.shadowObjectId = -1; // nothing hit
+
+ if ( shadowObjectIdChanged && scene._xmlNode &&
+ (scene._xmlNode["on" + eventType] || scene._xmlNode.hasAttribute("on" + eventType) ||
+ scene._listeners[eventType]) )
+ {
+ event = {
+ target: scene._xmlNode,
+ type: eventType,
+ button: button, mouseup: ((buttonState >>> 8) > 0),
+ layerX: x, layerY: y,
+ shadowObjectId: viewarea._pickingInfo.shadowObjectId,
+ cancelBubble: false,
+ stopPropagation: function () { this.cancelBubble = true; },
+ preventDefault: function () { this.cancelBubble = true; }
+ };
+ scene.callEvtHandler(("on" + eventType), event);
+ }
+
+ if (objId > 0) {
+ //x3dom.debug.logInfo(x3dom.nodeTypes.Shape.idMap.nodeID[objId]._DEF + " // " +
+ // x3dom.nodeTypes.Shape.idMap.nodeID[objId]._xmlNode.localName);
+ viewarea._pickingInfo.pickPos = pickPos;
+ viewarea._pickingInfo.pickNorm = pickNorm;
+ viewarea._pickingInfo.pickObj = x3dom.nodeTypes.Shape.idMap.nodeID[objId];
+ }
+ else {
+ viewarea._pickingInfo.pickObj = null;
+ //viewarea._pickingInfo.lastObj = null;
+ viewarea._pickingInfo.lastClickObj = null;
+ }
+ }
+ }
+ var pickTime = x3dom.Utils.stopMeasure("picking");
+ this.x3dElem.runtime.addMeasurement('PICKING', pickTime);
+
+ return true;
+ };
+
+ /*****************************************************************************
+ * Render ColorBuffer-Pass for picking sub window
+ *****************************************************************************/
+ Context.prototype.pickRect = function (viewarea, x1, y1, x2, y2)
+ {
+ var gl = this.ctx3d;
+ var scene = viewarea ? viewarea._scene : null;
+
+ // method requires that scene has already been rendered at least once
+ if (!gl || !scene || !scene._webgl || !scene.drawableCollection)
+ return false;
+
+ // values not fully correct but unnecessary anyway, just to feed the shader
+ var from = viewarea._last_mat_view.inverse().e3();
+ var sceneSize = scene._lastMax.subtract(scene._lastMin).length();
+
+ var x = (x1 <= x2) ? x1 : x2;
+ var y = (y1 >= y2) ? y1 : y2;
+ var width = (1 + Math.abs(x2 - x1)) * scene._webgl.pickScale;
+ var height = (1 + Math.abs(y2 - y1)) * scene._webgl.pickScale;
+
+ // render to texture for reading pixel values
+ this.renderPickingPass(gl, scene, viewarea._last_mat_view, viewarea._last_mat_scene,
+ from, sceneSize, 0, x, y, (width < 1) ? 1 : width, (height < 1) ? 1 : height);
+
+ var index;
+ var pickedObjects = [];
+
+ // get objects in rectangle
+ for (index = 0; scene._webgl.fboPick.pixelData &&
+ index < scene._webgl.fboPick.pixelData.length; index += 4) {
+ var objId = scene._webgl.fboPick.pixelData[index + 3] +
+ scene._webgl.fboPick.pixelData[index + 2] * 256;
+
+ if (objId > 0)
+ pickedObjects.push(objId);
+ }
+ pickedObjects.sort();
+
+ // make found object IDs unique
+ var pickedObjectsTemp = (function (arr) {
+ var a = [], l = arr.length;
+ for (var i = 0; i < l; i++) {
+ for (var j = i + 1; j < l; j++) {
+ if (arr[i] === arr[j])
+ j = ++i;
+ }
+ a.push(arr[i]);
+ }
+ return a;
+ })(pickedObjects);
+ pickedObjects = pickedObjectsTemp;
+
+ var pickedNodes = [];
+
+ var hitObject;
+
+ // for deriving shadow ids together with shape ids
+ var baseID = x3dom.nodeTypes.Shape.objectID + 2;
+
+ for (index = 0; index < pickedObjects.length; index++) {
+ objId = pickedObjects[index];
+
+ if (objId >= baseID)
+ {
+ objId -= baseID;
+
+ //Check if there are MultiParts
+ if (scene._multiPartMap) {
+ var mp, multiPart, colorMap, emissiveMap, specularMap, visibilityMap;
+
+ //Find related MultiPart
+ for (mp = 0; mp < scene._multiPartMap.multiParts.length; mp++) {
+ multiPart = scene._multiPartMap.multiParts[mp];
+ colorMap = multiPart._inlineNamespace.defMap["MultiMaterial_ColorMap"];
+ emissiveMap = multiPart._inlineNamespace.defMap["MultiMaterial_EmissiveMap"];
+ specularMap = multiPart._inlineNamespace.defMap["MultiMaterial_SpecularMap"];
+ visibilityMap = multiPart._inlineNamespace.defMap["MultiMaterial_VisibilityMap"];
+ if (objId >= multiPart._minId && objId <= multiPart._maxId) {
+ hitObject = new x3dom.Parts(multiPart, [objId], colorMap, emissiveMap, specularMap, visibilityMap);
+ pickedNodes.push(hitObject);
+ }
+ }
+ }
+
+ }
+ else
+ {
+ hitObject = x3dom.nodeTypes.Shape.idMap.nodeID[objId];
+ hitObject = (hitObject && hitObject._xmlNode) ? hitObject._xmlNode : null;
+
+ if (hitObject)
+ pickedNodes.push(hitObject);
+ }
+ }
+
+ return pickedNodes;
+ };
+
+ /*****************************************************************************
+ * Render Scene (Main-Pass)
+ *****************************************************************************/
+ Context.prototype.renderScene = function (viewarea)
+ {
+ var gl = this.ctx3d;
+ var scene = viewarea._scene;
+
+ if (gl === null || scene === null) {
+ return;
+ }
+
+ var rentex = viewarea._doc._nodeBag.renderTextures;
+ var rt_tex, rtl_i, rtl_n = rentex.length;
+ var texProp = null;
+
+ // for initFBO
+ var type = gl.UNSIGNED_BYTE;
+ var shadowType = gl.UNSIGNED_BYTE;
+ var nearestFilt = false;
+
+ if (x3dom.caps.FP_TEXTURES && !x3dom.caps.MOBILE) {
+ type = gl.FLOAT;
+ shadowType = gl.FLOAT;
+ if (!x3dom.caps.FPL_TEXTURES) {
+ nearestFilt = true; // TODO: use correct filtering for fp-textures
+ }
+ }
+
+ var shadowedLights, numShadowMaps;
+ var i, j, n, size, sizeAvailable;
+ var texType, refinementPos;
+ var vertices = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];
+
+ scene.updateVolume();
+
+ if (!scene._webgl)
+ {
+ scene._webgl = {};
+
+ this.setupFgnds(gl, scene);
+
+ // scale factor for mouse coords and width/ height (low res for speed-up)
+ scene._webgl.pickScale = 0.5;
+
+ scene._webgl._currFboWidth = Math.round(this.canvas.width * scene._webgl.pickScale);
+ scene._webgl._currFboHeight = Math.round(this.canvas.height * scene._webgl.pickScale);
+
+ // TODO: FIXME when spec ready: readPixels not (yet?) available for float textures
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=681903
+ // https://www.khronos.org/webgl/public-mailing-list/archives/1108/msg00025.html
+ scene._webgl.fboPick = x3dom.Utils.initFBO(gl,
+ scene._webgl._currFboWidth, scene._webgl._currFboHeight, gl.UNSIGNED_BYTE, false, true);
+ scene._webgl.fboPick.pixelData = null;
+
+ //Set picking shaders
+ /*scene._webgl.pickShader = this.cache.getShader(gl, x3dom.shader.PICKING);
+ scene._webgl.pickShader24 = this.cache.getShader(gl, x3dom.shader.PICKING_24);
+ scene._webgl.pickShaderId = this.cache.getShader(gl, x3dom.shader.PICKING_ID);
+ scene._webgl.pickColorShader = this.cache.getShader(gl, x3dom.shader.PICKING_COLOR);
+ scene._webgl.pickTexCoordShader = this.cache.getShader(gl, x3dom.shader.PICKING_TEXCOORD);*/
+
+ scene._webgl.normalShader = this.cache.getShader(gl, x3dom.shader.NORMAL);
+
+ //Initialize shadow maps
+ scene._webgl.fboShadow = [];
+
+ shadowedLights = viewarea.getShadowedLights();
+ n = shadowedLights.length;
+
+ for (i=0; i<n; i++)
+ {
+ size = shadowedLights[i]._vf.shadowMapSize;
+
+ if (!x3dom.isa(shadowedLights[i], x3dom.nodeTypes.PointLight))
+ //cascades for directional lights
+ numShadowMaps = Math.max(1,Math.min(shadowedLights[i]._vf.shadowCascades,6));
+ else
+ //six maps for point lights
+ numShadowMaps = 6;
+
+ scene._webgl.fboShadow[i] = [];
+
+ for (j=0; j < numShadowMaps; j++)
+ scene._webgl.fboShadow[i][j] = x3dom.Utils.initFBO(gl, size, size, shadowType, false, true);
+ }
+
+ if (scene._webgl.fboShadow.length > 0 || x3dom.SSAO.isEnabled(scene))
+ scene._webgl.fboScene = x3dom.Utils.initFBO(gl, this.canvas.width, this.canvas.height, shadowType, false, true);
+ scene._webgl.fboBlur = [];
+
+ //initialize blur fbo (different fbos for different sizes)
+ for (i=0; i<n; i++)
+ {
+ size = scene._webgl.fboShadow[i][0].height;
+ sizeAvailable = false;
+
+ for (j = 0; j < scene._webgl.fboBlur.length; j++){
+ if (size == scene._webgl.fboBlur[j].height)
+ sizeAvailable = true;
+ }
+ if (!sizeAvailable)
+ scene._webgl.fboBlur[scene._webgl.fboBlur.length] = x3dom.Utils.initFBO(gl, size, size, shadowType, false, true);
+ }
+
+ //initialize Data for post processing
+ scene._webgl.ppBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._webgl.ppBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+ scene._webgl.shadowShader = this.cache.getShader(gl, x3dom.shader.SHADOW);
+
+ // TODO; cleanup on shutdown and lazily create on first use like size-dependent variables below
+ scene._webgl.refinement = {
+ stamps: new Array(2),
+ positionBuffer: gl.createBuffer()
+ };
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._webgl.refinement.positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+ // This must be refreshed on node change!
+ for (rtl_i = 0; rtl_i < rtl_n; rtl_i++) {
+ rt_tex = rentex[rtl_i];
+
+ texProp = rt_tex._cf.textureProperties.node;
+ texType = rt_tex.requirePingPong() ? gl.UNSIGNED_BYTE : type;
+ rt_tex._webgl = {};
+ rt_tex._webgl.fbo = x3dom.Utils.initFBO(gl,
+ rt_tex._vf.dimensions[0], rt_tex._vf.dimensions[1], texType,
+ (texProp && texProp._vf.generateMipMaps), !rt_tex.requirePingPong());
+
+ rt_tex._cleanupGLObjects = function(retainTex) {
+ if (!retainTex)
+ gl.deleteTexture(this._webgl.fbo.tex);
+ if (this._webgl.fbo.rbo)
+ gl.deleteRenderbuffer(this._webgl.fbo.rbo);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteFramebuffer(this._webgl.fbo.fbo);
+ this._webgl.fbo.rbo = null;
+ this._webgl.fbo.fbo = null;
+ };
+
+ if (rt_tex.requirePingPong()) {
+ refinementPos = rt_tex._vf.dimensions[0] + "x" + rt_tex._vf.dimensions[1];
+ if (scene._webgl.refinement[refinementPos] === undefined) {
+ scene._webgl.refinement[refinementPos] = x3dom.Utils.initFBO(gl,
+ rt_tex._vf.dimensions[0], rt_tex._vf.dimensions[1], texType, false, false);
+ }
+ rt_tex._webgl.texture = null;
+ }
+ }
+
+ viewarea._last_mat_view = x3dom.fields.SFMatrix4f.identity();
+ viewarea._last_mat_proj = x3dom.fields.SFMatrix4f.identity();
+ viewarea._last_mat_scene = x3dom.fields.SFMatrix4f.identity();
+
+ this._calledViewpointChangedHandler = false;
+ }
+ else // updates needed?
+ {
+ var fboWidth = Math.round(this.canvas.width * scene._webgl.pickScale);
+ var fboHeight = Math.round(this.canvas.height * scene._webgl.pickScale);
+
+ if (scene._webgl._currFboWidth !== fboWidth ||
+ scene._webgl._currFboHeight !== fboHeight) {
+ scene._webgl._currFboWidth = fboWidth;
+ scene._webgl._currFboHeight = fboHeight;
+
+ scene._webgl.fboPick = x3dom.Utils.initFBO(gl, fboWidth, fboHeight, scene._webgl.fboPick.type, false, true);
+ scene._webgl.fboPick.pixelData = null;
+
+ x3dom.debug.logInfo("Refreshed picking FBO to size (" + fboWidth + ", " + fboHeight + ")");
+ }
+
+ for (rtl_i = 0; rtl_i < rtl_n; rtl_i++) {
+ rt_tex = rentex[rtl_i];
+ if (rt_tex._webgl && rt_tex._webgl.fbo &&
+ rt_tex._webgl.fbo.width == rt_tex._vf.dimensions[0] &&
+ rt_tex._webgl.fbo.height == rt_tex._vf.dimensions[1])
+ continue;
+
+ rt_tex.invalidateGLObject();
+ if (rt_tex._cleanupGLObjects)
+ rt_tex._cleanupGLObjects();
+ else
+ rt_tex._cleanupGLObjects = function(retainTex) {
+ if (!retainTex)
+ gl.deleteTexture(this._webgl.fbo.tex);
+ if (this._webgl.fbo.rbo)
+ gl.deleteRenderbuffer(this._webgl.fbo.rbo);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteFramebuffer(this._webgl.fbo.fbo);
+ this._webgl.fbo.rbo = null;
+ this._webgl.fbo.fbo = null;
+ };
+
+ texProp = rt_tex._cf.textureProperties.node;
+ texType = rt_tex.requirePingPong() ? gl.UNSIGNED_BYTE : type;
+ rt_tex._webgl = {};
+ rt_tex._webgl.fbo = x3dom.Utils.initFBO(gl,
+ rt_tex._vf.dimensions[0], rt_tex._vf.dimensions[1], texType,
+ (texProp && texProp._vf.generateMipMaps), !rt_tex.requirePingPong());
+
+ if (rt_tex.requirePingPong()) {
+ refinementPos = rt_tex._vf.dimensions[0] + "x" + rt_tex._vf.dimensions[1];
+ if (scene._webgl.refinement[refinementPos] === undefined) {
+ scene._webgl.refinement[refinementPos] = x3dom.Utils.initFBO(gl,
+ rt_tex._vf.dimensions[0], rt_tex._vf.dimensions[1], texType, false, false);
+ }
+ rt_tex._webgl.texture = null;
+ }
+
+ x3dom.debug.logInfo("Init/resize RenderedTexture_" + rtl_i + " to size " +
+ rt_tex._vf.dimensions[0] + " x " + rt_tex._vf.dimensions[1]);
+ }
+
+ //reinitialize shadow fbos if necessary
+ shadowedLights = viewarea.getShadowedLights();
+ n = shadowedLights.length;
+
+ for (i=0; i<n; i++) {
+ size = shadowedLights[i]._vf.shadowMapSize;
+
+ if (!x3dom.isa(shadowedLights[i], x3dom.nodeTypes.PointLight))
+ //cascades for directional lights
+ numShadowMaps = Math.max(1,Math.min(shadowedLights[i]._vf.shadowCascades,6));
+ else
+ //six maps for point lights
+ numShadowMaps = 6;
+
+ if (typeof scene._webgl.fboShadow[i] === "undefined" ||
+ scene._webgl.fboShadow[i].length != numShadowMaps ||
+ scene._webgl.fboShadow[i][0].height != size) {
+ scene._webgl.fboShadow[i] = [];
+ for (j=0;j<numShadowMaps;j++){
+ scene._webgl.fboShadow[i][j] = x3dom.Utils.initFBO(gl, size, size, shadowType, false, true);
+ }
+ }
+ }
+
+ //reinitialize blur fbos if necessary
+ for (i=0; i<n; i++){
+ size = scene._webgl.fboShadow[i][0].height;
+
+ sizeAvailable = false;
+ for (j = 0; j < scene._webgl.fboBlur.length; j++){
+ if (size == scene._webgl.fboBlur[j].height)
+ sizeAvailable = true;
+ }
+ if (!sizeAvailable)
+ scene._webgl.fboBlur[scene._webgl.fboBlur.length] = x3dom.Utils.initFBO(gl, size, size, shadowType, false, true);
+ }
+
+ if ((x3dom.SSAO.isEnabled(scene) ||scene._webgl.fboShadow.length > 0) && typeof scene._webgl.fboScene == "undefined" || scene._webgl.fboScene &&
+ (this.canvas.width != scene._webgl.fboScene.width || this.canvas.height != scene._webgl.fboScene.height)) {
+ scene._webgl.fboScene = x3dom.Utils.initFBO(gl, this.canvas.width, this.canvas.height, shadowType, false, true);
+ }
+ }
+
+ var env = scene.getEnvironment();
+ // update internal flags
+ env.checkSanity();
+
+ var bgnd = scene.getBackground();
+ // setup or update bgnd
+ this.setupScene(gl, bgnd);
+
+ this.numFaces = 0;
+ this.numCoords = 0;
+ this.numDrawCalls = 0;
+
+ var mat_proj = viewarea.getProjectionMatrix();
+ var mat_view = viewarea.getViewMatrix();
+
+ // fire viewpointChanged event
+ if (!this._calledViewpointChangedHandler || !viewarea._last_mat_view.equals(mat_view)) {
+ var e_viewpoint = scene.getViewpoint();
+ var e_eventType = "viewpointChanged";
+
+ try {
+ if ( e_viewpoint._xmlNode &&
+ (e_viewpoint._xmlNode["on" + e_eventType] ||
+ e_viewpoint._xmlNode.hasAttribute("on" + e_eventType) ||
+ e_viewpoint._listeners[e_eventType]) ) {
+ var e_viewtrafo = e_viewpoint.getCurrentTransform();
+ e_viewtrafo = e_viewtrafo.inverse().mult(mat_view);
+ var e_mat = e_viewtrafo.inverse();
+
+ var e_rotation = new x3dom.fields.Quaternion(0, 0, 1, 0);
+ e_rotation.setValue(e_mat);
+ var e_translation = e_mat.e3();
+
+ var e_event = {
+ target: e_viewpoint._xmlNode,
+ type: e_eventType,
+ matrix: e_viewtrafo,
+ position: e_translation,
+ orientation: e_rotation.toAxisAngle(),
+ cancelBubble: false,
+ stopPropagation: function () { this.cancelBubble = true; },
+ preventDefault: function () { this.cancelBubble = true; }
+ };
+
+ e_viewpoint.callEvtHandler(("on" + e_eventType), e_event);
+
+ this._calledViewpointChangedHandler = true;
+ }
+ }
+ catch (e_e) {
+ x3dom.debug.logException(e_e);
+ }
+ }
+
+ viewarea._last_mat_view = mat_view;
+ viewarea._last_mat_proj = mat_proj;
+
+ var mat_scene = mat_proj.mult(mat_view); //viewarea.getWCtoCCMatrix();
+ viewarea._last_mat_scene = mat_scene;
+
+
+ //===========================================================================
+ // Collect drawables (traverse)
+ //===========================================================================
+ scene.drawableCollection = null; // Always update needed?
+
+ if (!scene.drawableCollection)
+ {
+ var drawableCollectionConfig = {
+ viewArea: viewarea,
+ sortTrans: env._vf.sortTrans,
+ viewMatrix: mat_view,
+ projMatrix: mat_proj,
+ sceneMatrix: mat_scene,
+ frustumCulling: true,
+ smallFeatureThreshold: env._smallFeatureThreshold,
+ context: this,
+ gl: gl
+ };
+
+ scene.drawableCollection = new x3dom.DrawableCollection(drawableCollectionConfig);
+
+ x3dom.Utils.startMeasure('traverse');
+
+ scene.collectDrawableObjects(x3dom.fields.SFMatrix4f.identity(), scene.drawableCollection, true, false, 0, []);
+
+ var traverseTime = x3dom.Utils.stopMeasure('traverse');
+ this.x3dElem.runtime.addMeasurement('TRAVERSE', traverseTime);
+ }
+
+ //===========================================================================
+ // Sort drawables
+ //===========================================================================
+ x3dom.Utils.startMeasure('sorting');
+
+ scene.drawableCollection.sort();
+
+ var sortTime = x3dom.Utils.stopMeasure('sorting');
+ this.x3dElem.runtime.addMeasurement('SORT', sortTime);
+
+ //===========================================================================
+ // Render Shadow Pass
+ //===========================================================================
+ var slights = viewarea.getLights();
+ var numLights = slights.length;
+ var mat_light;
+ var WCToLCMatrices = [];
+ var lMatrices = [];
+ var shadowCount = 0;
+
+ x3dom.Utils.startMeasure('shadow');
+
+ for (var p = 0; p < numLights; p++) {
+ if (slights[p]._vf.shadowIntensity > 0.0) {
+
+ var lightMatrix = viewarea.getLightMatrix()[p];
+ shadowMaps = scene._webgl.fboShadow[shadowCount];
+ var offset = Math.max(0.0, Math.min(1.0, slights[p]._vf.shadowOffset));
+
+ if (!x3dom.isa(slights[p], x3dom.nodeTypes.PointLight)) {
+ //get cascade count
+ var numCascades = Math.max(1, Math.min(slights[p]._vf.shadowCascades, 6));
+
+ //calculate transformation matrices
+ mat_light = viewarea.getWCtoLCMatricesCascaded(lightMatrix, slights[p], mat_proj);
+
+ //render shadow pass
+ for (i = 0; i < numCascades; i++) {
+ this.renderShadowPass(gl, viewarea, mat_light[i], mat_view, shadowMaps[i], offset, false);
+ }
+ }
+ else {
+ //for point lights 6 render passes
+ mat_light = viewarea.getWCtoLCMatricesPointLight(lightMatrix, slights[p], mat_proj);
+ for (i = 0; i < 6; i++) {
+ this.renderShadowPass(gl, viewarea, mat_light[i], mat_view, shadowMaps[i], offset, false);
+ }
+ }
+ shadowCount++;
+
+ //save transformations for shadow rendering
+ WCToLCMatrices[WCToLCMatrices.length] = mat_light;
+ lMatrices[lMatrices.length] = lightMatrix;
+ }
+ }
+
+ //One pass for depth of scene from camera view (to enable post-processing shading)
+ if (shadowCount > 0 || x3dom.SSAO.isEnabled(scene)) {
+ this.renderShadowPass(gl, viewarea, mat_scene, mat_view, scene._webgl.fboScene, 0.0, true);
+ var shadowTime = x3dom.Utils.stopMeasure('shadow');
+ this.x3dElem.runtime.addMeasurement('SHADOW', shadowTime);
+ }
+ else {
+ this.x3dElem.runtime.removeMeasurement('SHADOW');
+ }
+
+ mat_light = viewarea.getWCtoLCMatrix(viewarea.getLightMatrix()[0]);
+
+ for (rtl_i = 0; rtl_i < rtl_n; rtl_i++) {
+ this.renderRTPass(gl, viewarea, rentex[rtl_i]);
+ }
+
+ // rendering
+ x3dom.Utils.startMeasure('render');
+
+ this.stateManager.viewport(0, 0, this.canvas.width, this.canvas.height);
+
+ // calls gl.clear etc. (bgnd stuff)
+ bgnd._webgl.render(gl, mat_view, mat_proj);
+
+ x3dom.nodeTypes.PopGeometry.numRenderedVerts = 0;
+ x3dom.nodeTypes.PopGeometry.numRenderedTris = 0;
+
+ n = scene.drawableCollection.length;
+
+ // Very, very experimental priority culling, currently coupled with frustum and small feature culling
+ // TODO; what about shadows?
+ if (env._vf.smallFeatureCulling && env._lowPriorityThreshold < 1 && viewarea.isMovingOrAnimating()) {
+ n = Math.floor(n * env._lowPriorityThreshold);
+ if (!n && scene.drawableCollection.length)
+ n = 1; // render at least one object
+ }
+
+ this.stateManager.unsetProgram();
+
+ // render all remaining shapes
+ for (i = 0; i < n; i++) {
+ var drawable = scene.drawableCollection.get(i);
+
+ this.renderShape(drawable, viewarea, slights, numLights, mat_view, mat_scene, mat_light, mat_proj, gl);
+ }
+
+ if (shadowCount > 0)
+ this.renderShadows(gl, viewarea, shadowedLights, WCToLCMatrices, lMatrices, mat_view, mat_proj, mat_scene);
+
+ this.stateManager.disable(gl.BLEND);
+ this.stateManager.disable(gl.DEPTH_TEST);
+
+ viewarea._numRenderedNodes = n;
+
+ if(x3dom.SSAO.isEnabled(scene))
+ x3dom.SSAO.renderSSAO(this.stateManager, gl, scene, this.canvas);
+
+ // if _visDbgBuf then show helper buffers in foreground for debugging
+ if (viewarea._visDbgBuf !== undefined && viewarea._visDbgBuf)
+ {
+ var pm = scene._vf.pickMode.toLowerCase();
+
+ if (pm.indexOf("idbuf") == 0 || pm == "color" || pm == "texcoord") {
+ this.stateManager.viewport(0, 3 * this.canvas.height / 4,
+ this.canvas.width / 4, this.canvas.height / 4);
+ scene._fgnd._webgl.render(gl, scene._webgl.fboPick.tex);
+ }
+
+ if (shadowCount > 0 || x3dom.SSAO.isEnabled(scene)) {
+ this.stateManager.viewport(this.canvas.width / 4, 3 * this.canvas.height / 4,
+ this.canvas.width / 4, this.canvas.height / 4);
+ scene._fgnd._webgl.render(gl, scene._webgl.fboScene.tex);
+ }
+
+ var row = 3, col = 2;
+ for (i = 0; i < shadowCount; i++) {
+ var shadowMaps = scene._webgl.fboShadow[i];
+ for (j = 0; j < shadowMaps.length; j++) {
+ this.stateManager.viewport(col * this.canvas.width / 4, row * this.canvas.height / 4,
+ this.canvas.width / 4, this.canvas.height / 4);
+ scene._fgnd._webgl.render(gl, shadowMaps[j].tex);
+ if (col < 2) {
+ col++;
+ } else {
+ col = 0;
+ row--;
+ }
+ }
+ }
+
+ for (rtl_i = 0; rtl_i < rtl_n; rtl_i++) {
+ rt_tex = rentex[rtl_i];
+ if (!rt_tex._webgl.fbo.fbo) // might be deleted (--> RefinementTexture when finished)
+ continue;
+
+ this.stateManager.viewport(rtl_i * this.canvas.width / 8, 5 * this.canvas.height / 8,
+ this.canvas.width / 8, this.canvas.height / 8);
+ scene._fgnd._webgl.render(gl, rt_tex._webgl.fbo.tex);
+ }
+ }
+
+ gl.finish();
+ //gl.flush();
+
+ var renderTime = x3dom.Utils.stopMeasure('render');
+
+ this.x3dElem.runtime.addMeasurement('RENDER', renderTime);
+ this.x3dElem.runtime.addMeasurement('DRAW', (n ? renderTime / n : 0));
+
+ this.x3dElem.runtime.addInfo('#NODES:', scene.drawableCollection.numberOfNodes);
+ this.x3dElem.runtime.addInfo('#SHAPES:', viewarea._numRenderedNodes);
+ this.x3dElem.runtime.addInfo("#DRAWS:", this.numDrawCalls);
+ this.x3dElem.runtime.addInfo("#POINTS:", this.numCoords);
+ this.x3dElem.runtime.addInfo("#TRIS:", this.numFaces);
+
+ //scene.drawableObjects = null;
+ };
+
+ /*****************************************************************************
+ * Render special PingPong-Pass
+ *****************************************************************************/
+ Context.prototype.renderPingPongPass = function (gl, viewarea, rt) {
+ var scene = viewarea._scene;
+ var refinementPos = rt._vf.dimensions[0] + "x" + rt._vf.dimensions[1];
+ var refinementFbo = scene._webgl.refinement[refinementPos];
+
+ // load stamp textures
+ if (rt._currLoadLevel == 0 && (!scene._webgl.refinement.stamps[0] || !scene._webgl.refinement.stamps[1])) {
+ scene._webgl.refinement.stamps[0] = this.cache.getTexture2D(gl, rt._nameSpace.doc,
+ rt._nameSpace.getURL(rt._vf.stamp0), false, false, false, false);
+ scene._webgl.refinement.stamps[1] = this.cache.getTexture2D(gl, rt._nameSpace.doc,
+ rt._nameSpace.getURL(rt._vf.stamp1), false, false, false, false);
+ }
+
+ // load next level of image
+ if (rt._currLoadLevel < rt._loadLevel) {
+ rt._currLoadLevel++;
+
+ if (rt._webgl.texture)
+ gl.deleteTexture(rt._webgl.texture);
+
+ var filename = rt._vf.url[0] + "/" + rt._currLoadLevel + "." + rt._vf.format;
+
+ rt._webgl.texture = x3dom.Utils.createTexture2D(gl, rt._nameSpace.doc,
+ rt._nameSpace.getURL(filename), false, false, false, false);
+
+ if (rt._vf.iterations % 2 === 0)
+ (rt._currLoadLevel % 2 !== 0) ? rt._repeat.x *= 2.0 : rt._repeat.y *= 2.0;
+ else
+ (rt._currLoadLevel % 2 === 0) ? rt._repeat.x *= 2.0 : rt._repeat.y *= 2.0;
+ }
+
+ if (!rt._webgl.texture.ready ||
+ !scene._webgl.refinement.stamps[0].ready || !scene._webgl.refinement.stamps[1].ready)
+ return;
+
+ // first pass
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, refinementFbo.fbo);
+ this.stateManager.viewport(0, 0, refinementFbo.width, refinementFbo.height);
+
+ this.stateManager.disable(gl.BLEND);
+ this.stateManager.disable(gl.CULL_FACE);
+ this.stateManager.disable(gl.DEPTH_TEST);
+
+ gl.clearColor(0, 0, 0, 1);
+ gl.clearDepth(1);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ var sp = this.cache.getShader(gl, x3dom.shader.TEXTURE_REFINEMENT);
+ this.stateManager.useProgram(sp);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._webgl.refinement.positionBuffer);
+ gl.vertexAttribPointer(sp.position, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ sp.stamp = 0;
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, scene._webgl.refinement.stamps[(rt._currLoadLevel + 1) % 2]); // draw stamp
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
+
+ if (rt._currLoadLevel > 1) {
+ sp.lastTex = 1;
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(gl.TEXTURE_2D, rt._webgl.fbo.tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ }
+
+ sp.curTex = 2;
+ gl.activeTexture(gl.TEXTURE2);
+ gl.bindTexture(gl.TEXTURE_2D, rt._webgl.texture); // draw level image to fbo
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ sp.mode = rt._currLoadLevel - 1;
+ sp.repeat = rt._repeat.toGL();
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ // second pass
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, rt._webgl.fbo.fbo);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ sp.mode = 0;
+ sp.curTex = 2;
+ gl.activeTexture(gl.TEXTURE2);
+ gl.bindTexture(gl.TEXTURE_2D, refinementFbo.tex); // draw result to fbo
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ gl.disableVertexAttribArray(sp.position);
+
+ // pass done
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, null);
+ this.stateManager.viewport(0, 0, this.canvas.width, this.canvas.height);
+
+ if (rt._vf.autoRefinement)
+ rt.nextLevel();
+
+ if (rt._currLoadLevel == rt._vf.maxLevel)
+ rt._currLoadLevel++;
+
+ if (rt._webgl.fbo.mipMap) {
+ gl.bindTexture(gl.TEXTURE_2D, rt._webgl.fbo.tex);
+ gl.generateMipmap(gl.TEXTURE_2D);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+
+ // we're finally done: cleanup/delete all helper FBOs
+ if (!rt.requirePingPong()) {
+ gl.deleteTexture(rt._webgl.texture);
+ delete rt._webgl.texture;
+
+ rt._cleanupGLObjects(true);
+ }
+
+ rt._renderedImage++;
+ };
+
+ /*****************************************************************************
+ * Render RenderedTexture-Pass
+ *****************************************************************************/
+ Context.prototype.renderRTPass = function (gl, viewarea, rt)
+ {
+ /// begin special case (progressive image refinement)
+ if (x3dom.isa(rt, x3dom.nodeTypes.RefinementTexture)) {
+ if (rt.requirePingPong()) {
+ this.renderPingPongPass(gl, viewarea, rt);
+ }
+ return;
+ }
+ /// end special case
+
+ switch (rt._vf.update.toUpperCase()) {
+ case "NONE":
+ return;
+ case "NEXT_FRAME_ONLY":
+ if (!rt._needRenderUpdate) {
+ return;
+ }
+ rt._needRenderUpdate = false;
+ break;
+ case "ALWAYS":
+ default:
+ break;
+ }
+
+ var scene = viewarea._scene;
+ var bgnd = null;
+
+ var mat_view = rt.getViewMatrix();
+ var mat_proj = rt.getProjectionMatrix();
+ var mat_scene = mat_proj.mult(mat_view);
+
+ var lightMatrix = viewarea.getLightMatrix()[0];
+ var mat_light = viewarea.getWCtoLCMatrix(lightMatrix);
+
+ var i, n, m = rt._cf.excludeNodes.nodes.length;
+
+ var arr = new Array(m);
+ for (i = 0; i < m; i++) {
+ var render = rt._cf.excludeNodes.nodes[i]._vf.render;
+ if (render === undefined) {
+ arr[i] = -1;
+ }
+ else {
+ if (render === true) {
+ arr[i] = 1;
+ } else {
+ arr[i] = 0;
+ }
+ }
+ rt._cf.excludeNodes.nodes[i]._vf.render = false;
+ }
+
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, rt._webgl.fbo.fbo);
+
+ this.stateManager.viewport(0, 0, rt._webgl.fbo.width, rt._webgl.fbo.height);
+
+ if (rt._cf.background.node === null) {
+ gl.clearColor(0, 0, 0, 1);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+ }
+ else if (rt._cf.background.node === scene.getBackground()) {
+ bgnd = scene.getBackground();
+ bgnd._webgl.render(gl, mat_view, mat_proj);
+ }
+ else {
+ bgnd = rt._cf.background.node;
+ this.setupScene(gl, bgnd);
+ bgnd._webgl.render(gl, mat_view, mat_proj);
+ }
+
+ this.stateManager.depthFunc(gl.LEQUAL);
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.enable(gl.CULL_FACE);
+
+ this.stateManager.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
+ this.stateManager.enable(gl.BLEND);
+
+ var slights = viewarea.getLights();
+ var numLights = slights.length;
+
+ var transform, shape, drawable;
+ var locScene = rt._cf.scene.node;
+
+ if (!locScene || locScene === scene) {
+ n = scene.drawableCollection.length;
+
+ if (rt._vf.showNormals) {
+ this.renderNormals(gl, scene, scene._webgl.normalShader, mat_view, mat_scene);
+ }
+ else {
+ this.stateManager.unsetProgram();
+
+ for (i = 0; i < n; i++) {
+ drawable = scene.drawableCollection.get(i);
+
+ this.renderShape(drawable, viewarea, slights, numLights,
+ mat_view, mat_scene, mat_light, mat_proj, gl);
+ }
+ }
+ }
+ else {
+ var env = scene.getEnvironment();
+
+ var drawableCollectionConfig = {
+ viewArea: viewarea,
+ sortTrans: env._vf.sortTrans,
+ viewMatrix: mat_view,
+ projMatrix: mat_proj,
+ sceneMatrix: mat_scene,
+ frustumCulling: false,
+ smallFeatureThreshold: 1,
+ context: this,
+ gl: gl
+ };
+
+ locScene.numberOfNodes = 0;
+ locScene.drawableCollection = new x3dom.DrawableCollection(drawableCollectionConfig);
+
+ locScene.collectDrawableObjects(x3dom.fields.SFMatrix4f.identity(),
+ locScene.drawableCollection, true, false, 0, []);
+
+ locScene.drawableCollection.sort();
+
+ n = locScene.drawableCollection.length;
+
+ if (rt._vf.showNormals) {
+ this.renderNormals(gl, locScene, scene._webgl.normalShader, mat_view, mat_scene);
+ }
+ else {
+ this.stateManager.unsetProgram();
+
+ for (i = 0; i < n; i++) {
+ drawable = locScene.drawableCollection.get(i);
+
+ if (!drawable.shape._vf.render) {
+ continue;
+ }
+
+ this.renderShape(drawable, viewarea, slights, numLights,
+ mat_view, mat_scene, mat_light, mat_proj, gl);
+ }
+ }
+ }
+
+ this.stateManager.disable(gl.BLEND);
+ this.stateManager.disable(gl.DEPTH_TEST);
+
+ gl.flush();
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ if (rt._webgl.fbo.mipMap) {
+ gl.bindTexture(gl.TEXTURE_2D, rt._webgl.fbo.tex);
+ gl.generateMipmap(gl.TEXTURE_2D);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+
+ for (i = 0; i < m; i++) {
+ if (arr[i] !== 0) {
+ rt._cf.excludeNodes.nodes[i]._vf.render = true;
+ }
+ }
+ };
+
+ /*****************************************************************************
+ * Render Normals
+ *****************************************************************************/
+ Context.prototype.renderNormals = function (gl, scene, sp, mat_view, mat_scene)
+ {
+ if (!sp || !scene) { // error
+ return;
+ }
+
+ this.stateManager.depthFunc(gl.LEQUAL);
+ this.stateManager.enable(gl.DEPTH_TEST);
+ this.stateManager.enable(gl.CULL_FACE);
+ this.stateManager.disable(gl.BLEND);
+
+ this.stateManager.useProgram(sp);
+
+ var bgCenter = x3dom.fields.SFVec3f.NullVector.toGL();
+ var bgSize = x3dom.fields.SFVec3f.OneVector.toGL();
+
+ for (var i = 0, n = scene.drawableCollection.length; i < n; i++)
+ {
+ var drawable = scene.drawableCollection.get(i);
+ var trafo = drawable.transform;
+ var shape = drawable.shape;
+ var s_gl = shape._webgl;
+
+ if (!s_gl || !shape || !shape._vf.render) {
+ continue;
+ }
+
+ var s_geo = shape._cf.geometry.node;
+ var s_msh = s_geo._mesh;
+
+ var model_view_inv = mat_view.mult(trafo).inverse();
+ sp.normalMatrix = model_view_inv.transpose().toGL();
+ sp.modelViewProjectionMatrix = mat_scene.mult(trafo).toGL();
+
+ //Set ImageGeometry switch (TODO; also impl. in Shader!)
+ sp.imageGeometry = s_gl.imageGeometry;
+
+ if (s_gl.coordType != gl.FLOAT) {
+ if (s_gl.popGeometry != 0 ||
+ (s_msh._numPosComponents == 4 && x3dom.Utils.isUnsignedType(s_geo._vf.coordType)))
+ sp.bgCenter = s_geo.getMin().toGL();
+ else
+ sp.bgCenter = s_geo._vf.position.toGL();
+ sp.bgSize = s_geo._vf.size.toGL();
+ sp.bgPrecisionMax = s_geo.getPrecisionMax('coordType');
+ }
+ else {
+ sp.bgCenter = bgCenter;
+ sp.bgSize = bgSize;
+ sp.bgPrecisionMax = 1;
+ }
+ if (s_gl.normalType != gl.FLOAT) {
+ sp.bgPrecisionNorMax = s_geo.getPrecisionMax('normalType');
+ }
+ else {
+ sp.bgPrecisionNorMax = 1;
+ }
+
+ if (shape.isSolid()) {
+ this.stateManager.enable(gl.CULL_FACE);
+
+ if (shape.isCCW()) {
+ this.stateManager.frontFace(gl.CCW);
+ }
+ else {
+ this.stateManager.frontFace(gl.CW);
+ }
+ }
+ else {
+ this.stateManager.disable(gl.CULL_FACE);
+ }
+
+
+ // render shape
+ for (var q = 0, q_n = s_gl.positions.length; q < q_n; q++) {
+ var q6 = 6 * q;
+ var v, v_n, offset;
+
+ if ( !(sp.position !== undefined && s_gl.buffers[q6 + 1] && s_gl.indexes[q]) )
+ continue;
+
+ // bind buffers
+ if (s_gl.buffers[q6]) {
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, s_gl.buffers[q6]);
+ }
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 1]);
+
+ gl.vertexAttribPointer(sp.position,
+ s_msh._numPosComponents, s_gl.coordType, false,
+ shape._coordStrideOffset[0], shape._coordStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.position);
+
+ if (sp.normal !== undefined && s_gl.buffers[q6 + 2]) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, s_gl.buffers[q6 + 2]);
+
+ gl.vertexAttribPointer(sp.normal,
+ s_msh._numNormComponents, s_gl.normalType, false,
+ shape._normalStrideOffset[0], shape._normalStrideOffset[1]);
+ gl.enableVertexAttribArray(sp.normal);
+ }
+
+ // draw mesh
+ if (s_gl.binaryGeometry > 0 || s_gl.popGeometry > 0) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType[v], s_geo._vf.vertexCount[v], s_gl.indexType,
+ x3dom.Utils.getByteAwareOffset(offset, s_gl.indexType, gl));
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ else if (s_gl.binaryGeometry < 0 || s_gl.popGeometry < 0 || s_gl.imageGeometry) {
+ for (v = 0, offset = 0, v_n = s_geo._vf.vertexCount.length; v < v_n; v++) {
+ gl.drawArrays(s_gl.primType[v], offset, s_geo._vf.vertexCount[v]);
+ offset += s_geo._vf.vertexCount[v];
+ }
+ }
+ else if (s_geo.hasIndexOffset()) {
+ var indOff = shape.tessellationProperties();
+ for (v = 0, v_n = indOff.length; v < v_n; v++) {
+ gl.drawElements(s_gl.primType, indOff[v].count, s_gl.indexType,
+ indOff[v].offset * x3dom.Utils.getOffsetMultiplier(s_gl.indexType, gl));
+ }
+ }
+ else if (s_gl.indexes[q].length == 0) {
+ gl.drawArrays(s_gl.primType, 0, s_gl.positions[q].length / 3);
+ }
+ else {
+ gl.drawElements(s_gl.primType, s_gl.indexes[q].length, s_gl.indexType, 0);
+ }
+
+ gl.disableVertexAttribArray(sp.position);
+
+ if (sp.normal !== undefined) {
+ gl.disableVertexAttribArray(sp.normal);
+ }
+ }
+ }
+ };
+
+ /*****************************************************************************
+ * Cleanup
+ *****************************************************************************/
+ Context.prototype.shutdown = function (viewarea) {
+ var gl = this.ctx3d;
+ var scene = viewarea._scene;
+
+ if (gl == null || !scene) {
+ return;
+ }
+
+ var bgnd = scene.getBackground();
+ if (bgnd._webgl.position !== undefined) {
+ gl.deleteBuffer(bgnd._webgl.buffers[1]);
+ gl.deleteBuffer(bgnd._webgl.buffers[0]);
+ }
+ var fgnd = scene._fgnd;
+ if (fgnd._webgl.position !== undefined) {
+ gl.deleteBuffer(fgnd._webgl.buffers[1]);
+ gl.deleteBuffer(fgnd._webgl.buffers[0]);
+ }
+
+ var n = scene.drawableCollection ? scene.drawableCollection.length : 0;
+ for (var i = 0; i < n; i++) {
+ var shape = scene.drawableCollection.get(i).shape;
+
+ if (shape._cleanupGLObjects)
+ shape._cleanupGLObjects(true);
+ }
+
+ //Release Texture and Shader Resources
+ this.cache.Release(gl);
+ };
+
+ /*****************************************************************************
+ * Draw shadows on screen
+ *****************************************************************************/
+ Context.prototype.renderShadows = function(gl, viewarea, shadowedLights, wctolc, lMatrices,
+ mat_view, mat_proj, mat_scene)
+ {
+ var scene = viewarea._scene;
+
+ //don't render shadows with less than 7 textures per fragment shader
+ var texLimit = x3dom.caps.MAX_TEXTURE_IMAGE_UNITS;
+
+ if (texLimit < 7)
+ return;
+
+ var texUnits = 1;
+ var renderSplit = [ 0 ];
+
+ var shadowMaps, numShadowMaps;
+ var i, j, k;
+
+ //filter shadow maps and determine, if multiple render passes are needed
+ for (i = 0; i < shadowedLights.length; i++)
+ {
+ var filterSize = shadowedLights[i]._vf.shadowFilterSize;
+ shadowMaps = scene._webgl.fboShadow[i];
+ numShadowMaps = shadowMaps.length;
+
+ //filtering
+ for (j=0; j<numShadowMaps;j++){
+ this.blurTex(gl, scene, shadowMaps[j], filterSize);
+ }
+
+ //shader consumes 6 tex units per lights (even if less are bound)
+ texUnits+=6;
+
+ if (texUnits > texLimit){
+ renderSplit[renderSplit.length] = i;
+ texUnits = 7;
+ }
+ }
+ renderSplit[renderSplit.length] = shadowedLights.length;
+
+ //render shadows for current render split
+ var n = renderSplit.length - 1;
+ var mat_proj_inv = mat_proj.inverse();
+ var mat_scene_inv = mat_scene.inverse();
+
+ //enable (multiplicative) blending
+ this.stateManager.enable(gl.BLEND);
+ this.stateManager.blendFunc(gl.DST_COLOR, gl.ZERO);
+
+ for (var s=0; s<n; s++)
+ {
+ var startIndex = renderSplit[s];
+ var endIndex = renderSplit[s+1];
+
+ var currentLights = [];
+
+ for (k=startIndex; k<endIndex; k++)
+ currentLights[currentLights.length] = shadowedLights[k];
+
+ var sp = this.cache.getShadowRenderingShader(gl, currentLights);
+
+ this.stateManager.useProgram(sp);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._webgl.ppBuffer);
+ gl.vertexAttribPointer(sp.position, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ //bind depth texture (depth from camera view)
+ sp.sceneMap = 0;
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, scene._webgl.fboScene.tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ //compute inverse projection matrix
+ sp.inverseProj = mat_proj_inv.toGL();
+
+ //compute inverse view projection matrix
+ sp.inverseViewProj = mat_scene_inv.toGL();
+
+ var mat_light;
+ var lightMatrix;
+ var shadowIndex = 0;
+
+ for (var p=0, pn=currentLights.length; p<pn; p++) {
+ //get light matrices and shadow maps for current light
+ lightMatrix = lMatrices[p+startIndex];
+ mat_light = wctolc[p+startIndex];
+ shadowMaps = scene._webgl.fboShadow[p+startIndex];
+
+ numShadowMaps = mat_light.length;
+
+ for (i=0; i< numShadowMaps; i++){
+ gl.activeTexture(gl.TEXTURE1 + shadowIndex);
+ gl.bindTexture(gl.TEXTURE_2D, shadowMaps[i].tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ sp['light'+p+'_'+i+'_ShadowMap'] = shadowIndex+1;
+ sp['light'+p+'_'+i+'_Matrix'] = mat_light[i].toGL();
+ shadowIndex++;
+ }
+ sp['light'+p+'_ViewMatrix'] = lightMatrix.toGL();
+
+ //cascade depths for directional and spot light
+ if (!x3dom.isa(currentLights[p], x3dom.nodeTypes.PointLight)){
+ for (j=0; j< numShadowMaps; j++){
+ var numCascades = Math.max(1,Math.min(currentLights[p]._vf.shadowCascades,6));
+ var splitFactor = Math.max(0,Math.min(currentLights[p]._vf.shadowSplitFactor,1));
+ var splitOffset = Math.max(0,Math.min(currentLights[p]._vf.shadowSplitOffset,1));
+
+ var splitDepths = viewarea.getShadowSplitDepths(numCascades, splitFactor, splitOffset, false, mat_proj);
+ sp['light'+p+'_'+j+'_Split'] = splitDepths[j+1];
+ }
+ }
+
+ //assign light properties
+ var light_transform = mat_view.mult(currentLights[p].getCurrentTransform());
+ if(x3dom.isa(currentLights[p], x3dom.nodeTypes.DirectionalLight))
+ {
+ sp['light'+p+'_Type'] = 0.0;
+ sp['light'+p+'_On'] = (currentLights[p]._vf.on) ? 1.0 : 0.0;
+ sp['light'+p+'_Direction'] = light_transform.multMatrixVec(currentLights[p]._vf.direction).toGL();
+ sp['light'+p+'_Attenuation'] = [1.0, 1.0, 1.0];
+ sp['light'+p+'_Location'] = [1.0, 1.0, 1.0];
+ sp['light'+p+'_Radius'] = 0.0;
+ sp['light'+p+'_BeamWidth'] = 0.0;
+ sp['light'+p+'_CutOffAngle'] = 0.0;
+ sp['light'+p+'_ShadowIntensity'] = currentLights[p]._vf.shadowIntensity;
+ sp['light'+p+'_ShadowCascades'] = currentLights[p]._vf.shadowCascades;
+ sp['light'+p+'_ShadowOffset'] = Math.max(0.0,Math.min(1.0,currentLights[p]._vf.shadowOffset));
+ }
+ else if(x3dom.isa(currentLights[p], x3dom.nodeTypes.PointLight))
+ {
+ sp['light'+p+'_Type'] = 1.0;
+ sp['light'+p+'_On'] = (currentLights[p]._vf.on) ? 1.0 : 0.0;
+ sp['light'+p+'_Direction'] = [1.0, 1.0, 1.0];
+ sp['light'+p+'_Attenuation'] = currentLights[p]._vf.attenuation.toGL();
+ sp['light'+p+'_Location'] = light_transform.multMatrixPnt(currentLights[p]._vf.location).toGL();
+ sp['light'+p+'_Radius'] = currentLights[p]._vf.radius;
+ sp['light'+p+'_BeamWidth'] = 0.0;
+ sp['light'+p+'_CutOffAngle'] = 0.0;
+ sp['light'+p+'_ShadowIntensity'] = currentLights[p]._vf.shadowIntensity;
+ sp['light'+p+'_ShadowOffset'] = Math.max(0.0,Math.min(1.0,currentLights[p]._vf.shadowOffset));
+ }
+ else if(x3dom.isa(currentLights[p], x3dom.nodeTypes.SpotLight))
+ {
+ sp['light'+p+'_Type'] = 2.0;
+ sp['light'+p+'_On'] = (currentLights[p]._vf.on) ? 1.0 : 0.0;
+ sp['light'+p+'_Direction'] = light_transform.multMatrixVec(currentLights[p]._vf.direction).toGL();
+ sp['light'+p+'_Attenuation'] = currentLights[p]._vf.attenuation.toGL();
+ sp['light'+p+'_Location'] = light_transform.multMatrixPnt(currentLights[p]._vf.location).toGL();
+ sp['light'+p+'_Radius'] = currentLights[p]._vf.radius;
+ sp['light'+p+'_BeamWidth'] = currentLights[p]._vf.beamWidth;
+ sp['light'+p+'_CutOffAngle'] = currentLights[p]._vf.cutOffAngle;
+ sp['light'+p+'_ShadowIntensity'] = currentLights[p]._vf.shadowIntensity;
+ sp['light'+p+'_ShadowCascades'] = currentLights[p]._vf.shadowCascades;
+ sp['light'+p+'_ShadowOffset'] = Math.max(0.0,Math.min(1.0,currentLights[p]._vf.shadowOffset));
+ }
+ }
+
+ gl.drawArrays(gl.TRIANGLES,0,6);
+
+ //cleanup
+ var nk = shadowIndex + 1;
+ for (k=0; k<nk; k++) {
+ gl.activeTexture(gl.TEXTURE0 + k);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ }
+ gl.disableVertexAttribArray(sp.position);
+ }
+
+ this.stateManager.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+ };
+
+ /*****************************************************************************
+ * Blur texture associated with given fbo
+ *****************************************************************************/
+ Context.prototype.blurTex = function(gl, scene, targetFbo, filterSize)
+ {
+ if (filterSize <= 0)
+ return;
+ else if (filterSize < 5)
+ filterSize = 3;
+ else if (filterSize < 7)
+ filterSize = 5;
+ else
+ filterSize = 7;
+
+ //first pass (horizontal blur), result stored in fboBlur
+ var width = targetFbo.width;
+ var height = targetFbo.height;
+ var fboBlur = null;
+
+ for (var i=0, n=scene._webgl.fboBlur.length; i<n; i++)
+ if (height == scene._webgl.fboBlur[i].height) {
+ fboBlur = scene._webgl.fboBlur[i];
+ break; // THINKABOUTME
+ }
+
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, fboBlur.fbo);
+ this.stateManager.viewport(0, 0, width, height);
+
+ this.stateManager.enable(gl.BLEND);
+ this.stateManager.blendFunc(gl.ONE, gl.ZERO);
+ this.stateManager.disable(gl.CULL_FACE);
+ this.stateManager.disable(gl.DEPTH_TEST);
+
+ gl.clearColor(1.0, 1.0, 1.0, 0.0);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ var sp = this.cache.getShader(gl, x3dom.shader.BLUR);
+
+ this.stateManager.useProgram(sp);
+
+ //initialize Data for post processing
+ gl.bindBuffer(gl.ARRAY_BUFFER, scene._webgl.ppBuffer);
+ gl.vertexAttribPointer(sp.position, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(sp.position);
+
+ sp.pixelSizeHor = 1.0/width;
+ sp.pixelSizeVert = 1.0/height;
+ sp.filterSize = filterSize;
+ sp.horizontal = true;
+
+ sp.texture = 0;
+
+ //bind texture
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, targetFbo.tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.drawArrays(gl.TRIANGLES,0,6);
+
+ //second pass (vertical blur), result stored in targetFbo
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, targetFbo.fbo);
+
+ gl.clearColor(1.0, 1.0, 1.0, 0.0);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ sp.horizontal = false;
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, fboBlur.tex);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.drawArrays(gl.TRIANGLES,0,6);
+
+ //cleanup
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.disableVertexAttribArray(sp.position);
+ gl.flush();
+
+ this.stateManager.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+ this.stateManager.bindFramebuffer(gl.FRAMEBUFFER, null);
+ this.stateManager.viewport(0, 0, this.canvas.width, this.canvas.height);
+ };
+
+ return setupContext;
+
+})();
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+x3dom.bridge = {
+
+ setFlashReady: function (driver, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.isFlashReady = true;
+ x3dom.debug.logInfo('Flash is ready for rendering (' + driver + ')');
+ },
+
+ onMouseDown: function (x, y, button, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onMousePress(x3dCanvas.gl, x, y, button);
+ x3dCanvas.doc.needRender = true;
+ },
+
+ onMouseUp: function (x, y, button, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onMouseRelease(x3dCanvas.gl, x, y, button);
+ x3dCanvas.doc.needRender = true;
+ },
+
+ onMouseOver: function (x, y, button, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onMouseOver(x3dCanvas.gl, x, y, button);
+ x3dCanvas.doc.needRender = true;
+ },
+
+ onMouseOut: function (x, y, button, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onMouseOut(x3dCanvas.gl, x, y, button);
+ x3dCanvas.doc.needRender = true;
+ },
+
+ onDoubleClick: function (x, y, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onDoubleClick(x3dCanvas.gl, x, y);
+ x3dCanvas.doc.needRender = true;
+ x3dom.debug.logInfo("dblClick");
+ },
+
+ onMouseDrag: function (x, y, button, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onDrag(x3dCanvas.gl, x, y, button);
+ x3dCanvas.doc.needRender = true;
+ },
+
+ onMouseMove: function (x, y, button, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onMove(x3dCanvas.gl, x, y, button);
+ x3dCanvas.doc.needRender = true;
+ },
+
+ onMouseWheel: function (x, y, button, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ x3dCanvas.doc.onDrag(x3dCanvas.gl, x, y, button);
+ x3dCanvas.doc.needRender = true;
+ },
+
+ onKeyDown: function (charCode, canvas) {
+ var x3dCanvas = x3dom.canvases[canvas];
+ var keysEnabled = x3dCanvas.x3dElem.getAttribute("keysEnabled");
+ if (!keysEnabled || keysEnabled.toLowerCase() === "true") {
+ x3dCanvas.doc.onKeyPress(charCode);
+ }
+ x3dCanvas.doc.needRender = true;
+ },
+
+ setBBox: function (id, center, size) {
+ var shape = x3dom.nodeTypes.Shape.idMap.nodeID[id];
+ //shape._vf.bboxCenter.setValues( new x3dom.fields.SFVec3f(center.x,center.y,center.z) );
+ //shape._vf.bboxSize.setValues( new x3dom.fields.SFVec3f(size.x,size.y,size.z) );
+ },
+
+ setShapeDirty: function (id) {
+ var shape = x3dom.nodeTypes.Shape.idMap.nodeID[id];
+ shape.setAllDirty();
+ }
+};
+
+
+x3dom.gfx_flash = (function () {
+
+ /** Context
+ *
+ */
+ function Context(object, name, renderType) {
+ this.object = object;
+ this.name = name;
+ this.isAlreadySet = false;
+ this.renderType = renderType;
+ }
+
+ /** setup context
+ *
+ */
+ function setupContext(object, renderType) {
+
+ //Set max indexable coords
+ x3dom.Utils.maxIndexableCoords = 65535;
+
+ //Return new Context
+ return new Context(object, 'flash', renderType);
+ }
+
+ /** get context name
+ *
+ */
+ Context.prototype.getName = function () {
+ return this.name;
+ };
+
+ /** render scene
+ *
+ */
+ Context.prototype.renderScene = function (viewarea) {
+ //Get Scene from Viewarea
+ var scene = viewarea._scene;
+
+ var min = x3dom.fields.SFVec3f.MAX();
+ var max = x3dom.fields.SFVec3f.MIN();
+
+ var vol = scene.getVolume();
+ vol.getBounds(min, max);
+
+ scene._lastMin = min;
+ scene._lastMax = max;
+
+ viewarea._last_mat_view = x3dom.fields.SFMatrix4f.identity();
+ viewarea._last_mat_proj = x3dom.fields.SFMatrix4f.identity();
+ viewarea._last_mat_scene = x3dom.fields.SFMatrix4f.identity();
+
+ //Dirty HACK
+ var viewpoint = scene.getViewpoint();
+ if (viewpoint._vf.zNear == -1 || viewpoint._vf.zFar == -1) {
+ viewpoint._vf.zFar = 20000;
+ viewpoint._vf.zNear = 0.1;
+ }
+
+ var mat_view = viewarea.getViewMatrix();
+ var mat_proj = viewarea.getProjectionMatrix();
+ var mat_scene = mat_proj.mult(mat_view);
+
+ //Setup the flash scene
+ this.setupScene(scene, viewarea);
+
+ //Get background node
+ var background = scene.getBackground();
+
+ //Setup the background
+ this.setupBackground(background);
+
+ // Get the fog node
+ var fog = scene.getFog();
+
+ // Setup the fog
+ this.setupFog(fog);
+
+ //Collect all drawableObjects
+ scene.drawableCollection = null;
+ var env = scene.getEnvironment();
+
+ var drawableCollectionConfig = {
+ viewArea: viewarea,
+ sortTrans: env._vf.sortTrans,
+ viewMatrix: mat_view,
+ projMatrix: mat_proj,
+ sceneMatrix: mat_scene,
+ frustumCulling: false,
+ smallFeatureThreshold: false,
+ context: null,
+ gl: null
+ };
+
+ scene.drawableCollection = new x3dom.DrawableCollection(drawableCollectionConfig);
+ scene.collectDrawableObjects(x3dom.fields.SFMatrix4f.identity(), scene.drawableCollection, true, false, 0, []);
+
+ scene.drawableCollection.concat();
+
+ //Get Number of drawableObjects
+ var numDrawableObjects = scene.drawableCollection.length;
+
+ if (numDrawableObjects > 0) {
+ var RefList = [];
+
+ //Iterate over all Objects for setup
+ for (var i = 0; i < numDrawableObjects; i++) {
+ //Get object and transformation
+ var drawable = scene.drawableCollection.get(i);
+ var trafo = drawable.transform;
+ var obj3d = drawable.shape;
+
+ //Count shape references for DEF/USE
+ if (RefList[obj3d._objectID] != undefined) {
+ RefList[obj3d._objectID]++;
+ } else {
+ RefList[obj3d._objectID] = 0;
+ }
+
+ // TODO; move to addDrawable()
+ this.setupShape(obj3d, trafo, RefList[obj3d._objectID]);
+ }
+ }
+
+ //Render the flash scene
+ this.object.renderScene();
+ };
+
+ /** setup scene
+ *
+ */
+ Context.prototype.setupScene = function (scene, viewarea) {
+
+ //Set View-Matrix
+ var mat_view = viewarea.getViewMatrix();
+
+ // fire viewpointChanged event
+ if (!viewarea._last_mat_view.equals(mat_view)) {
+ var e_viewpoint = viewarea._scene.getViewpoint();
+ var e_eventType = "viewpointChanged";
+ /*TEST*/
+ try {
+ if (e_viewpoint._xmlNode &&
+ (e_viewpoint._xmlNode["on" + e_eventType] ||
+ e_viewpoint._xmlNode.hasAttribute("on" + e_eventType) ||
+ e_viewpoint._listeners[e_eventType])) {
+ var e_viewtrafo = e_viewpoint.getCurrentTransform();
+ e_viewtrafo = e_viewtrafo.inverse().mult(mat_view);
+
+ var e_mat = e_viewtrafo.inverse();
+
+ var e_rotation = new x3dom.fields.Quaternion(0, 0, 1, 0);
+ //e_rotation.setValue(e_mat);
+
+ var e_translation = e_mat.e3();
+
+ var e_event = {
+ target: e_viewpoint._xmlNode,
+ type: e_eventType,
+ matrix: e_viewtrafo,
+ position: e_translation,
+ orientation: e_rotation.toAxisAngle(),
+ cancelBubble: false,
+ stopPropagation: function () {
+ this.cancelBubble = true;
+ }
+ };
+
+ e_viewpoint.callEvtHandler(e_eventType, e_event);
+ }
+ }
+ catch (e_e) {
+ x3dom.debug.logException(e_e);
+ }
+ }
+
+ viewarea._last_mat_view = mat_view;
+
+ //Dirty HACK
+ var viewpoint = scene.getViewpoint();
+ //viewpoint._vf.zFar = 100;
+ //viewpoint._vf.zNear = 0.1;
+
+ var mat_proj = viewarea.getProjectionMatrix();
+
+ this.object.setViewpoint({ fov: viewpoint._vf.fov,
+ zFar: viewpoint._vf.zFar,
+ zNear: viewpoint._vf.zNear,
+ viewMatrix: mat_view.toGL(),
+ projectionMatrix: mat_proj.toGL() });
+
+ //Set HeadLight
+ var nav = scene.getNavigationInfo();
+ if (nav._vf.headlight) {
+ /*this.object.setLights( { idx: 0,
+ type: 0,
+ on: 1.0,
+ color: [1.0, 1.0, 1.0],
+ intensity: 1.0,
+ ambientIntensity: 0.0,
+ direction: [0.0, 0.0, 1.0],
+ attenuation: [1.0, 1.0, 1.0],
+ location: [1.0, 1.0, 1.0],
+ radius: 0.0,
+ beamWidth: 0.0,
+ cutOffAngle: 0.0 } );*/
+
+ this.object.setHeadLight({ id: -1,
+ on: 1.0,
+ color: [1.0, 1.0, 1.0],
+ intensity: 1.0,
+ ambientIntensity: 0.0,
+ direction: [0.0, 0.0, -1.0] });
+ }
+
+ //TODO Set Lights
+ if (this.renderType == "deferred") {
+ var lights = viewarea.getLights();
+ for (var i = 0; i < lights.length; i++) {
+ if (lights[i]._dirty) {
+
+ if (x3dom.isa(lights[i], x3dom.nodeTypes.DirectionalLight)) {
+ this.object.setDirectionalLight({ id: lights[i]._lightID,
+ on: lights[i]._vf.on,
+ color: lights[i]._vf.color.toGL(),
+ intensity: lights[i]._vf.intensity,
+ ambientIntensity: lights[i]._vf.ambientIntensity,
+ direction: lights[i]._vf.direction.toGL() });
+ }
+ else if (x3dom.isa(lights[i], x3dom.nodeTypes.PointLight)) {
+ var light_transform = mat_view.mult(lights[i].getCurrentTransform());
+
+ this.object.setPointLight({ id: lights[i]._lightID,
+ on: lights[i]._vf.on,
+ color: lights[i]._vf.color.toGL(),
+ intensity: lights[i]._vf.intensity,
+ ambientIntensity: lights[i]._vf.ambientIntensity,
+ attenuation: lights[i]._vf.attenuation.toGL(),
+ location: lights[i]._vf.location.toGL(),
+ radius: lights[i]._vf.radius });
+ }
+ else if (x3dom.isa(lights[i], x3dom.nodeTypes.SpotLight)) {
+ /*this.object.setSpotLight( { id: lights[i]._lightID,
+ on: lights[i]._vf.on,
+ color: lights[i]._vf.color.toGL(),
+ intensity: lights[i]._vf.color.toGL(),
+ ambientIntensity: lights[i]._vf.ambientIntensity,
+ direction: lights[i]._vf.direction.toGL(),
+ attenuation: lights[i]._vf.attenuation.toGL(),
+ location: lights[i]._vf.location.toGL(),
+ radius: lights[i]._vf.radius,
+ beamWidth: lights[i]._vf.beamWidth,
+ cutOffAngle: lights[i]._vf.cutOffAngle } );*/
+ }
+ lights[i]._dirty = false;
+ }
+ }
+ }
+ };
+
+ /** setup Background
+ *
+ */
+ Context.prototype.setupBackground = function (background) {
+ //If background dirty -> update
+ if (background._dirty) {
+ this.object.setBackground({ texURLs: background.getTexUrl(),
+ skyAngle: background._vf.skyAngle,
+ skyColor: background.getSkyColor().toGL(),
+ groundAngle: background._vf.groundAngle,
+ groundColor: background.getGroundColor().toGL(),
+ transparency: background.getTransparency() });
+ background._dirty = false;
+ }
+ };
+
+ /** setup Fog
+ *
+ */
+ Context.prototype.setupFog = function (fog) {
+ if (!fog || !fog._vf || fog._vf.visibilityRange <= 0.0) {
+ this.object.setFog({
+ color: null,
+ visibilityRange: -1.0,
+ fogType: -1.0
+ });
+ return;
+ };
+
+ this.object.setFog({
+ color: fog._vf.color.toGL(),
+ visibilityRange: fog._vf.visibilityRange,
+ fogType: (fog._vf.fogType === "LINEAR") ? 0.0 : 1.0
+ });
+ };
+
+ /** setup Shape
+ *
+ */
+ Context.prototype.setupShape = function (shape, trafo, refID) {
+
+ //Check shape geometry type
+ if (x3dom.isa(shape._cf.geometry.node, x3dom.nodeTypes.PointSet)) {
+ x3dom.debug.logError("Flash backend doesn't support PointSets yet");
+ } else if (x3dom.isa(shape._cf.geometry.node, x3dom.nodeTypes.IndexedLineSet)) {
+ x3dom.debug.logError("Flash backend doesn't support LineSets yet");
+ } else if (x3dom.isa(shape._cf.geometry.node, x3dom.nodeTypes.Text)) {
+ this.setupText(shape, trafo, refID);
+ } else {
+ this.setupIndexedFaceSet(shape, trafo, refID);
+ }
+ };
+
+ Context.prototype.setupIndexedFaceSet = function (shape, trafo, refID) {
+ //Set modelMatrix
+ this.object.setMeshTransform({ id: shape._objectID,
+ refID: refID,
+ transform: trafo.toGL() });
+ if (refID == 0) {
+ //Check if is ImageGeometry or BinaryGeometry
+ var isImageGeometry = x3dom.isa(shape._cf.geometry.node, x3dom.nodeTypes.ImageGeometry);
+ var isBinaryGeometry = x3dom.isa(shape._cf.geometry.node, x3dom.nodeTypes.BinaryGeometry);
+
+ //Check if Appearance is available
+ var appearance = shape._cf.appearance.node;
+ var sortType = (appearance) ? shape._cf.appearance.node._vf.sortType : "auto";
+ var sortKey = (appearance) ? shape._cf.appearance.node._vf.sortKey : 0
+
+ //Set Mesh Properties
+ if (isImageGeometry) {
+ this.object.setMeshProperties({ id: shape._objectID,
+ type: "ImageGeometry",
+ sortType: sortType,
+ sortKey: sortKey,
+ solid: shape.isSolid(),
+ bboxMin: shape._cf.geometry.node.getMin().toGL(),
+ bboxMax: shape._cf.geometry.node.getMax().toGL(),
+ bboxCenter: shape._cf.geometry.node.getCenter().toGL(),
+ primType: shape._cf.geometry.node._vf.primType,
+ vertexCount: shape._cf.geometry.node._vf.vertexCount });
+ } else if (isBinaryGeometry) {
+ this.object.setMeshProperties({ id: shape._objectID,
+ type: "BinaryGeometry",
+ sortType: sortType,
+ sortKey: sortKey,
+ solid: shape.isSolid(),
+ bgCenter: shape._cf.geometry.node._vf.position.toGL(),
+ bgSize: shape._cf.geometry.node._vf.size.toGL(),
+ bboxCenter: shape._cf.geometry.node.getCenter().toGL(),
+ primType: shape._cf.geometry.node._vf.primType,
+ vertexCount: shape._cf.geometry.node._vf.vertexCount });
+ } else {
+ this.object.setMeshProperties({ id: shape._objectID,
+ type: "Default",
+ sortType: sortType,
+ sortKey: sortKey,
+ solid: shape.isSolid() });
+ }
+
+ //Set indices
+ if (shape._dirty.indexes === true) {
+ if (isImageGeometry) {
+ //TODO new flash IG implementation
+ /*this.object.setMeshIndices( { id: shape._objectID,
+ idx: 0,
+ indices: shape._cf.geometry.node.getIndexTextureURL() } );*/
+ } else if (isBinaryGeometry) {
+ this.object.setMeshIndices({ id: shape._objectID,
+ idx: 0,
+ indices: shape._nameSpace.getURL(shape._cf.geometry.node._vf.index) });
+ } else {
+ //If Mesh is multi indexed we have to split it in Flash
+ if (shape._cf.geometry.node._mesh._multiIndIndices && shape._cf.geometry.node._mesh._multiIndIndices.length)
+ {
+ shape._cf.geometry.node._mesh.splitMesh(3, true);
+ }
+
+ for (var i = 0; i < shape._cf.geometry.node._mesh._indices.length; i++) {
+ this.object.setMeshIndices({ id: shape._objectID,
+ idx: i,
+ indices: shape._cf.geometry.node._mesh._indices[i] });
+ }
+ }
+ shape._dirty.indexes = false;
+ }
+
+ //Set vertices
+ if (shape._dirty.positions === true) {
+ if (isImageGeometry) {
+ this.object.setMeshVertices({ id: shape._objectID,
+ idx: 0,
+ //TODO new flash IG implementation coords: shape._cf.geometry.node.getCoordinateTextureURLs(),
+ coordinateTexture0: shape._cf.geometry.node.getCoordinateTextureURL(0),
+ coordinateTexture1: shape._cf.geometry.node.getCoordinateTextureURL(1) });
+ } else if (isBinaryGeometry) {
+ this.object.setMeshVertices({ id: shape._objectID,
+ idx: 0,
+ interleaved: shape._cf.geometry.node._hasStrideOffset,
+ vertices: shape._nameSpace.getURL(shape._cf.geometry.node._vf.coord),
+ normals: shape._nameSpace.getURL(shape._cf.geometry.node._vf.normal),
+ texCoords: shape._nameSpace.getURL(shape._cf.geometry.node._vf.texCoord),
+ colors: shape._nameSpace.getURL(shape._cf.geometry.node._vf.color),
+ numColorComponents: shape._cf.geometry.node._mesh._numColComponents,
+ numNormalComponents: shape._cf.geometry.node._mesh._numNormComponents,
+ vertexType: shape._cf.geometry.node._vf.coordType,
+ normalType: shape._cf.geometry.node._vf.normalType,
+ texCoordType: shape._cf.geometry.node._vf.texCoordType,
+ colorType: shape._cf.geometry.node._vf.colorType,
+ vertexStrideOffset: shape._coordStrideOffset,
+ normalStrideOffset: shape._normalStrideOffset,
+ texCoordStrideOffset: shape._texCoordStrideOffset,
+ colorStrideOffset: shape._colorStrideOffset });
+ } else {
+ for (var i = 0; i < shape._cf.geometry.node._mesh._positions.length; i++) {
+ this.object.setMeshVertices({ id: shape._objectID,
+ idx: i,
+ vertices: shape._cf.geometry.node._mesh._positions[i] });
+ }
+ }
+ shape._dirty.positions = false;
+ }
+
+ //Set normals
+ if (shape._dirty.normals === true) {
+ if (isImageGeometry) {
+ this.object.setMeshNormals({ id: shape._objectID,
+ idx: 0,
+ //TODO new flash IG implementation normals: shape._cf.geometry.node.getNormalTextureURLs(),
+ normalTexture: shape._cf.geometry.node.getNormalTextureURL() });
+ } else if (isBinaryGeometry) {
+ if (!shape._cf.geometry.node._hasStrideOffset) {
+ this.object.setMeshNormals({ id: shape._objectID,
+ idx: 0,
+ normals: shape._nameSpace.getURL(shape._cf.geometry.node._vf.normal) });
+ }
+ } else {
+ if (shape._cf.geometry.node._mesh._normals[0].length) {
+ for (var i = 0; i < shape._cf.geometry.node._mesh._normals.length; i++) {
+ this.object.setMeshNormals({ id: shape._objectID,
+ idx: i,
+ normals: shape._cf.geometry.node._mesh._normals[i] });
+ }
+ }
+ }
+ shape._dirty.normals = false;
+ }
+
+ //Set colors
+ if (shape._dirty.colors === true) {
+ if (isImageGeometry) {
+ this.object.setMeshColors({ id: shape._objectID,
+ idx: 0,
+ colorTexture: shape._cf.geometry.node.getColorTextureURL(),
+ components: shape._cf.geometry.node._mesh._numColComponents });
+ } else if (isBinaryGeometry) {
+ if (!shape._cf.geometry.node._hasStrideOffset) {
+ this.object.setMeshColors({ id: shape._objectID,
+ idx: 0,
+ colors: shape._nameSpace.getURL(shape._cf.geometry.node._vf.color),
+ components: shape._cf.geometry.node._mesh._numColComponents });
+ }
+ } else {
+ if (shape._cf.geometry.node._mesh._colors[0].length) {
+ for (var i = 0; i < shape._cf.geometry.node._mesh._colors.length; i++) {
+ this.object.setMeshColors({ id: shape._objectID,
+ idx: i,
+ colors: shape._cf.geometry.node._mesh._colors[i],
+ components: shape._cf.geometry.node._mesh._numColComponents });
+ }
+ }
+ }
+ shape._dirty.colors = false;
+ }
+
+ //Set texture coordinates
+ if (shape._dirty.texcoords === true) {
+ if (isImageGeometry) {
+ this.object.setMeshTexCoords({ id: shape._objectID,
+ idx: 0,
+ texCoordTexture: shape._cf.geometry.node.getTexCoordTextureURL() });
+ } else if (isBinaryGeometry) {
+ if (!shape._cf.geometry.node._hasStrideOffset) {
+ this.object.setMeshTexCoords({ id: shape._objectID,
+ idx: 0,
+ texCoords: shape._nameSpace.getURL(shape._cf.geometry.node._vf.texCoord) });
+ }
+ } else {
+ if (shape._cf.geometry.node._mesh._texCoords[0].length) {
+ for (var i = 0; i < shape._cf.geometry.node._mesh._texCoords.length; i++) {
+ this.object.setMeshTexCoords({ id: shape._objectID,
+ idx: i,
+ texCoords: shape._cf.geometry.node._mesh._texCoords[i] });
+ }
+ }
+ }
+ shape._dirty.texcoords = false;
+ }
+
+ //Set material
+ if (shape._dirty.material === true) {
+ if (appearance) {
+ var material = shape._cf.appearance.node._cf.material.node;
+ if (material) {
+ this.object.setMeshMaterial({ id: shape._objectID,
+ ambientIntensity: material._vf.ambientIntensity,
+ diffuseColor: material._vf.diffuseColor.toGL(),
+ emissiveColor: material._vf.emissiveColor.toGL(),
+ shininess: material._vf.shininess,
+ specularColor: material._vf.specularColor.toGL(),
+ transparency: material._vf.transparency });
+ }
+ }
+ shape._dirty.material = false;
+ }
+
+ //Set Texture
+ if (shape._dirty.texture === true) {
+ if (appearance) {
+ var texTrafo = null;
+ if (appearance._cf.textureTransform.node) {
+ texTrafo = appearance.texTransformMatrix().toGL();
+ }
+
+ var texture = shape._cf.appearance.node._cf.texture.node;
+
+ if (texture) {
+ if (x3dom.isa(texture, x3dom.nodeTypes.PixelTexture)) {
+ this.object.setPixelTexture({ id: shape._objectID,
+ width: texture._vf.image.width,
+ height: texture._vf.image.height,
+ comp: texture._vf.image.comp,
+ pixels: texture._vf.image.toGL() });
+ } else if (x3dom.isa(texture, x3dom.nodeTypes.ComposedCubeMapTexture)) {
+ this.object.setCubeTexture({ id: shape._objectID,
+ texURLs: texture.getTexUrl() });
+ } else if (texture._isCanvas && texture._canvas) {
+ this.object.setCanvasTexture({ id: shape._objectID,
+ width: texture._canvas.width,
+ height: texture._canvas.height,
+ dataURL: texture._canvas.toDataURL() });
+ } else if (x3dom.isa(texture, x3dom.nodeTypes.MultiTexture)) {
+ x3dom.debug.logError("Flash backend doesn't support MultiTextures yet");
+ } else if (x3dom.isa(texture, x3dom.nodeTypes.MovieTexture)) {
+ x3dom.debug.logError("Flash backend doesn't support MovieTextures yet");
+ } else {
+ this.object.setMeshTexture({ id: shape._objectID,
+ origChannelCount: texture._vf.origChannelCount,
+ repeatS: texture._vf.repeatS,
+ repeatT: texture._vf.repeatT,
+ url: texture._vf.url[0],
+ transform: texTrafo });
+ }
+ } else {
+ this.object.removeTexture({ id: shape._objectID });
+ }
+ }
+ shape._dirty.texture = false;
+ }
+
+ //Set sphere mapping
+ if (shape._cf.geometry.node._cf.texCoord !== undefined &&
+ shape._cf.geometry.node._cf.texCoord.node !== null &&
+ !x3dom.isa(shape._cf.geometry.node._cf.texCoord.node, x3dom.nodeTypes.X3DTextureNode) &&
+ shape._cf.geometry.node._cf.texCoord.node._vf.mode) {
+ var texMode = shape._cf.geometry.node._cf.texCoord.node._vf.mode;
+ if (texMode.toLowerCase() == "sphere") {
+ this.object.setSphereMapping({ id: shape._objectID,
+ sphereMapping: 1 });
+ }
+ else {
+ this.object.setSphereMapping({ id: shape._objectID,
+ sphereMapping: 0 });
+ }
+ }
+ else {
+ this.object.setSphereMapping({ id: shape._objectID,
+ sphereMapping: 0 });
+ }
+ }
+ };
+
+ Context.prototype.setupText = function (shape, trafo, refID) {
+ //Set modelMatrix
+ this.object.setMeshTransform({ id: shape._objectID,
+ refID: refID,
+ transform: trafo.toGL() });
+
+ if (refID == 0) {
+
+ /*this.object.setMeshProperties( { id: shape._objectID,
+ type: "Text",
+ solid: shape.isSolid() } );*/
+
+ //Check if Appearance is available
+ var appearance = shape._cf.appearance.node;
+ var sortType = (appearance) ? shape._cf.appearance.node._vf.sortType : "auto";
+ var sortKey = (appearance) ? shape._cf.appearance.node._vf.sortKey : 0
+
+ if (shape._dirty.text === true) {
+ var fontStyleNode = shape._cf.geometry.node._cf.fontStyle.node;
+ if (fontStyleNode === null) {
+ this.object.setMeshProperties({ id: shape._objectID,
+ type: "Text",
+ sortType: sortType,
+ sortKey: sortKey,
+ solid: shape.isSolid(),
+ text: shape._cf.geometry.node._vf.string,
+ fontFamily: ['SERIF'],
+ fontStyle: "PLAIN",
+ fontAlign: "BEGIN",
+ fontSize: 32,
+ fontSpacing: 1.0,
+ fontHorizontal: true,
+ fontLanguage: "",
+ fontLeftToRight: true,
+ fontTopToBottom: true });
+ } else {
+ this.object.setMeshProperties({ id: shape._objectID,
+ type: "Text",
+ sortType: sortType,
+ sortKey: sortKey,
+ solid: shape.isSolid(),
+ text: shape._cf.geometry.node._vf.string,
+ fontFamily: fontStyleNode._vf.family.toString(),
+ fontStyle: fontStyleNode._vf.style.toString(),
+ fontAlign: fontStyleNode._vf.justify.toString(),
+ fontSize: fontStyleNode._vf.size,
+ fontSpacing: fontStyleNode._vf.spacing,
+ fontHorizontal: fontStyleNode._vf.horizontal,
+ fontLanguage: fontStyleNode._vf.language,
+ fontLeftToRight: fontStyleNode._vf.leftToRight,
+ fontTopToBottom: fontStyleNode._vf.topToBottom });
+ }
+ shape._dirty.text = false;
+ }
+
+ if (shape._dirty.material === true) {
+ if (appearance) {
+ var material = shape._cf.appearance.node._cf.material.node;
+ if (material) {
+ this.object.setMeshMaterial({ id: shape._objectID,
+ ambientIntensity: material._vf.ambientIntensity,
+ diffuseColor: material._vf.diffuseColor.toGL(),
+ emissiveColor: material._vf.emissiveColor.toGL(),
+ shininess: material._vf.shininess,
+ specularColor: material._vf.specularColor.toGL(),
+ transparency: material._vf.transparency });
+ }
+ }
+ shape._dirty.material = false;
+ }
+ }
+ };
+
+
+ /** pick Value
+ *
+ */
+ Context.prototype.pickValue = function (viewarea, x, y, viewMat, sceneMat) {
+ var scene = viewarea._scene;
+
+ // method requires that scene has already been rendered at least once
+ if (this.object === null || scene === null || scene.drawableCollection === undefined || !scene.drawableCollection || scene._vf.pickMode.toLowerCase() === "box") {
+ return false;
+ }
+
+ var pickMode = (scene._vf.pickMode.toLowerCase() === "color") ? 1 :
+ ((scene._vf.pickMode.toLowerCase() === "texcoord") ? 2 : 0);
+
+ var data = this.object.pickValue({ pickMode: pickMode });
+
+ if (data.objID > 0) {
+ viewarea._pickingInfo.pickPos = new x3dom.fields.SFVec3f(data.pickPosX, data.pickPosY, data.pickPosZ);
+ viewarea._pickingInfo.pickObj = x3dom.nodeTypes.Shape.idMap.nodeID[data.objID];
+ } else {
+ viewarea._pickingInfo.pickObj = null;
+ viewarea._pickingInfo.lastClickObj = null;
+ }
+
+ return true;
+ };
+
+ /** shutdown
+ *
+ */
+ Context.prototype.shutdown = function (viewarea) {
+ // TODO?
+ };
+
+ //Return the setup context function
+ return setupContext;
+})();
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+/// NodeNameSpace constructor
+x3dom.NodeNameSpace = function (name, document) {
+ this.name = name;
+ this.doc = document;
+ this.baseURL = "";
+ this.defMap = {};
+ this.parent = null;
+ this.childSpaces = [];
+};
+
+x3dom.NodeNameSpace.prototype.addNode = function (node, name) {
+ this.defMap[name] = node;
+ node._nameSpace = this;
+};
+
+x3dom.NodeNameSpace.prototype.removeNode = function (name) {
+ var node = name ? this.defMap[name] : null;
+ if (node) {
+ delete this.defMap[name];
+ node._nameSpace = null;
+ }
+};
+
+x3dom.NodeNameSpace.prototype.getNamedNode = function (name) {
+ return this.defMap[name];
+};
+
+x3dom.NodeNameSpace.prototype.getNamedElement = function (name) {
+ var node = this.defMap[name];
+ return (node ? node._xmlNode : null);
+};
+
+x3dom.NodeNameSpace.prototype.addSpace = function (space) {
+ this.childSpaces.push(space);
+ space.parent = this;
+};
+
+x3dom.NodeNameSpace.prototype.removeSpace = function (space) {
+ space.parent = null;
+ for (var it=0; it<this.childSpaces.length; it++) {
+ if (this.childSpaces[it] == space) {
+ this.childSpaces.splice(it, 1);
+ }
+ }
+};
+
+x3dom.NodeNameSpace.prototype.setBaseURL = function (url) {
+ var i = url.lastIndexOf ("/");
+ this.baseURL = (i >= 0) ? url.substr(0,i+1) : "";
+
+ x3dom.debug.logInfo("setBaseURL: " + this.baseURL);
+};
+
+x3dom.NodeNameSpace.prototype.getURL = function (url) {
+ if (url === undefined || !url.length) {
+ return "";
+ }
+ else {
+ return ((url[0] === '/') || (url.indexOf(":") >= 0)) ? url : (this.baseURL + url);
+ }
+};
+
+// helper to check an element's attribute
+x3dom.hasElementAttribute = function(attrName)
+{
+ var ok = this.__hasAttribute(attrName);
+ if (!ok && attrName) {
+ ok = this.__hasAttribute(attrName.toLowerCase());
+ }
+ return ok;
+};
+
+// helper to get an element's attribute
+x3dom.getElementAttribute = function(attrName)
+{
+ var attrib = this.__getAttribute(attrName);
+ if (!attrib && attrib != "" && attrName) {
+ attrib = this.__getAttribute(attrName.toLowerCase());
+ }
+
+ if (attrib || !this._x3domNode) {
+ return attrib;
+ }
+ else {
+ return this._x3domNode._vf[attrName];
+ }
+};
+
+// helper to set an element's attribute
+x3dom.setElementAttribute = function(attrName, newVal)
+{
+ //var prevVal = this.getAttribute(attrName);
+ this.__setAttribute(attrName, newVal);
+ //newVal = this.getAttribute(attrName);
+
+ var x3dNode = this._x3domNode;
+ if (x3dNode) {
+ x3dNode.updateField(attrName, newVal);
+ x3dNode._nameSpace.doc.needRender = true;
+ }
+};
+
+/**
+ * Returns the value of the field with the given name.
+ * The value is returned as an object of the corresponding field type.
+ *
+ * @param {String} fieldName - the name of the field
+ */
+x3dom.getFieldValue = function(fieldName)
+{
+ var x3dNode = this._x3domNode;
+
+ if (x3dNode && x3dNode._vf[fieldName]) {
+ return x3dNode._vf[fieldName].copy();
+ }
+
+ return null;
+};
+
+
+/**
+ * Sets the value of the field with the given name to the given value.
+ * The value is specified as an object of the corresponding field type.
+ *
+ * @param {String} fieldName - the name of the field where the value should be set
+ * @param {String} fieldvalue - the new field value
+ */
+x3dom.setFieldValue = function(fieldName, fieldvalue) {
+ var x3dNode = this._x3domNode;
+ if (x3dNode && x3dNode._vf[fieldName]) {
+
+ // SF/MF object types are cloned based on a copy function
+ if(fieldvalue instanceof Object && 'copy' in fieldvalue)
+ {
+ x3dNode._vf[fieldName] = fieldvalue.copy();
+ }
+ //f.i. SFString SFBool aren't objects
+ else
+ x3dNode._vf[fieldName] = fieldvalue;
+
+ x3dNode.fieldChanged(fieldName);
+ x3dNode._nameSpace.doc.needRender = true;
+ }
+};
+
+
+/**
+ * Returns the field object of the field with the given name.
+ * The returned object is no copy, but instead a reference to X3DOM's internal field object.
+ * Changes to this object should be committed using the returnFieldRef function.
+ * Note: this only works for fields with pointer types such as MultiFields!
+ *
+ * @param {String} fieldName - the name of the field
+ */
+x3dom.requestFieldRef = function(fieldName)
+{
+ var x3dNode = this._x3domNode;
+ if (x3dNode && x3dNode._vf[fieldName])
+ {
+ return x3dNode._vf[fieldName];
+ }
+
+ return null;
+};
+
+
+/**
+ * Commits all changes made to the internal field object of the field with the given name.
+ * This must be done in order to notify X3DOM to process all related changes internally.
+ *
+ * @param {String} fieldName - the name of the field
+ */
+x3dom.releaseFieldRef = function(fieldName)
+{
+ var x3dNode = this._x3domNode;
+ if (x3dNode && x3dNode._vf[fieldName])
+ {
+ x3dNode.fieldChanged(fieldName);
+ x3dNode._nameSpace.doc.needRender = true;
+ }
+};
+
+
+x3dom.NodeNameSpace.prototype.setupTree = function (domNode) {
+ var n = null;
+
+ if (x3dom.isX3DElement(domNode)) {
+
+ // return if it is already initialized
+ if (domNode._x3domNode) {
+ x3dom.debug.logWarning('Tree is already initialized');
+ return null;
+ }
+
+ // workaround since one cannot find out which handlers are registered
+ if ( (domNode.tagName !== undefined) &&
+ (!domNode.__addEventListener) && (!domNode.__removeEventListener) )
+ {
+ // helper to track an element's listeners
+ domNode.__addEventListener = domNode.addEventListener;
+ domNode.addEventListener = function(type, func, phase) {
+ if (!this._x3domNode._listeners[type]) {
+ this._x3domNode._listeners[type] = [];
+ }
+ this._x3domNode._listeners[type].push(func);
+
+ //x3dom.debug.logInfo('addEventListener for ' + this.tagName + ".on" + type);
+ this.__addEventListener(type, func, phase);
+ };
+
+ domNode.__removeEventListener = domNode.removeEventListener;
+ domNode.removeEventListener = function(type, func, phase) {
+ var list = this._x3domNode._listeners[type];
+ if (list) {
+ for (var it=0; it<list.length; it++) {
+ if (list[it] == func) {
+ list.splice(it, 1);
+ //x3dom.debug.logInfo('removeEventListener for ' +
+ // this.tagName + ".on" + type);
+ }
+ }
+ }
+ this.__removeEventListener(type, func, phase);
+ };
+ }
+
+ // TODO (?): dynamic update of USE attribute during runtime
+ if (domNode.hasAttribute('USE') || domNode.hasAttribute('use'))
+ {
+ //fix usage of lowercase 'use'
+ if (!domNode.hasAttribute('USE')) {
+ domNode.setAttribute('USE', domNode.getAttribute('use'));
+ }
+
+ n = this.defMap[domNode.getAttribute('USE')];
+ if (!n) {
+ var nsName = domNode.getAttribute('USE').split('__');
+
+ if (nsName.length >= 2) {
+ var otherNS = this;
+ while (otherNS) {
+ if (otherNS.name == nsName[0])
+ n = otherNS.defMap[nsName[1]];
+ if (n)
+ otherNS = null;
+ else
+ otherNS = otherNS.parent;
+ }
+ if (!n) {
+ n = null;
+ x3dom.debug.logWarning('Could not USE: ' + domNode.getAttribute('USE'));
+ }
+ }
+ }
+ if (n) {
+ domNode._x3domNode = n;
+ }
+ return n;
+ }
+ else {
+ // check and create ROUTEs
+ if (domNode.localName.toLowerCase() === 'route') {
+ var route = domNode;
+ var fnAtt = route.getAttribute('fromNode') || route.getAttribute('fromnode');
+ var tnAtt = route.getAttribute('toNode') || route.getAttribute('tonode');
+ var fromNode = this.defMap[fnAtt];
+ var toNode = this.defMap[tnAtt];
+ if (! (fromNode && toNode)) {
+ x3dom.debug.logWarning("Broken route - can't find all DEFs for " + fnAtt + " -> " + tnAtt);
+ }
+ else {
+ //x3dom.debug.logInfo("ROUTE: from=" + fromNode._DEF + ", to=" + toNode._DEF);
+ fnAtt = route.getAttribute('fromField') || route.getAttribute('fromfield');
+ tnAtt = route.getAttribute('toField') || route.getAttribute('tofield');
+ fromNode.setupRoute(fnAtt, toNode, tnAtt);
+ // Store reference to namespace for being able to remove route later on
+ route._nodeNameSpace = this;
+ }
+ return null;
+ }
+
+ //attach X3DOM's custom field interface functions
+ domNode.requestFieldRef = x3dom.requestFieldRef;
+ domNode.releaseFieldRef = x3dom.releaseFieldRef;
+ domNode.getFieldValue = x3dom.getFieldValue;
+ domNode.setFieldValue = x3dom.setFieldValue;
+
+ // find the NodeType for the given dom-node
+ var nodeType = x3dom.nodeTypesLC[domNode.localName.toLowerCase()];
+ if (nodeType === undefined) {
+ x3dom.debug.logWarning("Unrecognised X3D element &lt;" + domNode.localName + "&gt;.");
+ }
+ else {
+ //active workaround for missing DOMAttrModified support
+ if ( (x3dom.userAgentFeature.supportsDOMAttrModified === false)
+ && (domNode instanceof Element) ) {
+ if (domNode.setAttribute && !domNode.__setAttribute) {
+ domNode.__setAttribute = domNode.setAttribute;
+ domNode.setAttribute = x3dom.setElementAttribute;
+ }
+
+ if (domNode.getAttribute && !domNode.__getAttribute) {
+ domNode.__getAttribute = domNode.getAttribute;
+ domNode.getAttribute = x3dom.getElementAttribute;
+ }
+
+ if (domNode.hasAttribute && !domNode.__hasAttribute) {
+ domNode.__hasAttribute = domNode.hasAttribute;
+ domNode.hasAttribute = x3dom.hasElementAttribute;
+ }
+ }
+
+ // create x3domNode
+ var ctx = {
+ doc: this.doc,
+ xmlNode: domNode,
+ nameSpace: this
+ };
+ n = new nodeType(ctx);
+
+ // find and store/link _DEF name
+ if (domNode.hasAttribute('DEF')) {
+ n._DEF = domNode.getAttribute('DEF');
+ this.defMap[n._DEF] = n;
+ }
+ else {
+ if (domNode.hasAttribute('id')) {
+ n._DEF = domNode.getAttribute('id');
+ this.defMap[n._DEF] = n;
+ }
+ }
+
+ // add experimental highlighting functionality
+ if (domNode.highlight === undefined)
+ {
+ domNode.highlight = function(enable, colorStr) {
+ var color = x3dom.fields.SFColor.parse(colorStr);
+ this._x3domNode.highlight(enable, color);
+ this._x3domNode._nameSpace.doc.needRender = true;
+ };
+ }
+
+ // link both DOM-Node and Scene-graph-Node
+ n._xmlNode = domNode;
+ domNode._x3domNode = n;
+
+ // call children
+ var that = this;
+ Array.forEach ( domNode.childNodes, function (childDomNode) {
+ var c = that.setupTree(childDomNode);
+ if (c) {
+ n.addChild(c, childDomNode.getAttribute("containerField"));
+ }
+ } );
+
+ n.nodeChanged();
+ return n;
+ }
+ }
+ }
+ else if (domNode.localName) {
+ // be nice to users who use nodes not (yet) known to the system
+ x3dom.debug.logWarning("Unrecognised X3D element &lt;" + domNode.localName + "&gt;.");
+ n = null;
+ }
+
+ return n;
+};
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### X3DNode ###
+x3dom.registerNodeType(
+ "X3DNode",
+ "Core",
+ defineClass(null,
+ /**
+ * Constructor for X3DNode
+ * @constructs x3dom.nodeTypes.X3DNode
+ * @x3d 3.3
+ * @component Core
+ * @status experimental
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all nodes in the X3D system.
+ */
+ function (ctx) {
+ // reference to DOM element
+ this._xmlNode = null;
+
+ // holds a link to the node name
+ this._DEF = null;
+
+ // links the nameSpace
+ this._nameSpace = (ctx && ctx.nameSpace) ? ctx.nameSpace : null;
+
+ // holds all value fields (e.g. SFFloat, MFVec3f, ...)
+ this._vf = {};
+ this._vfFieldTypes = {};
+
+ // holds all child fields ( SFNode and MFNode )
+ this._cf = {};
+ this._cfFieldTypes = {};
+
+ this._fieldWatchers = {};
+ this._routes = {};
+
+ this._listeners = {};
+
+ this._parentNodes = [];
+
+ // FIXME; should be removed and handled by _cf methods
+ this._childNodes = [];
+
+
+ /**
+ * Field to add metadata information
+ * @var {x3dom.fields.SFNode} metadata
+ * @memberof x3dom.nodeTypes.X3DNode
+ * @initvalue X3DMetadataObject
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('metadata', x3dom.nodeTypes.X3DMetadataObject);
+
+ },
+ {
+ type: function () {
+ return this.constructor;
+ },
+
+ typeName: function () {
+ return this.constructor._typeName;
+ },
+
+ addChild: function (node, containerFieldName) {
+ if (node) {
+ var field = null;
+ if (containerFieldName) {
+ field = this._cf[containerFieldName];
+ }
+ else {
+ for (var fieldName in this._cf) {
+ if (this._cf.hasOwnProperty(fieldName)) {
+ var testField = this._cf[fieldName];
+ if (x3dom.isa(node,testField.type)) {
+ field = testField;
+ break;
+ }
+ }
+ }
+ }
+ if (field && field.addLink(node)) {
+ node._parentNodes.push(this);
+ this._childNodes.push(node);
+ node.parentAdded(this);
+ return true;
+ }
+ }
+ return false;
+ },
+
+ removeChild: function (node) {
+ if (node) {
+ for (var fieldName in this._cf) {
+ if (this._cf.hasOwnProperty(fieldName)) {
+ var field = this._cf[fieldName];
+ if (field.rmLink(node)) {
+ for (var i = node._parentNodes.length - 1; i >= 0; i--) {
+ if (node._parentNodes[i] === this) {
+ node._parentNodes.splice(i, 1);
+ node.parentRemoved(this);
+ }
+ }
+ for (var j = this._childNodes.length - 1; j >= 0; j--) {
+ if (this._childNodes[j] === node) {
+ node.onRemove();
+ this._childNodes.splice(j, 1);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ },
+
+ onRemove: function() {
+ // to be overwritten by concrete classes
+ },
+
+ parentAdded: function(parent) {
+ // to be overwritten by concrete classes
+ },
+
+ parentRemoved: function(parent) {
+ // attention: overwritten by concrete classes
+ for (var i=0, n=this._childNodes.length; i<n; i++) {
+ if (this._childNodes[i]) {
+ this._childNodes[i].parentRemoved(this);
+ }
+ }
+ },
+
+ getCurrentTransform: function () {
+ if (this._parentNodes.length >= 1) {
+ return this.transformMatrix(this._parentNodes[0].getCurrentTransform());
+ }
+ else {
+ return x3dom.fields.SFMatrix4f.identity();
+ }
+ },
+
+ transformMatrix: function (transform) {
+ return transform;
+ },
+
+ getVolume: function () {
+ //x3dom.debug.logWarning("Called getVolume for unbounded node!");
+ return null;
+ },
+
+ invalidateVolume: function() {
+ // overwritten
+ },
+
+ invalidateCache: function() {
+ // overwritten
+ },
+
+ volumeValid: function() {
+ return false;
+ },
+
+ // Collects all objects to be drawn
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes) {
+ // explicitly do nothing on collect traversal for (most) nodes
+ },
+
+ highlight: function(enable, color)
+ {
+ if (this._vf.hasOwnProperty("diffuseColor"))
+ {
+ if (enable) {
+ if (this._actDiffuseColor === undefined) {
+ this._actDiffuseColor = new x3dom.fields.SFColor();
+ this._highlightOn = false;
+ }
+
+ if (!this._highlightOn) {
+ this._actDiffuseColor.setValues(this._vf.diffuseColor);
+ this._highlightOn = true;
+ }
+ this._vf.diffuseColor.setValues(color);
+ }
+ else {
+ if (this._actDiffuseColor !== undefined) {
+ this._vf.diffuseColor.setValues(this._actDiffuseColor);
+ this._highlightOn = false;
+ // new/delete every frame can be very slow
+ // but prevent from copying if called not only on change
+ delete this._actDiffuseColor;
+ }
+ }
+ }
+
+ for (var i=0, n=this._childNodes.length; i<n; i++)
+ {
+ if (this._childNodes[i])
+ this._childNodes[i].highlight(enable, color);
+ }
+ },
+
+ findX3DDoc: function () {
+ return this._nameSpace.doc;
+ },
+
+ doIntersect: function(line) {
+ var isect = false;
+ for (var i=0; i<this._childNodes.length; i++) {
+ if (this._childNodes[i]) {
+ isect = this._childNodes[i].doIntersect(line) || isect;
+ }
+ }
+ return isect;
+ },
+
+ postMessage: function (field, msg) {
+ // TODO: timestamps and stuff
+ this._vf[field] = msg; // FIXME; _cf!!!
+ var listeners = this._fieldWatchers[field];
+
+ var that = this;
+ if (listeners) {
+ Array.forEach(listeners, function (l) { l.call(that, msg); });
+ }
+
+ //for Web-style access to the output data of ROUTES, provide a callback function
+ var eventObject = {
+ target: that._xmlNode,
+ type: "outputchange", // event only called onxxx if used as old-fashioned attribute
+ fieldName: field,
+ value: msg
+ };
+
+ this.callEvtHandler("onoutputchange", eventObject);
+ },
+
+ // method for handling field updates
+ updateField: function (field, msg) {
+ var f = this._vf[field];
+
+ if (f === undefined) {
+ for (var key in this._vf) {
+ if (key.toLowerCase() == field) {
+ field = key;
+ f = this._vf[field];
+ break;
+ }
+ }
+
+ var pre = "set_";
+ if (f === undefined && field.indexOf(pre) == 0) {
+ var fieldName = field.substr(pre.length, field.length - 1);
+ if (this._vf[fieldName] !== undefined) {
+ field = fieldName;
+ f = this._vf[field];
+ }
+ }
+ if (f === undefined) {
+ f = null;
+ this._vf[field] = f;
+ }
+ }
+
+ if (f !== null) {
+ try {
+ this._vf[field].setValueByStr(msg);
+ }
+ catch (exc1) {
+ try {
+ switch ((typeof(this._vf[field])).toString()) {
+ case "number":
+ if (typeof(msg) == "number")
+ this._vf[field] = msg;
+ else
+ this._vf[field] = +msg;
+ break;
+ case "boolean":
+ if (typeof(msg) == "boolean")
+ this._vf[field] = msg;
+ else
+ this._vf[field] = (msg.toLowerCase() == "true");
+ break;
+ case "string":
+ this._vf[field] = msg;
+ break;
+ }
+ }
+ catch (exc2) {
+ x3dom.debug.logError("updateField: setValueByStr() NYI for " + typeof(f));
+ }
+ }
+
+ // TODO: eval fieldChanged for all nodes!
+ this.fieldChanged(field);
+ }
+ },
+
+ setupRoute: function (fromField, toNode, toField) {
+ var pos;
+ var fieldName;
+ var pre = "set_", post = "_changed";
+
+ // build correct fromField
+ if (!this._vf[fromField]) {
+ pos = fromField.indexOf(pre);
+ if (pos === 0) {
+ fieldName = fromField.substr(pre.length, fromField.length - 1);
+ if (this._vf[fieldName]) {
+ fromField = fieldName;
+ }
+ } else {
+ pos = fromField.indexOf(post);
+ if (pos > 0) {
+ fieldName = fromField.substr(0, fromField.length - post.length);
+ if (this._vf[fieldName]) {
+ fromField = fieldName;
+ }
+ }
+ }
+ }
+
+ // build correct toField
+ if (!toNode._vf[toField]) {
+ pos = toField.indexOf(pre);
+ if (pos === 0) {
+ fieldName = toField.substr(pre.length, toField.length - 1);
+ if (toNode._vf[fieldName]) {
+ toField = fieldName;
+ }
+ }
+ else {
+ pos = toField.indexOf(post);
+ if (pos > 0) {
+ fieldName = toField.substr(0, toField.length - post.length);
+ if (toNode._vf[fieldName]) {
+ toField = fieldName;
+ }
+ }
+ }
+ }
+
+ var where = this._DEF + "&" + fromField + "&" + toNode._DEF + "&" + toField;
+
+ if (!this._routes[where]) {
+ if (!this._fieldWatchers[fromField]) {
+ this._fieldWatchers[fromField] = [];
+ }
+ this._fieldWatchers[fromField].push(
+ function (msg) {
+ toNode.postMessage(toField, msg);
+ }
+ );
+
+ if (!toNode._fieldWatchers[toField]) {
+ toNode._fieldWatchers[toField] = [];
+ }
+ toNode._fieldWatchers[toField].push(
+ // FIXME: THIS DOESN'T WORK FOR NODE (_cf) FIELDS
+ function (msg) {
+ toNode._vf[toField] = msg;
+ toNode.fieldChanged(toField);
+ }
+ );
+
+ // store this route to be able to delete it
+ this._routes[where] = {
+ from: this._fieldWatchers[fromField].length - 1,
+ to: toNode._fieldWatchers[toField].length - 1
+ };
+ }
+ },
+
+ removeRoute: function (fromField, toNode, toField) {
+ var pos;
+ var fieldName;
+ var pre = "set_", post = "_changed";
+
+ // again, build correct fromField
+ if (!this._vf[fromField]) {
+ pos = fromField.indexOf(pre);
+ if (pos === 0) {
+ fieldName = fromField.substr(pre.length, fromField.length - 1);
+ if (this._vf[fieldName]) {
+ fromField = fieldName;
+ }
+ } else {
+ pos = fromField.indexOf(post);
+ if (pos > 0) {
+ fieldName = fromField.substr(0, fromField.length - post.length);
+ if (this._vf[fieldName]) {
+ fromField = fieldName;
+ }
+ }
+ }
+ }
+
+ // again, build correct toField
+ if (!toNode._vf[toField]) {
+ pos = toField.indexOf(pre);
+ if (pos === 0) {
+ fieldName = toField.substr(pre.length, toField.length - 1);
+ if (toNode._vf[fieldName]) {
+ toField = fieldName;
+ }
+ }
+ else {
+ pos = toField.indexOf(post);
+ if (pos > 0) {
+ fieldName = toField.substr(0, toField.length - post.length);
+ if (toNode._vf[fieldName]) {
+ toField = fieldName;
+ }
+ }
+ }
+ }
+
+ // finally, delete route
+ var where = this._DEF + "&" + fromField + "&" + toNode._DEF + "&" + toField;
+
+ if (this._routes[where]) {
+ this._fieldWatchers[fromField].splice(this._routes[where].from, 1);
+ toNode._fieldWatchers[toField].splice(this._routes[where].to, 1);
+
+ delete this._routes[where];
+ }
+ },
+
+ fieldChanged: function (fieldName) {
+ // to be overwritten by concrete classes
+ },
+
+ nodeChanged: function () {
+ // to be overwritten by concrete classes
+ },
+
+ callEvtHandler: function(eventType, event) {
+ var node = this;
+
+ if (!node._xmlNode) {
+ return event.cancelBubble;
+ }
+
+ try {
+ var attrib = node._xmlNode[eventType];
+ event.target = node._xmlNode;
+
+ if (typeof(attrib) === "function") {
+ attrib.call(node._xmlNode, event);
+ }
+ else {
+ var funcStr = node._xmlNode.getAttribute(eventType);
+ var func = new Function('event', funcStr);
+ func.call(node._xmlNode, event);
+ }
+
+ var list = node._listeners[event.type];
+ if (list) {
+ for (var it=0; it<list.length; it++) {
+ list[it].call(node._xmlNode, event);
+ }
+ }
+ }
+ catch(ex) {
+ x3dom.debug.logException(ex);
+ }
+
+ return event.cancelBubble;
+ },
+
+ initSetter: function (xmlNode, name) {
+ if (!xmlNode || !name)
+ return;
+
+ var nameLC = name.toLowerCase();
+ if (xmlNode.__defineSetter__ && xmlNode.__defineGetter__) {
+ xmlNode.__defineSetter__(name, function(value) {
+ xmlNode.setAttribute(name, value);
+ });
+ xmlNode.__defineGetter__(name, function() {
+ return xmlNode.getAttribute(name);
+ });
+ if (nameLC != name) {
+ xmlNode.__defineSetter__(nameLC, function(value) {
+ xmlNode.setAttribute(name, value);
+ });
+ xmlNode.__defineGetter__(nameLC, function() {
+ return xmlNode.getAttribute(name);
+ });
+ }
+ }
+ else {
+ // IE has no __define[G|S]etter__ !!!
+ Object.defineProperty(xmlNode, name, {
+ set: function(value) {
+ xmlNode.setAttribute(name, value);
+ },
+ get: function() {
+ return xmlNode.getAttribute(name);
+ },
+ configurable: true,
+ enumerable: true
+ });
+ }
+
+ if (this._vf[name] &&
+ !xmlNode.attributes[name] && !xmlNode.attributes[name.toLowerCase()]) {
+ var str = "";
+ try {
+ if (this._vf[name].toGL)
+ str = this._vf[name].toGL().toString();
+ else
+ str = this._vf[name].toString();
+ }
+ catch (e) {
+ str = this._vf[name].toString();
+ }
+ if (!str) {
+ str = "";
+ }
+ xmlNode.setAttribute(name, str);
+ }
+ },
+
+ // single fields
+ addField_SFInt32: function (ctx, name, n) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ parseInt(ctx.xmlNode.getAttribute(name),10) : n;
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFInt32";
+ },
+
+ addField_SFFloat: function (ctx, name, n) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ +ctx.xmlNode.getAttribute(name) : n;
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFFloat";
+ },
+
+ addField_SFDouble: function (ctx, name, n) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ +ctx.xmlNode.getAttribute(name) : n;
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFDouble";
+ },
+
+ addField_SFTime: function (ctx, name, n) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ +ctx.xmlNode.getAttribute(name) : n;
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFTime";
+ },
+
+ addField_SFBool: function (ctx, name, n) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ ctx.xmlNode.getAttribute(name).toLowerCase() === "true" : n;
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFBool";
+ },
+
+ addField_SFString: function (ctx, name, n) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ ctx.xmlNode.getAttribute(name) : n;
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFString";
+ },
+
+ addField_SFColor: function (ctx, name, r, g, b) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.SFColor.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.SFColor(r, g, b);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFColor";
+ },
+
+ addField_SFColorRGBA: function (ctx, name, r, g, b, a) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.SFColorRGBA.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.SFColorRGBA(r, g, b, a);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFColorRGBA";
+ },
+
+ addField_SFVec2f: function (ctx, name, x, y) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.SFVec2f.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.SFVec2f(x, y);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFVec2f";
+ },
+
+ addField_SFVec3f: function (ctx, name, x, y, z) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.SFVec3f.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.SFVec3f(x, y, z);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFVec3f";
+ },
+
+ addField_SFVec4f: function (ctx, name, x, y, z, w) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.SFVec4f.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.SFVec4f(x, y, z, w);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFVec4f";
+ },
+
+ addField_SFVec3d: function(ctx, name, x, y, z) {
+ this.addField_SFVec3f(ctx, name, x, y, z);
+ this._vfFieldTypes[name] = "SFVec3d";
+ },
+
+ addField_SFRotation: function (ctx, name, x, y, z, a) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.Quaternion.parseAxisAngle(ctx.xmlNode.getAttribute(name)) :
+ x3dom.fields.Quaternion.axisAngle(new x3dom.fields.SFVec3f(x, y, z), a);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFRotation";
+ },
+
+ addField_SFMatrix4f: function (ctx, name, _00, _01, _02, _03,
+ _10, _11, _12, _13,
+ _20, _21, _22, _23,
+ _30, _31, _32, _33) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.SFMatrix4f.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.SFMatrix4f(_00, _01, _02, _03,
+ _10, _11, _12, _13,
+ _20, _21, _22, _23,
+ _30, _31, _32, _33);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFMatrix4f";
+ },
+
+ addField_SFImage: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.SFImage.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.SFImage(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "SFImage";
+ },
+
+ // multi fields
+ addField_MFString: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFString.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFString(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFString";
+ },
+
+ addField_MFBoolean: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFBoolean.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFBoolean(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFBoolean";
+ },
+
+ addField_MFInt32: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFInt32.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFInt32(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFInt32";
+ },
+
+ addField_MFFloat: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFFloat.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFFloat(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFFloat";
+ },
+
+ addField_MFDouble: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFFloat.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFFloat(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFDouble";
+ },
+
+ addField_MFColor: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFColor.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFColor(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFColor";
+ },
+
+ addField_MFColorRGBA: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFColorRGBA.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFColorRGBA(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFColorRGBA";
+ },
+
+ addField_MFVec2f: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFVec2f.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFVec2f(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFVec2f";
+ },
+
+ addField_MFVec3f: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFVec3f.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFVec3f(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFVec3f";
+ },
+
+ addField_MFVec3d: function (ctx, name, def) {
+ this.addField_MFVec3f(ctx, name, def);
+ this._vfFieldTypes[name] = "MFVec3d";
+ },
+
+ addField_MFRotation: function (ctx, name, def) {
+ this._vf[name] = ctx && ctx.xmlNode && ctx.xmlNode.hasAttribute(name) ?
+ x3dom.fields.MFRotation.parse(ctx.xmlNode.getAttribute(name)) :
+ new x3dom.fields.MFRotation(def);
+
+ if (ctx && ctx.xmlNode) { this.initSetter(ctx.xmlNode, name); }
+ this._vfFieldTypes[name] = "MFRotation";
+ },
+
+ // child node fields
+ addField_SFNode: function (name, type) {
+ this._cf[name] = new x3dom.fields.SFNode(type);
+ this._cfFieldTypes[name] = "SFNode";
+ },
+ addField_MFNode: function (name, type) {
+ this._cf[name] = new x3dom.fields.MFNode(type);
+ this._cfFieldTypes[name] = "MFNode";
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DMetadataObject ### */
+x3dom.registerNodeType(
+ "X3DMetadataObject",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for X3DMetadataObject
+ * @constructs x3dom.nodeTypes.X3DMetadataObject
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract interface is the basis for all metadata nodes. The interface is inherited by
+ * all metadata nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DMetadataObject.superClass.call(this, ctx);
+
+
+ /**
+ * The specification of a non-empty value for the name field is required.
+ * @var {x3dom.fields.SFString} name
+ * @memberof x3dom.nodeTypes.X3DMetadataObject
+ * @initvalue ""
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'name', "");
+
+ /**
+ * The specification of the reference field is optional. If provided, it identifies the metadata standard
+ * or other specification that defines the name field. If the reference field is not provided or is empty,
+ * the meaning of the name field is considered implicit to the characters in the string.
+ * @var {x3dom.fields.SFString} reference
+ * @memberof x3dom.nodeTypes.X3DMetadataObject
+ * @initvalue ""
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'reference', "");
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MetadataBoolean ### */
+x3dom.registerNodeType(
+ "MetadataBoolean",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DMetadataObject,
+
+ /**
+ * Constructor for MetadataBoolean
+ * @constructs x3dom.nodeTypes.MetadataBoolean
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMetadataObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The metadata provided by this node is contained in the Boolean values of the value field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MetadataBoolean.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFBoolean} value
+ * @memberof x3dom.nodeTypes.MetadataBoolean
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFBoolean(ctx, 'value', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MetadataDouble ### */
+x3dom.registerNodeType(
+ "MetadataDouble",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DMetadataObject,
+
+ /**
+ * Constructor for MetadataDouble
+ * @constructs x3dom.nodeTypes.MetadataDouble
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMetadataObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The metadata provided by this node is contained in the double-precision floating point numbers of
+ * the value field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MetadataDouble.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFDouble} value
+ * @memberof x3dom.nodeTypes.MetadataDouble
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFDouble(ctx, 'value', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MetadataFloat ### */
+x3dom.registerNodeType(
+ "MetadataFloat",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DMetadataObject,
+
+ /**
+ * Constructor for MetadataFloat
+ * @constructs x3dom.nodeTypes.MetadataFloat
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMetadataObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The metadata provided by this node is contained in the single-precision floating point numbers of
+ * the value field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MetadataFloat.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFFloat} value
+ * @memberof x3dom.nodeTypes.MetadataFloat
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'value', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MetadataInteger ### */
+x3dom.registerNodeType(
+ "MetadataInteger",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DMetadataObject,
+
+ /**
+ * Constructor for MetadataInteger
+ * @constructs x3dom.nodeTypes.MetadataInteger
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMetadataObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The metadata provided by this node is contained in the integers of the value field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MetadataInteger.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFInt32} value
+ * @memberof x3dom.nodeTypes.MetadataInteger
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'value', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MetadataSet ### */
+x3dom.registerNodeType(
+ "MetadataSet",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DMetadataObject,
+
+ /**
+ * Constructor for MetadataSet
+ * @constructs x3dom.nodeTypes.MetadataSet
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMetadataObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The metadata provided by this node is contained in the metadata nodes of the value field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MetadataSet.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFNode} value
+ * @memberof x3dom.nodeTypes.MetadataSet
+ * @initvalue x3dom.nodeTypes.X3DMetadataObject
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('value', x3dom.nodeTypes.X3DMetadataObject);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MetadataString ### */
+x3dom.registerNodeType(
+ "MetadataString",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DMetadataObject,
+
+ /**
+ * Constructor for MetadataString
+ * @constructs x3dom.nodeTypes.MetadataString
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMetadataObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The metadata provided by this node is contained in the strings of the value field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MetadataString.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} value
+ * @memberof x3dom.nodeTypes.MetadataString
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'value', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Field ### */
+x3dom.registerNodeType(
+ "Field",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for Field
+ * @constructs x3dom.nodeTypes.Field
+ * @x3d x.x
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Class represents a field of a node containing name, type and value
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Field.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} name
+ * @memberof x3dom.nodeTypes.Field
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'name', "");
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} type
+ * @memberof x3dom.nodeTypes.Field
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'type', "");
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} value
+ * @memberof x3dom.nodeTypes.Field
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'value', "");
+
+ },
+ {
+ fieldChanged: function(fieldName) {
+ var that = this;
+ if (fieldName === 'value') {
+ Array.forEach(this._parentNodes, function (node) {
+ node.fieldChanged(that._vf.name);
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DChildNode ### */
+x3dom.registerNodeType(
+ "X3DChildNode",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for X3DChildNode
+ * @constructs x3dom.nodeTypes.X3DChildNode
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type indicates that the concrete nodes that are instantiated based on it may
+ * be used in children, addChildren, and removeChildren fields.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DChildNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DBindableNode ### */
+x3dom.registerNodeType(
+ "X3DBindableNode",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DBindableNode
+ * @constructs x3dom.nodeTypes.X3DBindableNode
+ * @x3d 3.3
+ * @component Core
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc X3DBindableNode is the abstract base type for all bindable children nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DBindableNode.superClass.call(this, ctx);
+
+
+ /**
+ * Pushes/pops the node on/from the top of the bindable stack
+ * @var {x3dom.fields.SFBool} bind
+ * @memberof x3dom.nodeTypes.X3DBindableNode
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'bind', false);
+
+ /**
+ * Description of the bindable node
+ * @var {x3dom.fields.SFString} description
+ * @memberof x3dom.nodeTypes.X3DBindableNode
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'description', "");
+
+ /**
+ *
+ * @var {x3dom.fields.SFBool} isActive
+ * @memberof x3dom.nodeTypes.X3DBindableNode
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'isActive', false);
+
+ this._autoGen = (ctx && ctx.autoGen ? true : false);
+ if (this._autoGen)
+ this._vf.description = "default" + this.constructor.superClass._typeName;
+
+ // Bindable stack to register node later on
+ this._stack = null;
+
+ },
+ {
+ bind: function (value) {
+ if (this._stack) {
+ if (value) {
+ this._stack.push (this);
+ }
+ else {
+ this._stack.pop (this);
+ }
+ }
+ else {
+ x3dom.debug.logError ('No BindStack in ' + this.typeName() + 'Bindable');
+ }
+ },
+
+ activate: function (prev) {
+ this.postMessage('isActive', true);
+ x3dom.debug.logInfo('activate ' + this.typeName() + 'Bindable ' +
+ this._DEF + '/' + this._vf.description);
+ },
+
+ deactivate: function (prev) {
+ this.postMessage('isActive', false);
+ x3dom.debug.logInfo('deactivate ' + this.typeName() + 'Bindable ' +
+ this._DEF + '/' + this._vf.description);
+ },
+
+ fieldChanged: function(fieldName) {
+ if (fieldName.indexOf("bind") >= 0) {
+ this.bind(this._vf.bind);
+ }
+ },
+
+ nodeChanged: function() {
+ this._stack = this._nameSpace.doc._bindableBag.addBindable(this);
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DInfoNode ### */
+x3dom.registerNodeType(
+ "X3DInfoNode",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DInfoNode
+ * @constructs x3dom.nodeTypes.X3DInfoNode
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all nodes that contain only information without visual semantics.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DInfoNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### WorldInfo ### */
+x3dom.registerNodeType(
+ "WorldInfo",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DInfoNode,
+
+ /**
+ * Constructor for WorldInfo
+ * @constructs x3dom.nodeTypes.WorldInfo
+ * @x3d 3.3
+ * @component Core
+ * @status full
+ * @extends x3dom.nodeTypes.X3DInfoNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The WorldInfo node contains information about the world. This node is strictly for documentation
+ * purposes and has no effect on the visual appearance or behaviour of the world.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.WorldInfo.superClass.call(this, ctx);
+
+
+ /**
+ * The title field is intended to store the name or title of the world so that browsers can present this to
+ * the user (perhaps in the window border).
+ * @var {x3dom.fields.MFString} info
+ * @memberof x3dom.nodeTypes.WorldInfo
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'info', []);
+
+ /**
+ * Information about the world can be stored in the info field, such as author information, copyright, and
+ * usage instructions.
+ * @var {x3dom.fields.SFString} title
+ * @memberof x3dom.nodeTypes.WorldInfo
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'title', "");
+
+ x3dom.debug.logInfo(this._vf.info);
+ x3dom.debug.logInfo(this._vf.title);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### X3DSensorNode ###
+x3dom.registerNodeType(
+ "X3DSensorNode",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DSensorNode
+ * @constructs x3dom.nodeTypes.X3DSensorNode
+ * @x3d 3.3
+ * @component Core
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all sensors.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DSensorNode.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies whether this sensor is enabled. A disabled sensor does not produce any output.
+ * @var {x3dom.fields.SFBool} enabled
+ * @memberof x3dom.nodeTypes.X3DSensorNode
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'enabled', true);
+
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// deprecated, will be removed in 1.5
+// ### Param ###
+x3dom.registerNodeType(
+ "Param",
+ "Core",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for Param
+ * @constructs x3dom.nodeTypes.Param
+ * @x3d x.x
+ * @component Core
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * DEPRECATED: Param element needs to be child of X3D element {@link http://x3dom.org/docs/latest/configuration.html}
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Param.superClass.call(this, ctx);
+
+ x3dom.debug.logWarning('DEPRECATED: Param element needs to be child of X3D element '
+ + '[<a href="http://x3dom.org/docs/latest/configuration.html">DOCS</a>]');
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DBoundedObject ### */
+x3dom.registerNodeType(
+ "X3DBoundedObject",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DBoundedObject
+ * @constructs x3dom.nodeTypes.X3DBoundedObject
+ * @x3d 3.3
+ * @component Grouping
+ * @status full
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the basis for all node types that have bounds specified as part of
+ * the definition. The bboxCenter and bboxSize fields specify a bounding box that encloses the grouping node's
+ * children. This is a hint that may be used for optimization purposes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DBoundedObject.superClass.call(this, ctx);
+
+
+ /**
+ * Flag to enable/disable rendering
+ * @var {x3dom.fields.SFBool} render
+ * @memberof x3dom.nodeTypes.X3DBoundedObject
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'render', true);
+
+ /**
+ * Center of the bounding box
+ * @var {x3dom.fields.SFVec3f} bboxCenter
+ * @memberof x3dom.nodeTypes.X3DBoundedObject
+ * @initvalue 0,0,0
+ * @range [-inf, inf]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'bboxCenter', 0, 0, 0);
+
+ /**
+ * Size of the bounding box
+ * @var {x3dom.fields.SFVec3f} bboxSize
+ * @memberof x3dom.nodeTypes.X3DBoundedObject
+ * @initvalue -1,-1,-1
+ * @range [0, inf] or -1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'bboxSize', -1, -1, -1);
+
+ this._graph = {
+ boundedNode: this, // backref to node object
+ localMatrix: x3dom.fields.SFMatrix4f.identity(), // usually identity
+ globalMatrix: null, // new x3dom.fields.SFMatrix4f();
+ volume: new x3dom.fields.BoxVolume(), // local bbox
+ worldVolume: new x3dom.fields.BoxVolume(), // global bbox
+ center: new x3dom.fields.SFVec3f(0,0,0), // center in eye coords
+ coverage: -1, // currently approx. number of pixels on screen
+ needCulling: true // to be able to disable culling per node
+ };
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ // TODO; wait for sync traversal to invalidate en block
+ if (this._vf.hasOwnProperty(fieldName)) {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ },
+
+ nodeChanged: function () {
+ // TODO; wait for sync traversal to invalidate en block
+ this.invalidateVolume();
+ //this.invalidateCache();
+ },
+
+ parentAdded: function(parent) {
+ // some default behavior if not overwitten
+ this.invalidateVolume();
+ //this.invalidateCache();
+ },
+
+ getVolume: function()
+ {
+ var vol = this._graph.volume;
+
+ if (!this.volumeValid() && this._vf.render)
+ {
+ for (var i=0, n=this._childNodes.length; i<n; i++)
+ {
+ var child = this._childNodes[i];
+ // render could be undefined, but undefined != true
+ if (!child || child._vf.render !== true)
+ continue;
+
+ var childVol = child.getVolume();
+
+ if (childVol && childVol.isValid())
+ vol.extendBounds(childVol.min, childVol.max);
+ }
+ }
+
+ return vol;
+ },
+
+ invalidateVolume: function()
+ {
+ var graph = this._graph;
+
+ graph.volume.invalidate();
+
+ // also clear cache
+ graph.worldVolume.invalidate();
+ graph.globalMatrix = null;
+
+ // set parent volumes invalid, too
+ for (var i=0, n=this._parentNodes.length; i<n; i++) {
+ var node = this._parentNodes[i];
+ if (node && node.volumeValid())
+ node.invalidateVolume();
+ }
+ },
+
+ invalidateCache: function()
+ {
+ var graph = this._graph;
+
+ //if (graph.volume.isValid() &&
+ // graph.globalMatrix == null && !graph.worldVolume.isValid())
+ // return; // stop here, we're already done
+
+ graph.worldVolume.invalidate();
+ graph.globalMatrix = null;
+
+ // clear children's cache, too
+ //for (var i=0, n=this._childNodes.length; i<n; i++) {
+ // var node = this._childNodes[i];
+ // if (node)
+ // node.invalidateCache();
+ //}
+ },
+
+ cacheInvalid: function()
+ {
+ return ( this._graph.globalMatrix == null ||
+ !this._graph.worldVolume.isValid() );
+ },
+
+ volumeValid: function()
+ {
+ return this._graph.volume.isValid();
+ },
+
+ graphState: function()
+ {
+ return this._graph;
+ },
+
+ forceUpdateCoverage: function()
+ {
+ return false;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### X3DGroupingNode ###
+x3dom.registerNodeType(
+ "X3DGroupingNode",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DBoundedObject,
+
+ /**
+ * Constructor for X3DGroupingNode
+ * @constructs x3dom.nodeTypes.X3DGroupingNode
+ * @x3d 3.3
+ * @component Grouping
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DBoundedObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type indicates that concrete node types derived from it contain children nodes
+ * and is the basis for all aggregation.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DGroupingNode.superClass.call(this, ctx);
+
+
+ /**
+ * Grouping nodes have a field that contains a list of children nodes. Each grouping node defines a
+ * coordinate space for its children. This coordinate space is relative to the coordinate space of the node
+ * of which the group node is a child. Such a node is called a parent node. This means that transformations
+ * accumulate down the scene graph hierarchy.
+ * @var {x3dom.fields.MFNode} children
+ * @memberof x3dom.nodeTypes.X3DGroupingNode
+ * @initvalue X3DChildNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('children', x3dom.nodeTypes.X3DChildNode);
+ // FIXME; add addChild and removeChild slots ?
+
+ },
+ {
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ // check if multi parent sub-graph, don't cache in that case
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ // an invalid world matrix or volume needs to be invalidated down the hierarchy
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ // check if sub-graph can be culled away or render flag was set to false
+ planeMask = drawableCollection.cull(transform, this.graphState(), singlePath, planeMask);
+ if (planeMask <= 0) {
+ return;
+ }
+
+ var cnode, childTransform;
+
+ if (singlePath) {
+ // rebuild cache on change and reuse world transform
+ if (!this._graph.globalMatrix) {
+ this._graph.globalMatrix = this.transformMatrix(transform);
+ }
+ childTransform = this._graph.globalMatrix;
+ }
+ else {
+ childTransform = this.transformMatrix(transform);
+ }
+
+ var n = this._childNodes.length;
+
+ if (x3dom.nodeTypes.ClipPlane.count > 0) {
+ var localClipPlanes = [];
+
+ for (var j = 0; j < n; j++) {
+ if ( (cnode = this._childNodes[j]) ) {
+ if (x3dom.isa(cnode, x3dom.nodeTypes.ClipPlane) && cnode._vf.on && cnode._vf.enabled) {
+ localClipPlanes.push({plane: cnode, trafo: childTransform});
+ }
+ }
+ }
+
+ clipPlanes = localClipPlanes.concat(clipPlanes);
+ }
+
+ for (var i=0; i<n; i++) {
+ if ( (cnode = this._childNodes[i]) ) {
+ cnode.collectDrawableObjects(childTransform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### Switch ###
+x3dom.registerNodeType(
+ "Switch",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Switch
+ * @constructs x3dom.nodeTypes.Switch
+ * @x3d 3.3
+ * @component Grouping
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Switch grouping node traverses zero or one of the nodes specified in the children field.
+ * All nodes under a Switch continue to receive and send events regardless of the value of whichChoice.
+ * For example, if an active TimeSensor is contained within an inactive choice of an Switch, the TimeSensor sends events regardless of the Switch's state.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Switch.superClass.call(this, ctx);
+
+
+ /**
+ * The whichChoice field specifies the index of the child to traverse, with the first child having index 0.
+ * If whichChoice is less than zero or greater than the number of nodes in the children field, nothing is chosen.
+ * @var {x3dom.fields.SFInt32} whichChoice
+ * @memberof x3dom.nodeTypes.Switch
+ * @initvalue -1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'whichChoice', -1);
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName == "whichChoice") {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ },
+
+ getVolume: function()
+ {
+ var vol = this._graph.volume;
+
+ if (!this.volumeValid() && this._vf.render)
+ {
+ if (this._vf.whichChoice >= 0 &&
+ this._vf.whichChoice < this._childNodes.length)
+ {
+ var child = this._childNodes[this._vf.whichChoice];
+
+ var childVol = (child && child._vf.render === true) ? child.getVolume() : null;
+
+ if (childVol && childVol.isValid())
+ vol.extendBounds(childVol.min, childVol.max);
+ }
+ }
+
+ return vol;
+ },
+
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ if (this._vf.whichChoice < 0 || this._vf.whichChoice >= this._childNodes.length ||
+ (planeMask = drawableCollection.cull(transform, this.graphState(), singlePath, planeMask)) <= 0) {
+ return;
+ }
+
+ var cnode, childTransform;
+
+ if (singlePath) {
+ if (!this._graph.globalMatrix) {
+ this._graph.globalMatrix = this.transformMatrix(transform);
+ }
+ childTransform = this._graph.globalMatrix;
+ }
+ else {
+ childTransform = this.transformMatrix(transform);
+ }
+
+ if ( (cnode = this._childNodes[this._vf.whichChoice]) ) {
+ cnode.collectDrawableObjects(childTransform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ },
+
+ doIntersect: function(line)
+ {
+ if (this._vf.whichChoice < 0 ||
+ this._vf.whichChoice >= this._childNodes.length) {
+ return false;
+ }
+
+ var child = this._childNodes[this._vf.whichChoice];
+ if (child) {
+ return child.doIntersect(line);
+ }
+
+ return false;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### X3DTransformNode ###
+x3dom.registerNodeType(
+ "X3DTransformNode",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for X3DTransformNode
+ * @constructs x3dom.nodeTypes.X3DTransformNode
+ * @x3d x.x
+ * @component Grouping
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the basis for all node types that group and transform their children.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DTransformNode.superClass.call(this, ctx);
+
+ if (ctx)
+ ctx.doc._nodeBag.trans.push(this);
+ else
+ x3dom.debug.logWarning("X3DTransformNode: No runtime context found!");
+
+ // holds the current matrix (local space transform)
+ this._trafo = null;
+
+ // workaround, only check on init if getStyle is necessary, since expensive
+ this._needCssStyleUpdates = true;
+
+ },
+ {
+ tick: function (t)
+ {
+ var dom = this._xmlNode;
+
+ if (dom && (dom['ontransform'] ||
+ dom.hasAttribute('ontransform') ||
+ this._listeners['transform'])) {
+ var transMatrix = this.getCurrentTransform();
+
+ var event = {
+ target: dom,
+ type: 'transform',
+ worldX: transMatrix._03,
+ worldY: transMatrix._13,
+ worldZ: transMatrix._23,
+ cancelBubble: false,
+ stopPropagation: function () {
+ this.cancelBubble = true;
+ }
+ };
+
+ this.callEvtHandler("ontransform", event);
+ }
+
+ // temporary per frame update method for CSS-Transform
+ if (this._needCssStyleUpdates && dom) {
+ var trans = x3dom.getStyle(dom, "-webkit-transform") ||
+ x3dom.getStyle(dom, "-moz-transform") ||
+ x3dom.getStyle(dom, "-ms-transform") ||
+ x3dom.getStyle(dom, "transform");
+
+ if (trans && (trans != 'none')) {
+ this._trafo.setValueByStr(trans);
+
+ this.invalidateVolume();
+ //this.invalidateCache();
+
+ return true;
+ }
+ this._needCssStyleUpdates = false; // no special CSS set
+ }
+
+ return false;
+ },
+
+ transformMatrix: function(transform) {
+ return transform.mult(this._trafo);
+ },
+
+ getVolume: function()
+ {
+ var vol = this._graph.volume;
+
+ if (!this.volumeValid() && this._vf.render)
+ {
+ this._graph.localMatrix = this._trafo;
+
+ for (var i=0, n=this._childNodes.length; i<n; i++)
+ {
+ var child = this._childNodes[i];
+ if (!child || child._vf.render !== true)
+ continue;
+
+ var childVol = child.getVolume();
+
+ if (childVol && childVol.isValid())
+ vol.extendBounds(childVol.min, childVol.max);
+ }
+
+ if (vol.isValid())
+ vol.transform(this._trafo);
+ }
+
+ return vol;
+ },
+
+ doIntersect: function(line)
+ {
+ var isect = false;
+ var mat = this._trafo.inverse();
+
+ var tmpPos = new x3dom.fields.SFVec3f(line.pos.x, line.pos.y, line.pos.z);
+ var tmpDir = new x3dom.fields.SFVec3f(line.dir.x, line.dir.y, line.dir.z);
+
+ line.pos = mat.multMatrixPnt(line.pos);
+ line.dir = mat.multMatrixVec(line.dir);
+
+ if (line.hitObject) {
+ line.dist *= line.dir.length();
+ }
+
+ // check for _nearest_ hit object and don't stop on first!
+ for (var i=0; i<this._childNodes.length; i++)
+ {
+ if (this._childNodes[i]) {
+ isect = this._childNodes[i].doIntersect(line) || isect;
+ }
+ }
+
+ line.pos.setValues(tmpPos);
+ line.dir.setValues(tmpDir);
+
+ if (isect) {
+ line.hitPoint = this._trafo.multMatrixPnt(line.hitPoint);
+ line.dist *= line.dir.length();
+ }
+
+ return isect;
+ },
+
+ parentRemoved: function(parent)
+ {
+ var i, n;
+
+ if (this._parentNodes.length == 0) {
+ var doc = this.findX3DDoc();
+
+ for (i=0, n=doc._nodeBag.trans.length; i<n; i++) {
+ if (doc._nodeBag.trans[i] === this) {
+ doc._nodeBag.trans.splice(i, 1);
+ }
+ }
+ }
+
+ for (i=0, n=this._childNodes.length; i<n; i++) {
+ if (this._childNodes[i]) {
+ this._childNodes[i].parentRemoved(this);
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### Transform ###
+x3dom.registerNodeType(
+ "Transform",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DTransformNode,
+
+ /**
+ * Constructor for Transform
+ * @constructs x3dom.nodeTypes.Transform
+ * @x3d 3.3
+ * @component Grouping
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DTransformNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Transform node is a grouping node that defines a coordinate system for its children that is relative to the coordinate systems of its ancestors.
+ * The translation, rotation, scale, scaleOrientation and center fields define a geometric 3D transformation.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Transform.superClass.call(this, ctx);
+
+
+ /**
+ * The center field specifies a translation offset from the origin of the local coordinate system (0,0,0).
+ * @var {x3dom.fields.SFVec3f} center
+ * @memberof x3dom.nodeTypes.Transform
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'center', 0, 0, 0);
+
+ /**
+
+ * The translation field specifies a translation to the coordinate system.
+ * @var {x3dom.fields.SFVec3f} translation
+ * @memberof x3dom.nodeTypes.Transform
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'translation', 0, 0, 0);
+
+ /**
+ * The rotation field specifies a rotation of the coordinate system.
+ * @var {x3dom.fields.SFRotation} rotation
+ * @memberof x3dom.nodeTypes.Transform
+ * @initvalue 0,0,1,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'rotation', 0, 0, 1, 0);
+
+ /**
+ * The scale field specifies a non-uniform scale of the coordinate system.
+ * Scale values may have any value: positive, negative (indicating a reflection), or zero. A value of zero indicates that any child geometry shall not be displayed.
+ * @var {x3dom.fields.SFVec3f} scale
+ * @memberof x3dom.nodeTypes.Transform
+ * @initvalue 1,1,1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'scale', 1, 1, 1);
+
+ /**
+ * The scaleOrientation specifies a rotation of the coordinate system before the scale (to specify scales in arbitrary orientations).
+ * The scaleOrientation applies only to the scale operation.
+ * @var {x3dom.fields.SFRotation} scaleOrientation
+ * @memberof x3dom.nodeTypes.Transform
+ * @initvalue 0,0,1,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'scaleOrientation', 0, 0, 1, 0);
+
+ // P' = T * C * R * SR * S * -SR * -C * P
+ this._trafo = x3dom.fields.SFMatrix4f.translation(
+ this._vf.translation.add(this._vf.center)).
+ mult(this._vf.rotation.toMatrix()).
+ mult(this._vf.scaleOrientation.toMatrix()).
+ mult(x3dom.fields.SFMatrix4f.scale(this._vf.scale)).
+ mult(this._vf.scaleOrientation.toMatrix().inverse()).
+ mult(x3dom.fields.SFMatrix4f.translation(this._vf.center.negate()));
+
+ },
+ {
+ fieldChanged: function (fieldName)
+ {
+ if (fieldName == "center" || fieldName == "translation" ||
+ fieldName == "rotation" || fieldName == "scale" ||
+ fieldName == "scaleOrientation")
+ {
+ // P' = T * C * R * SR * S * -SR * -C * P
+ this._trafo = x3dom.fields.SFMatrix4f.translation(
+ this._vf.translation.add(this._vf.center)).
+ mult(this._vf.rotation.toMatrix()).
+ mult(this._vf.scaleOrientation.toMatrix()).
+ mult(x3dom.fields.SFMatrix4f.scale(this._vf.scale)).
+ mult(this._vf.scaleOrientation.toMatrix().inverse()).
+ mult(x3dom.fields.SFMatrix4f.translation(this._vf.center.negate()));
+
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ else if (fieldName == "render") {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### MatrixTransform ###
+x3dom.registerNodeType(
+ "MatrixTransform",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DTransformNode,
+
+ /**
+ * Constructor for MatrixTransform
+ * @constructs x3dom.nodeTypes.MatrixTransform
+ * @x3d x.x
+ * @component Grouping
+ * @extends x3dom.nodeTypes.X3DTransformNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The MatrixTransform node is a grouping node that defines a coordinate system for its children that is relative to the coordinate systems of its ancestors.
+ * The transformation is given as a matrix.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MatrixTransform.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the transformation matrix.
+ * @var {x3dom.fields.SFMatrix4f} matrix
+ * @memberof x3dom.nodeTypes.MatrixTransform
+ * @initvalue 1,0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFMatrix4f(ctx, 'matrix',
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+ this._trafo = this._vf.matrix.transpose();
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName == "matrix") {
+ this._trafo = this._vf.matrix.transpose();
+
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ else if (fieldName == "render") {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### Group ###
+x3dom.registerNodeType(
+ "Group",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Group
+ * @constructs x3dom.nodeTypes.Group
+ * @x3d 3.3
+ * @component Grouping
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc A Group node contains children nodes without introducing a new transformation.
+ * It is equivalent to a Transform node containing an identity transform.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Group.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### Block ###
+x3dom.registerNodeType(
+ "Block",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Block
+ * @constructs x3dom.nodeTypes.Block
+ * @x3d x.x
+ * @component Grouping
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Block.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} nameSpaceName
+ * @memberof x3dom.nodeTypes.Block
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'nameSpaceName', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### StaticGroup ###
+x3dom.registerNodeType(
+ "StaticGroup",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for StaticGroup
+ * @constructs x3dom.nodeTypes.StaticGroup
+ * @x3d 3.3
+ * @component Grouping
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The StaticGroup node contains children nodes which cannot be modified.
+ * StaticGroup children are guaranteed to not change, send events, receive events or contain any USE references outside the StaticGroup.
+ * This allows the browser to optimize this content for faster rendering and less memory usage.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.StaticGroup.superClass.call(this, ctx);
+
+ // Node implements optimizations; no need to maintain the children node's
+ // X3D representations, as they cannot be accessed after creation time
+ x3dom.debug.logWarning("StaticGroup erroneously also bakes parent transforms, if happens use Group node!"); // Blender exports to SG
+
+ /**
+ * Enables debugging.
+ * @var {x3dom.fields.SFBool} debug
+ * @memberof x3dom.nodeTypes.StaticGroup
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'debug', false);
+
+ /**
+ * Enable debug box volumes.
+ * @var {x3dom.fields.SFBool} showDebugBoxVolumes
+ * @memberof x3dom.nodeTypes.StaticGroup
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'showDebugBoxVolumes', false);
+
+ // type of bvh to use, supported are 'jsBIH', 'BIH' and 'OCTREE'
+
+ /**
+ * Defines the type of bvh to use. Supported are 'jsBIH', 'BIH' and 'OCTREE'.
+ * @var {x3dom.fields.SFString} bvhType
+ * @memberof x3dom.nodeTypes.StaticGroup
+ * @initvalue 'jsBIH'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'bvhType', 'jsBIH');
+
+ /**
+ *
+ * @var {x3dom.fields.SFInt32} maxObjectsPerNode
+ * @memberof x3dom.nodeTypes.StaticGroup
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'maxObjectsPerNode', 1);
+ // -1 sets default values, other values forces maxDepth
+
+ /**
+ *
+ * @var {x3dom.fields.SFInt32} maxDepth
+ * @memberof x3dom.nodeTypes.StaticGroup
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'maxDepth', -1);
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} minRelativeBBoxSize
+ * @memberof x3dom.nodeTypes.StaticGroup
+ * @initvalue 0.01
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'minRelativeBBoxSize', 0.01);
+
+ this.needBvhRebuild = true;
+ this.drawableCollection = null;
+ this.bvh = null;
+
+ },
+ {
+ getMaxDepth : function()
+ {
+ if(this._vf.maxDepth == -1 )
+ {
+ return (this._vf.bvhType == ('jsBIH' || 'BIH')) ? 50 : 4;
+ }
+ return this._vf.maxDepth;
+ },
+
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ // check if multi parent sub-graph, don't cache in that case
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ // an invalid world matrix or volume needs to be invalidated down the hierarchy
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ // check if sub-graph can be culled away or render flag was set to false
+ planeMask = drawableCollection.cull(transform, this.graphState(), singlePath, planeMask);
+ if (planeMask <= 0) {
+ return;
+ }
+
+ var cnode, childTransform;
+
+ if (singlePath) {
+ // rebuild cache on change and reuse world transform
+ if (!this._graph.globalMatrix) {
+ this._graph.globalMatrix = this.transformMatrix(transform);
+ }
+ childTransform = this._graph.globalMatrix;
+ }
+ else {
+ childTransform = this.transformMatrix(transform);
+ }
+
+ if (this.needBvhRebuild)
+ {
+ var drawableCollectionConfig = {
+ viewArea: drawableCollection.viewarea,
+ sortTrans: drawableCollection.sortTrans,
+ viewMatrix: drawableCollection.viewMatrix,
+ projMatrix: drawableCollection.projMatrix,
+ sceneMatrix: drawableCollection.sceneMatrix,
+ frustumCulling: false,
+ smallFeatureThreshold: 0,//1, // THINKABOUTME
+ context: drawableCollection.context
+ };
+
+ this.drawableCollection = new x3dom.DrawableCollection(drawableCollectionConfig);
+
+ var i, n = this._childNodes.length;
+ for (i=0; i<n; i++) {
+ if ( (cnode = this._childNodes[i]) ) {
+ //this is only used to collect all drawables once
+ cnode.collectDrawableObjects(childTransform, this.drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ }
+ this.drawableCollection.concat();
+
+ var scene = this._nameSpace.doc._scene;
+
+ //create settings
+ var bvhSettings = new x3dom.bvh.Settings(
+ this._vf.debug,
+ this._vf.showDebugBoxVolumes,
+ this._vf.bvhType,
+ this._vf.maxObjectsPerNode,
+ this.getMaxDepth(),
+ this._vf.minRelativeBBoxSize
+ );
+ //create bvh type
+ this.bvh = (this._vf.bvhType == 'jsBIH' ) ?
+ new x3dom.bvh.BIH(scene, bvhSettings) :
+ new x3dom.bvh.Culler(this.drawableCollection,scene, bvhSettings);
+
+ //add decorator for debug shapes
+ if(this._vf.debug || this._vf.showDebugBoxVolumes)
+ this.bvh = new x3dom.bvh.DebugDecorator(this.bvh, scene, bvhSettings);
+
+ //add drawables
+ n = this.drawableCollection.length;
+ for (i = 0; i < n; i++)
+ {
+ this.bvh.addDrawable(this.drawableCollection.get(i))
+ }
+
+ //compile bvh
+ this.bvh.compile();
+
+ if(this._vf.debug)
+ this.bvh.showCompileStats();
+
+ this.needBvhRebuild = false; // TODO: re-evaluate if Inline node is child node
+ }
+
+ x3dom.Utils.startMeasure('bvhTraverse');
+ //collect drawables
+ this.bvh.collectDrawables(drawableCollection);
+ var dt = x3dom.Utils.stopMeasure('bvhTraverse');
+ this._nameSpace.doc.ctx.x3dElem.runtime.addMeasurement('BVH', dt);
+
+ //show stats
+ this.bvh.showTraverseStats(this._nameSpace.doc.ctx.x3dElem.runtime);
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### RemoteSelectionGroup ###
+x3dom.registerNodeType(
+ "RemoteSelectionGroup",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for RemoteSelectionGroup
+ * @constructs x3dom.nodeTypes.RemoteSelectionGroup
+ * @x3d x.x
+ * @component Grouping
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The RemoteSelectionGroup node uses a WebSocket connection to request the results of a a side
+ * culling.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.RemoteSelectionGroup.superClass.call(this, ctx);
+
+
+ /**
+ * The address for the WebSocket connection
+ * @var {x3dom.fields.MFString} url
+ * @memberof x3dom.nodeTypes.RemoteSelectionGroup
+ * @initvalue ["ws://localhost:35668/cstreams/0"]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'url', ["ws://localhost:35668/cstreams/0"]);
+
+ /**
+ * Defines a list of subsequent id/object pairs.
+ * @var {x3dom.fields.MFString} label
+ * @memberof x3dom.nodeTypes.RemoteSelectionGroup
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'label', []);
+
+ /**
+ * Sets the maximum number of items that are rendered.
+ * @var {x3dom.fields.SFInt32} maxRenderedIds
+ * @range -1 or [0, inf]
+ * @memberof x3dom.nodeTypes.RemoteSelectionGroup
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'maxRenderedIds', -1);
+
+ /**
+ * Sets whether a reconnect is attempted on a connection loss.
+ * @var {x3dom.fields.SFBool} reconnect
+ * @memberof x3dom.nodeTypes.RemoteSelectionGroup
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'reconnect', true);
+
+ /**
+ * Sets the scaling factor to reduce the number of render calls during navigation
+ * @var {x3dom.fields.SFFloat} scaleRenderedIdsOnMove
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.RemoteSelectionGroup
+ * @initvalue 1.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'scaleRenderedIdsOnMove', 1.0);
+
+ /**
+ * Defines whether culling is used. If culling is disabled the RemoteSelectionGroup works like a normal group.
+ * @var {x3dom.fields.SFBool} enableCulling
+ * @memberof x3dom.nodeTypes.RemoteSelectionGroup
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'enableCulling', true);
+
+ /**
+ * Defines a set of labels to disable nodes. The label must include the prefix.
+ * @var {x3dom.fields.MFString} invisibleNodes
+ * @memberof x3dom.nodeTypes.RemoteSelectionGroup
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'invisibleNodes', []);
+
+ this._idList = []; // to be updated by socket connection
+ this._websocket = null; // pointer to socket
+
+ this._nameObjMap = {};
+ this._createTime = [];
+ this._visibleList = [];
+
+ if (ctx)
+ this.initializeSocket(); // init socket connection
+ else
+ x3dom.debug.logWarning("RemoteSelectionGroup: No runtime context found!");
+
+ },
+ {
+ initializeSocket: function()
+ {
+ var that = this;
+
+ if ("WebSocket" in window)
+ {
+ var wsUrl = "ws://localhost:35668/cstreams/0";
+
+ if (this._vf.url.length && this._vf.url[0].length)
+ wsUrl = this._vf.url[0];
+
+ this._websocket = new WebSocket(wsUrl);
+
+ this._websocket._lastMsg = null;
+ this._websocket._lastData = "";
+
+ this._websocket.onopen = function(evt)
+ {
+ x3dom.debug.logInfo("WS Connected");
+
+ var view = that._nameSpace.doc._viewarea.getViewMatrix();
+ this._lastMsg = view.toGL().toString();
+
+ view = that._nameSpace.doc._viewarea.getProjectionMatrix();
+ this._lastMsg += ("," + view.toGL().toString());
+
+ this.send(this._lastMsg);
+ x3dom.debug.logInfo("WS Sent: " + this._lastMsg);
+
+ this._lastMsg = ""; // triggers first update
+ this._lastData = "";
+ };
+
+ this._websocket.onclose = function(evt)
+ {
+ x3dom.debug.logInfo("WS Disconnected");
+
+ if (that._vf.reconnect)
+ {
+ window.setTimeout(function() {
+ that.initializeSocket();
+ }, 2000);
+ }
+ };
+
+ this._websocket.onmessage = function(evt)
+ {
+ if (that._vf.maxRenderedIds < 0)
+ {
+ // render all sent items
+ that._idList = x3dom.fields.MFString.parse(evt.data);
+ }
+ else if (that._vf.maxRenderedIds > 0)
+ {
+ // render #maxRenderedIds items
+ that._idList = [];
+ var arr = x3dom.fields.MFString.parse(evt.data);
+ var n = Math.min(arr.length, Math.abs(that._vf.maxRenderedIds));
+
+ for (var i=0; i<n; ++i) {
+ that._idList[i] = arr[i];
+ }
+ }
+
+ if (that._vf.maxRenderedIds != 0 && this._lastData != evt.data)
+ {
+ this._lastData = evt.data;
+ that._nameSpace.doc.needRender = true;
+ //x3dom.debug.logInfo("WS Response: " + evt.data);
+
+ that.invalidateVolume();
+ //that.invalidateCache();
+ }
+ };
+
+ this._websocket.onerror = function(evt)
+ {
+ x3dom.debug.logError(evt.data);
+ };
+
+ this._websocket.updateCamera = function()
+ {
+ // send again
+ var view = that._nameSpace.doc._viewarea.getViewMatrix();
+ var message = view.toGL().toString();
+
+ view = that._nameSpace.doc._viewarea.getProjectionMatrix();
+ message += ("," + view.toGL().toString());
+
+ if (this._lastMsg != null && this._lastMsg != message)
+ {
+ this._lastMsg = message;
+ this.send(message);
+ //x3dom.debug.logInfo("WS Sent: " + message);
+ }
+ };
+
+ // if there were a d'tor this would belong there
+ // this._websocket.close();
+ }
+ else
+ {
+ x3dom.debug.logError("Browser has no WebSocket support!");
+ }
+ },
+
+ nodeChanged: function ()
+ {
+ var n = this._vf.label.length;
+
+ this._nameObjMap = {};
+ this._createTime = new Array(n);
+ this._visibleList = new Array(n);
+
+ for (var i=0; i<n; ++i)
+ {
+ var shape = this._childNodes[i];
+
+ if (shape && x3dom.isa(shape, x3dom.nodeTypes.X3DShapeNode))
+ {
+ this._nameObjMap[this._vf.label[i]] = { shape: shape, pos: i };
+ this._visibleList[i] = true;
+ }
+ else {
+ this._visibleList[i] = false;
+ x3dom.debug.logError("Invalid children: " + this._vf.label[i]);
+ }
+
+ // init list that holds creation time of gl object
+ this._createTime[i] = 0;
+ }
+
+ this.invalidateVolume();
+ //this.invalidateCache();
+
+ x3dom.debug.logInfo("RemoteSelectionGroup has " + n + " entries.");
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName == "url")
+ {
+ if (this._websocket) {
+ this._websocket.close();
+ this._websocket = null;
+ }
+ this.initializeSocket();
+ }
+ else if (fieldName == "invisibleNodes")
+ {
+ for (var i=0, n=this._vf.label.length; i<n; ++i)
+ {
+ var shape = this._childNodes[i];
+
+ if (shape && x3dom.isa(shape, x3dom.nodeTypes.X3DShapeNode))
+ {
+ this._visibleList[i] = true;
+
+ for (var j=0, numInvis=this._vf.invisibleNodes.length; j<numInvis; ++j)
+ {
+ var nodeName = this._vf.invisibleNodes[j];
+ var starInd = nodeName.lastIndexOf('*');
+ var matchNameBegin = false;
+
+ if (starInd > 0) {
+ nodeName = nodeName.substring(0, starInd);
+ matchNameBegin = true;
+ }
+ if (nodeName.length <= 1)
+ continue;
+
+ if ((matchNameBegin && this._vf.label[i].indexOf(nodeName) == 0) ||
+ this._vf.label[i] == nodeName) {
+ this._visibleList[i] = false;
+ break;
+ }
+ }
+ }
+ else {
+ this._visibleList[i] = false;
+ }
+ }
+
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ else if (fieldName == "render") {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ },
+
+ getNumRenderedObjects: function(len, isMoving)
+ {
+ var n = len;
+
+ if (this._vf.maxRenderedIds > 0)
+ {
+ var num = Math.max(this._vf.maxRenderedIds, 16); // set lower bound
+
+ var scale = 1; // scale down on move
+ if (isMoving)
+ scale = Math.min(this._vf.scaleRenderedIdsOnMove, 1);
+
+ num = Math.max(Math.round(scale * num), 0);
+ n = Math.min(n, num);
+ }
+
+ return n;
+ },
+
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ planeMask = drawableCollection.cull(transform, this.graphState(), singlePath, planeMask);
+ if (planeMask <= 0) {
+ return;
+ }
+
+ var viewarea = this._nameSpace.doc._viewarea;
+ var isMoving = viewarea.isMovingOrAnimating();
+
+ var ts = new Date().getTime();
+ var maxLiveTime = 10000;
+ var i, n, numChild = this._childNodes.length;
+
+ if (!this._vf.enableCulling)
+ {
+ n = this.getNumRenderedObjects(numChild, isMoving);
+
+ var cnt = 0;
+ for (i=0; i<numChild; i++)
+ {
+ var shape = this._childNodes[i];
+
+ if (shape)
+ {
+ var needCleanup = true;
+
+ if (this._visibleList[i] && cnt < n &&
+ shape.collectDrawableObjects(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes))
+ {
+ this._createTime[i] = ts;
+ cnt++;
+ needCleanup = false;
+ }
+
+ if (needCleanup && !isMoving && this._createTime[i] > 0 &&
+ ts - this._createTime[i] > maxLiveTime && shape._cleanupGLObjects)
+ {
+ shape._cleanupGLObjects(true);
+ this._createTime[i] = 0;
+ }
+ }
+ }
+
+ return;
+ }
+
+ if (this._websocket)
+ this._websocket.updateCamera();
+
+ if (this._vf.label.length)
+ {
+ n = this.getNumRenderedObjects(this._idList.length, isMoving);
+
+ for (i=0; i<n; i++)
+ {
+ var obj = this._nameObjMap[this._idList[i]];
+ if (obj && obj.shape) {
+ obj.shape.collectDrawableObjects(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ this._createTime[obj.pos] = ts;
+ }
+ else
+ x3dom.debug.logError("Invalid label: " + this._idList[i]);
+ }
+
+ for (i=0; i<this._childNodes.length; i++)
+ {
+ if (this._childNodes[i] && !isMoving && this._createTime[i] > 0 &&
+ ts - this._createTime[i] > maxLiveTime && this._childNodes[i]._cleanupGLObjects)
+ {
+ this._childNodes[i]._cleanupGLObjects(true);
+ this._createTime[i] = 0;
+ }
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// Not a real X3D node type
+// ### Scene ###
+x3dom.registerNodeType(
+ "Scene",
+ "Grouping",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Scene
+ * @constructs x3dom.nodeTypes.Scene
+ * @x3d x.x
+ * @component Core
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The scene node wraps the x3d scene.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Scene.superClass.call(this, ctx);
+
+ // define the experimental picking mode: box, idBuf, idBuf24, idBufId, color, texCoord
+
+ /**
+ * The picking mode for the scene
+ * @var {x3dom.fields.SFString} pickMode
+ * @memberof x3dom.nodeTypes.Scene
+ * @initvalue "idBuf"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'pickMode', "idBuf");
+ // experimental field to switch off picking
+
+ /**
+ * Flag to enable/disable pick pass
+ * @var {x3dom.fields.SFBool} doPickPass
+ * @memberof x3dom.nodeTypes.Scene
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'doPickPass', true);
+
+ // another experimental field for shadow DOM remapping
+
+ /**
+ * The url of the shadow object id mapping
+ * @var {x3dom.fields.SFString} shadowObjectIdMapping
+ * @memberof x3dom.nodeTypes.Scene
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'shadowObjectIdMapping', "");
+
+ this._lastMin = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._lastMax = new x3dom.fields.SFVec3f(1, 1, 1);
+
+ this._shadowIdMap = null;
+ this.loadMapping();
+
+ this._multiPartMap = null;
+ },
+ {
+ /* Bindable getter (e.g. getViewpoint) are added automatically */
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName == "shadowObjectIdMapping")
+ {
+ this.loadMapping();
+ }
+ },
+
+ updateVolume: function()
+ {
+ var vol = this.getVolume();
+
+ if (vol.isValid())
+ {
+ this._lastMin = x3dom.fields.SFVec3f.copy(vol.min);
+ this._lastMax = x3dom.fields.SFVec3f.copy(vol.max);
+ }
+ },
+
+ loadMapping: function()
+ {
+ this._shadowIdMap = null;
+
+ if (this._vf.shadowObjectIdMapping.length == 0) {
+ return;
+ }
+
+ var that = this;
+ var xhr = new XMLHttpRequest();
+
+ xhr.open("GET", this._nameSpace.getURL(this._vf.shadowObjectIdMapping), true);
+ xhr.send();
+
+ xhr.onload = function()
+ {
+ that._shadowIdMap = eval("(" + xhr.response + ")");
+
+ if (!that._shadowIdMap || !that._shadowIdMap.mapping) {
+ x3dom.debug.logWarning("Invalid ID map: " + that._vf.shadowObjectIdMapping);
+ }
+ else {
+ x3dom.debug.assert(that._shadowIdMap.maxID <= that._shadowIdMap.mapping.length,
+ "Too few ID map entries in " + that._vf.shadowObjectIdMapping + ", " +
+ "length of mapping array is only " + that._shadowIdMap.mapping.length +
+ " instead of " + that._shadowIdMap.ids.length + "!");
+ }
+ };
+ }
+ }
+ )
+);
+
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ *
+ * Based on code originally provided by
+ * Philip Taylor: http://philip.html5.org
+ */
+
+
+///////////////////////////////////////////////////////////////////////////////
+// BindableStack constructor
+///////////////////////////////////////////////////////////////////////////////
+x3dom.BindableStack = function (doc, type, defaultType, getter) {
+ this._doc = doc;
+ this._type = type;
+ this._defaultType = defaultType;
+ this._defaultRoot = null;
+ this._getter = getter;
+ this._bindBag = [];
+ this._bindStack = [];
+};
+
+x3dom.BindableStack.prototype.top = function () {
+ return ( (this._bindStack.length > 0) ? this._bindStack[this._bindStack.length - 1] : null );
+};
+
+x3dom.BindableStack.prototype.push = function (bindable) {
+ var top = this.top();
+
+ if (top === bindable) {
+ return;
+ }
+
+ if (top) {
+ top.deactivate();
+ }
+
+ this._bindStack.push(bindable);
+
+ bindable.activate(top);
+};
+
+x3dom.BindableStack.prototype.replaceTop = function (bindable) {
+ var top = this.top();
+
+ if (top === bindable) {
+ return;
+ }
+
+ if (top) {
+ top.deactivate();
+
+ this._bindStack[this._bindStack.length - 1] = bindable;
+
+ bindable.activate(top);
+ }
+};
+
+x3dom.BindableStack.prototype.pop = function (bindable) {
+ var top;
+
+ if (bindable) {
+ top = this.top();
+ if (bindable !== top) {
+ return null;
+ }
+ }
+
+ top = this._bindStack.pop();
+
+ if (top) {
+ top.deactivate();
+ }
+
+ return top;
+};
+
+x3dom.BindableStack.prototype.switchTo = function (target) {
+ var last = this.getActive();
+ var n = this._bindBag.length;
+ var toBind = 0;
+ var i = 0, lastIndex = -1;
+
+ if (n <= 1) {
+ return;
+ }
+
+ switch (target)
+ {
+ case 'first':
+ toBind = this._bindBag[0];
+ break;
+ case 'last':
+ toBind = this._bindBag[n-1];
+ break;
+ default:
+ for (i = 0; i < n; i++) {
+ if (this._bindBag[i] == last) {
+ lastIndex = i;
+ break;
+ }
+ }
+ if (lastIndex >= 0) {
+ i = lastIndex;
+ while (!toBind) {
+ if (target == 'next') {
+ i = (i < (n-1)) ? (i+1) : 0;
+ } else { // prev
+ i = (i>0) ? (i-1) : (n-1);
+ }
+ if (i == lastIndex) {
+ break;
+ }
+ if (this._bindBag[i]._vf.description.length >= 0) {
+ toBind = this._bindBag[i];
+ }
+ }
+ }
+ break;
+ }
+
+ if (toBind) {
+ this.replaceTop(toBind);
+ } else {
+ x3dom.debug.logWarning ('Cannot switch bindable; no other bindable with description found.');
+ }
+};
+
+// Get currently active bindable of given stack type, creates new if none exists
+x3dom.BindableStack.prototype.getActive = function () {
+ if (this._bindStack.length === 0) {
+ if (this._bindBag.length === 0) {
+ if (this._defaultRoot) {
+ x3dom.debug.logInfo ('create new ' + this._defaultType._typeName +
+ ' for ' + this._type._typeName + '-stack');
+ var obj = new this._defaultType(
+ { doc: this._doc, nameSpace: this._defaultRoot._nameSpace, autoGen: true } );
+
+ this._defaultRoot.addChild(obj);
+ obj.nodeChanged();
+ }
+ else {
+ x3dom.debug.logError ('stack without defaultRoot');
+ }
+ }
+ else {
+ x3dom.debug.logInfo ('activate first ' + this._type._typeName +
+ ' for ' + this._type._typeName + '-stack');
+ }
+
+ this._bindStack.push(this._bindBag[0]);
+ this._bindBag[0].activate();
+ }
+
+ return this._bindStack[this._bindStack.length - 1];
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// BindableBag constructor
+///////////////////////////////////////////////////////////////////////////////
+x3dom.BindableBag = function (doc) {
+ this._stacks = [];
+
+ this.addType ("X3DViewpointNode", "Viewpoint", "getViewpoint", doc);
+ this.addType ("X3DNavigationInfoNode", "NavigationInfo", "getNavigationInfo", doc);
+ this.addType ("X3DBackgroundNode", "Background", "getBackground", doc);
+ this.addType ("X3DFogNode", "Fog", "getFog", doc);
+ this.addType ("X3DEnvironmentNode", "Environment", "getEnvironment", doc);
+};
+
+x3dom.BindableBag.prototype.addType = function(typeName, defaultTypeName, getter, doc) {
+ var type = x3dom.nodeTypes[typeName];
+ var defaultType = x3dom.nodeTypes[defaultTypeName];
+
+ if (type && defaultType) {
+ var stack = new x3dom.BindableStack (doc, type, defaultType, getter);
+ this._stacks.push(stack);
+ }
+ else {
+ x3dom.debug.logWarning('Invalid Bindable type/defaultType: ' +
+ typeName + '/' + defaultType);
+ }
+};
+
+x3dom.BindableBag.prototype.setRefNode = function (node) {
+ Array.forEach ( this._stacks, function (stack) {
+ // set reference to Scene
+ stack._defaultRoot = node;
+ node[stack._getter] = function () { return stack.getActive(); };
+ } );
+};
+
+x3dom.BindableBag.prototype.addBindable = function(node) {
+ for (var i = 0, n = this._stacks.length; i < n; i++) {
+ var stack = this._stacks[i];
+
+ if ( x3dom.isa (node, stack._type) ) {
+ x3dom.debug.logInfo('register ' + node.typeName() + 'Bindable ' +
+ node._DEF + '/' + node._vf.description);
+
+ stack._bindBag.push(node);
+
+ var top = stack.top();
+
+ if (top && top._autoGen) {
+ stack.replaceTop(node);
+
+ // remove auto-generated default bindable
+ for (var j = 0, m = stack._bindBag.length; j < m; j++) {
+ if (stack._bindBag[j] === top) {
+ stack._bindBag.splice(j, 1);
+ break;
+ }
+ }
+ stack._defaultRoot.removeChild(top);
+ }
+
+ return stack;
+ }
+ }
+
+ x3dom.debug.logError (node.typeName() + ' is not a valid bindable');
+ return null;
+};
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DGeometryNode ### */
+x3dom.registerNodeType(
+ "X3DGeometryNode",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for X3DGeometryNode
+ * @constructs x3dom.nodeTypes.X3DGeometryNode
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all geometry in X3D.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DGeometryNode.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies whether backface-culling is used. If solid is TRUE only front-faces are drawn.
+ * @var {x3dom.fields.SFBool} solid
+ * @memberof x3dom.nodeTypes.X3DGeometryNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'solid', true);
+
+ /**
+ * The ccw field defines the ordering of the vertex coordinates of the geometry with respect to user-given or automatically generated normal vectors used in the lighting model equations.
+ * @var {x3dom.fields.SFBool} ccw
+ * @memberof x3dom.nodeTypes.X3DGeometryNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'ccw', true);
+
+ /**
+ * Most geo primitives use geo cache and others might later on, but one should be able to disable cache per geometry node.
+ * @var {x3dom.fields.SFBool} useGeoCache
+ * @memberof x3dom.nodeTypes.X3DGeometryNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'useGeoCache', true);
+
+ /**
+ * Specifies whether this geometry should be rendered with or without lighting.
+ * @var {x3dom.fields.SFBool} lit
+ * @memberof x3dom.nodeTypes.X3DGeometryNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'lit', true);
+
+ // mesh object also holds volume (_vol)
+ this._mesh = new x3dom.Mesh(this);
+
+ },
+ {
+ getVolume: function() {
+ // geometry doesn't hold volume, but mesh does
+ return this._mesh.getVolume();
+ },
+
+ invalidateVolume: function() {
+ this._mesh.invalidate();
+ },
+
+ getCenter: function() {
+ return this._mesh.getCenter();
+ },
+
+ getDiameter: function() {
+ return this._mesh.getDiameter();
+ },
+
+ doIntersect: function(line) {
+ return this._mesh.doIntersect(line);
+ },
+
+ forceUpdateCoverage: function() {
+ return false;
+ },
+
+ hasIndexOffset: function() {
+ return false;
+ },
+
+ getColorTexture: function() {
+ return null;
+ },
+
+ getColorTextureURL: function() {
+ return null;
+ },
+
+ parentAdded: function(parent) {
+ if (x3dom.isa(parent, x3dom.nodeTypes.X3DShapeNode)) {
+ if (parent._cleanupGLObjects) {
+ parent._cleanupGLObjects(true);
+ }
+ parent.setAllDirty();
+ parent.invalidateVolume();
+ }
+ },
+
+ needLighting: function() {
+ var hasTris = this._mesh._primType.indexOf("TRIANGLE") >= 0;
+ return (this._vf.lit && hasTris);
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Mesh ### */
+x3dom.registerNodeType(
+ "Mesh", // experimental WebSG geo node
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometryNode,
+
+ /**
+ * Constructor for Mesh
+ * @constructs x3dom.nodeTypes.Mesh
+ * @x3d x.x
+ * @component Rendering
+ * @extends x3dom.nodeTypes.X3DGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is an experimental WebSG geo node
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Mesh.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} primType
+ * @memberof x3dom.nodeTypes.Mesh
+ * @initvalue "triangle"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'primType', "triangle");
+
+ /**
+ *
+ * @var {x3dom.fields.MFInt32} index
+ * @memberof x3dom.nodeTypes.Mesh
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'index', []);
+
+
+ /**
+ *
+ * @var {x3dom.fields.MFNode} vertexAttributes
+ * @memberof x3dom.nodeTypes.Mesh
+ * @initvalue x3dom.nodeTypes.X3DVertexAttributeNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFNode('vertexAttributes', x3dom.nodeTypes.X3DVertexAttributeNode);
+
+ },
+ {
+ nodeChanged: function()
+ {
+ var time0 = new Date().getTime();
+
+ var i, n = this._cf.vertexAttributes.nodes.length;
+
+ for (i=0; i<n; i++)
+ {
+ var name = this._cf.vertexAttributes.nodes[i]._vf.name;
+
+ switch (name.toLowerCase())
+ {
+ case "position":
+ this._mesh._positions[0] = this._cf.vertexAttributes.nodes[i]._vf.value.toGL();
+ break;
+ case "normal":
+ this._mesh._normals[0] = this._cf.vertexAttributes.nodes[i]._vf.value.toGL();
+ break;
+ case "texcoord":
+ this._mesh._texCoords[0] = this._cf.vertexAttributes.nodes[i]._vf.value.toGL();
+ break;
+ case "color":
+ this._mesh._colors[0] = this._cf.vertexAttributes.nodes[i]._vf.value.toGL();
+ break;
+ default:
+ this._mesh._dynamicFields[name] = {};
+ this._mesh._dynamicFields[name].numComponents =
+ this._cf.vertexAttributes.nodes[i]._vf.numComponents;
+ this._mesh._dynamicFields[name].value =
+ this._cf.vertexAttributes.nodes[i]._vf.value.toGL();
+ break;
+ }
+ }
+
+ this._mesh._indices[0] = this._vf.index.toGL();
+
+ this.invalidateVolume();
+
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ var time1 = new Date().getTime() - time0;
+ x3dom.debug.logWarning("Mesh load time: " + time1 + " ms");
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PointSet ### */
+x3dom.registerNodeType(
+ "PointSet",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometryNode,
+
+ /**
+ * Constructor for PointSet
+ * @constructs x3dom.nodeTypes.PointSet
+ * @x3d 3.3
+ * @component Rendering
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc PointSet is a node that contains a set of colored 3D points, represented by contained Color and Coordinate nodes.
+ * Color values or a Material emissiveColor is used to draw lines and points. Hint: use a different color (or emissiveColor) than the background color.
+ * Hint: insert a Shape node before adding geometry or Appearance. You can also substitute a type-matched ProtoInstance for content.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PointSet.superClass.call(this, ctx);
+
+
+ /**
+ * Coordinate node specifiying the vertices used by the geometry.
+ * @var {x3dom.fields.SFNode} coord
+ * @memberof x3dom.nodeTypes.PointSet
+ * @initvalue x3dom.nodeTypes.X3DCoordinateNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('coord', x3dom.nodeTypes.X3DCoordinateNode);
+
+ /**
+ * If NULL the geometry is rendered using the Material and texture defined in the Appearance node.
+ * If not NULL the field shall contain a Color node whose colours are applied depending on the value of "colorPerVertex".
+ * @var {x3dom.fields.SFNode} color
+ * @memberof x3dom.nodeTypes.PointSet
+ * @initvalue x3dom.nodeTypes.X3DColorNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('color', x3dom.nodeTypes.X3DColorNode);
+
+ this._mesh._primType = 'POINTS';
+
+ },
+ {
+ nodeChanged: function()
+ {
+ var time0 = new Date().getTime();
+
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode, "PointSet without coord node!");
+ var positions = coordNode.getPoints();
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ var colors = new x3dom.fields.MFColor();
+ if (colorNode) {
+ colors = colorNode._vf.color;
+ x3dom.debug.assert(positions.length == colors.length, "Size of color and coord array differs!");
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+
+ this._mesh._numColComponents = numColComponents;
+ this._mesh._lit = false;
+
+ this._mesh._indices[0] = [];
+ this._mesh._positions[0] = positions.toGL();
+ this._mesh._colors[0] = colors.toGL();
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+
+ this.invalidateVolume();
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ var time1 = new Date().getTime() - time0;
+ //x3dom.debug.logInfo("Mesh load time: " + time1 + " ms");
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ var pnts = null;
+
+ if (fieldName == "coord")
+ {
+ pnts = this._cf.coord.node.getPoints();
+
+ this._mesh._positions[0] = pnts.toGL();
+
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color")
+ {
+ pnts = this._cf.color.node._vf.color;
+
+ this._mesh._colors[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DComposedGeometryNode ### */
+x3dom.registerNodeType(
+ "X3DComposedGeometryNode",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometryNode,
+
+ /**
+ * Constructor for X3DComposedGeometryNode
+ * @constructs x3dom.nodeTypes.X3DComposedGeometryNode
+ * @x3d 3.3
+ * @component Rendering
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all composed 3D geometry in X3D.
+ * A composed geometry node type defines an abstract type that composes geometry from a set of nodes that define individual components.
+ * Composed geometry may have color, coordinates, normal and texture coordinates supplied.
+ * The rendered output of the combination of these is dependent on the concrete node definition.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DComposedGeometryNode.superClass.call(this, ctx);
+
+
+ /**
+ * If colorPerVertex is FALSE, colours are applied to each face. If colorPerVertex is true, colours are applied to each vertex.
+ * @var {x3dom.fields.SFBool} colorPerVertex
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'colorPerVertex', true);
+
+ /**
+ * If normalPerVertex is FALSE, colours are applied to each face. If normalPerVertex is true, normals are applied to each vertex.
+ * @var {x3dom.fields.SFBool} normalPerVertex
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'normalPerVertex', true);
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} normalUpdateMode
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue 'fast'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'normalUpdateMode', 'fast'); // none; fast; nice
+
+
+ /**
+ * If the attrib field is not empty it shall contain a list of per-vertex attribute information for programmable shaders.
+ * @var {x3dom.fields.MFNode} attrib
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue x3dom.nodeTypes.X3DVertexAttributeNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFNode('attrib', x3dom.nodeTypes.X3DVertexAttributeNode);
+
+
+ /**
+ * Contains a Coordinate node.
+ * @var {x3dom.fields.SFNode} coord
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue x3dom.nodeTypes.X3DCoordinateNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('coord', x3dom.nodeTypes.X3DCoordinateNode);
+
+ /**
+ * If the normal field is not NULL, it shall contain a Normal node whose normals are applied to the vertices or faces of the X3DComposedGeometryNode in a manner exactly equivalent to that described above for applying colours to vertices/faces (where normalPerVertex corresponds to colorPerVertex and normalIndex corresponds to colorIndex).
+ * If the normal field is NULL, the browser shall automatically generate normals in accordance with the node's definition. If the node does not define a behaviour, the default is to generate an averaged normal for all faces that share that vertex.
+ * @var {x3dom.fields.SFNode} normal
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue x3dom.nodeTypes.Normal
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('normal', x3dom.nodeTypes.Normal);
+
+ /**
+ * If the color field is NULL, the geometry shall be rendered normally using the Material and texture defined in the Appearance node.
+ * @var {x3dom.fields.SFNode} color
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue x3dom.nodeTypes.X3DColorNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('color', x3dom.nodeTypes.X3DColorNode);
+
+ /**
+ * If the texCoord field is not NULL, it shall contain a TextureCoordinate node.
+ * @var {x3dom.fields.SFNode} texCoord
+ * @memberof x3dom.nodeTypes.X3DComposedGeometryNode
+ * @initvalue x3dom.nodeTypes.X3DTextureCoordinateNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('texCoord', x3dom.nodeTypes.X3DTextureCoordinateNode);
+
+ },
+ {
+ handleAttribs: function()
+ {
+ //var time0 = new Date().getTime();
+
+ // TODO; handle case that more than 2^16-1 attributes are to be referenced
+ var i, n = this._cf.attrib.nodes.length;
+
+ for (i=0; i<n; i++)
+ {
+ var name = this._cf.attrib.nodes[i]._vf.name;
+
+ switch (name.toLowerCase())
+ {
+ case "position":
+ this._mesh._positions[0] = this._cf.attrib.nodes[i]._vf.value.toGL();
+ break;
+ case "normal":
+ this._mesh._normals[0] = this._cf.attrib.nodes[i]._vf.value.toGL();
+ break;
+ case "texcoord":
+ this._mesh._texCoords[0] = this._cf.attrib.nodes[i]._vf.value.toGL();
+ break;
+ case "color":
+ this._mesh._colors[0] = this._cf.attrib.nodes[i]._vf.value.toGL();
+ break;
+ default:
+ this._mesh._dynamicFields[name] = {};
+ this._mesh._dynamicFields[name].numComponents =
+ this._cf.attrib.nodes[i]._vf.numComponents;
+ this._mesh._dynamicFields[name].value =
+ this._cf.attrib.nodes[i]._vf.value.toGL();
+ break;
+ }
+ }
+
+ //var time1 = new Date().getTime() - time0;
+ //x3dom.debug.logInfo("Mesh load time: " + time1 + " ms");
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### LineSet ### */
+x3dom.registerNodeType(
+ "LineSet",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometryNode,
+
+ /**
+ * Constructor for LineSet
+ * @constructs x3dom.nodeTypes.LineSet
+ * @x3d 3.3
+ * @component Rendering
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc LineSet is a geometry node that can contain a Color node and a Coordinate node.
+ * Color values or a Material emissiveColor is used to draw lines and points.
+ * Lines are not lit, are not texture-mapped, and do not participate in collision detection.
+ * Hint: use a different color (or emissiveColor) than the background color.
+ * Hint: if rendering Coordinate points originally defined for an IndexedFaceSet, index values may need to repeat each initial vertex to close each polygon outline.
+ * Hint: insert a Shape node before adding geometry or Appearance.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.LineSet.superClass.call(this, ctx);
+
+
+ /**
+ * vertexCount describes how many vertices are used in each polyline from Coordinate field. Coordinates are assigned to each line by taking vertexCount[n] vertices from Coordinate field.
+ * @var {x3dom.fields.MFInt32} vertexCount
+ * @range [2, inf]
+ * @memberof x3dom.nodeTypes.LineSet
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'vertexCount', []);
+
+
+ /**
+ * If the "attrib" field is not empty it shall contain a list of per-vertex attribute information for programmable shaders
+ * @var {x3dom.fields.MFNode} attrib
+ * @memberof x3dom.nodeTypes.LineSet
+ * @initvalue x3dom.nodeTypes.X3DVertexAttributeNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('attrib', x3dom.nodeTypes.X3DVertexAttributeNode);
+
+ /**
+ * Coordinate node specifiying the vertices used by the geometry.
+ * @var {x3dom.fields.SFNode} coord
+ * @memberof x3dom.nodeTypes.LineSet
+ * @initvalue x3dom.nodeTypes.X3DCoordinateNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('coord', x3dom.nodeTypes.X3DCoordinateNode);
+
+ /**
+ * If NULL the geometry is rendered using the Material and texture defined in the Appearance node. If not NULL the field shall contain a Color node whose colours are applied depending on the value of "colorPerVertex".
+ * @var {x3dom.fields.SFNode} color
+ * @memberof x3dom.nodeTypes.LineSet
+ * @initvalue x3dom.nodeTypes.X3DColorNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('color', x3dom.nodeTypes.X3DColorNode);
+
+ this._mesh._primType = "LINES";
+ x3dom.Utils.needLineWidth = true;
+
+ },
+ {
+ nodeChanged: function() {
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode);
+ var positions = coordNode.getPoints();
+
+ this._mesh._positions[0] = positions.toGL();
+
+ var colorNode = this._cf.color.node;
+ if (colorNode) {
+ var colors = colorNode._vf.color;
+
+ this._mesh._colors[0] = colors.toGL();
+
+ this._mesh._numColComponents = 3;
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ this._mesh._numColComponents = 4;
+ }
+ }
+
+ var cnt = 0;
+ this._mesh._indices[0] = [];
+
+ for (var i=0, n=this._vf.vertexCount.length; i<n; i++) {
+ var vc = this._vf.vertexCount[i];
+ if (vc < 2) {
+ x3dom.debug.logError("LineSet.vertexCount must not be smaller than 2!");
+ break;
+ }
+ for (var j=vc-2; j>=0; j--) {
+ this._mesh._indices[0].push(cnt++, cnt);
+ if (j == 0) cnt++;
+ }
+ }
+ },
+
+ fieldChanged: function(fieldName) {
+ if (fieldName == "coord") {
+ var pnts = this._cf.coord.node.getPoints();
+ this._mesh._positions[0] = pnts.toGL();
+
+ this.invalidateVolume();
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color") {
+ var cols = this._cf.color.node._vf.color;
+ this._mesh._colors[0] = cols.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### IndexedLineSet ### */
+x3dom.registerNodeType(
+ "IndexedLineSet",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometryNode,
+
+ /**
+ * Constructor for IndexedLineSet
+ * @constructs x3dom.nodeTypes.IndexedLineSet
+ * @x3d 3.3
+ * @component Rendering
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc IndexedLineSet is a geometry node that can contain a Color node and a Coordinate node.
+ * Color values or a Material emissiveColor is used to draw lines and points. Lines are not lit, are not texture-mapped, and do not participate in collision detection.
+ * Hint: use a different color (or emissiveColor) than the background color.
+ * Hint: if rendering Coordinate points originally defined for an IndexedFaceSet, index values may need to repeat each initial vertex to close each polygon outline.
+ * Hint: insert a Shape node before adding geometry or Appearance. You can also substitute a type-matched ProtoInstance for content.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.IndexedLineSet.superClass.call(this, ctx);
+
+
+ /**
+ * Whether Color node is applied per vertex (true) or per polygon (false).
+ * @var {x3dom.fields.SFBool} colorPerVertex
+ * @memberof x3dom.nodeTypes.IndexedLineSet
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'colorPerVertex', true); // TODO
+
+
+ /**
+ * If the "attrib" field is not empty it shall contain a list of per-vertex attribute information for programmable shaders
+ * @var {x3dom.fields.MFNode} attrib
+ * @memberof x3dom.nodeTypes.IndexedLineSet
+ * @initvalue x3dom.nodeTypes.X3DVertexAttributeNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('attrib', x3dom.nodeTypes.X3DVertexAttributeNode);
+
+ /**
+ * Coordinate node specifiying the vertices used by the geometry.
+ * @var {x3dom.fields.SFNode} coord
+ * @memberof x3dom.nodeTypes.IndexedLineSet
+ * @initvalue x3dom.nodeTypes.X3DCoordinateNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('coord', x3dom.nodeTypes.X3DCoordinateNode);
+
+ /**
+ * If NULL the geometry is rendered using the Material and texture defined in the Appearance node. If not NULL the field shall contain a Color node whose colours are applied depending on the value of "colorPerVertex".
+ * @var {x3dom.fields.SFNode} color
+ * @memberof x3dom.nodeTypes.IndexedLineSet
+ * @initvalue x3dom.nodeTypes.X3DColorNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('color', x3dom.nodeTypes.X3DColorNode);
+
+
+ /**
+ * coordIndex indices provide order in which coordinates are applied.
+ * Order starts at index 0, commas are optional between sets, use -1 to separate indices for each polyline.
+ * Hint: if rendering Coordinate points originally defined for an IndexedFaceSet, index values may need to repeat initial each initial vertex to close the polygons.
+ * @var {x3dom.fields.MFInt32} coordIndex
+ * @range [0, inf] or -1
+ * @memberof x3dom.nodeTypes.IndexedLineSet
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'coordIndex', []);
+
+ /**
+ * colorIndex indices provide order in which colors are applied.
+ * Hint: if rendering Coordinate points originally defined for an IndexedFaceSet, index values may need to repeat initial each initial vertex to close the polygons.
+ * @var {x3dom.fields.MFInt32} colorIndex
+ * @range [0, inf] or -1
+ * @memberof x3dom.nodeTypes.IndexedLineSet
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'colorIndex', []);
+
+ this._mesh._primType = 'LINES';
+ x3dom.Utils.needLineWidth = true;
+
+ },
+ {
+ nodeChanged: function()
+ {
+ var time0 = new Date().getTime();
+
+ // this.handleAttribs();
+
+ var indexes = this._vf.coordIndex;
+ var colorInd = this._vf.colorIndex;
+
+ var hasColor = false, hasColorInd = false;
+
+ // TODO; implement colorPerVertex also for single index
+ var colPerVert = this._vf.colorPerVertex;
+
+ if (colorInd.length > 0)
+ {
+ hasColorInd = true;
+ }
+
+ var positions, colors;
+
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode);
+
+ positions = coordNode.getPoints();
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ if (colorNode)
+ {
+ hasColor = true;
+ colors = colorNode._vf.color;
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+ else {
+ hasColor = false;
+ }
+
+ this._mesh._indices[0] = [];
+ this._mesh._positions[0] = [];
+ this._mesh._colors[0] = [];
+
+ var i, t, cnt, lineCnt;
+ var p0, p1, c0, c1;
+
+ // Found MultiIndex Mesh OR LineSet with too many vertices for 16 bit
+ if ( (hasColor && hasColorInd) || positions.length > x3dom.Utils.maxIndexableCoords )
+ {
+ t = 0;
+ cnt = 0;
+ lineCnt = 0;
+
+ for (i=0; i < indexes.length; ++i)
+ {
+ if (indexes[i] === -1) {
+ t = 0;
+ continue;
+ }
+
+ if (hasColorInd) {
+ x3dom.debug.assert(colorInd[i] != -1);
+ }
+
+ switch (t)
+ {
+ case 0:
+ p0 = +indexes[i];
+ if (hasColorInd && colPerVert) { c0 = +colorInd[i]; }
+ else { c0 = p0; }
+ t = 1;
+ break;
+ case 1:
+ p1 = +indexes[i];
+ if (hasColorInd && colPerVert) { c1 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c1 = +colorInd[lineCnt]; }
+ else { c1 = p1; }
+
+ this._mesh._indices[0].push(cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p0].x);
+ this._mesh._positions[0].push(positions[p0].y);
+ this._mesh._positions[0].push(positions[p0].z);
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+
+ if (hasColor) {
+ if (!colPerVert) {
+ c0 = c1;
+ }
+ this._mesh._colors[0].push(colors[c0].r);
+ this._mesh._colors[0].push(colors[c0].g);
+ this._mesh._colors[0].push(colors[c0].b);
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ }
+
+ t = 2;
+ lineCnt++;
+ break;
+ case 2:
+ p0 = p1;
+ c0 = c1;
+ p1 = +indexes[i];
+ if (hasColorInd && colPerVert) { c1 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c1 = +colorInd[lineCnt]; }
+ else { c1 = p1; }
+
+ this._mesh._indices[0].push(cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p0].x);
+ this._mesh._positions[0].push(positions[p0].y);
+ this._mesh._positions[0].push(positions[p0].z);
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+
+ if (hasColor) {
+ if (!colPerVert) {
+ c0 = c1;
+ }
+ this._mesh._colors[0].push(colors[c0].r);
+ this._mesh._colors[0].push(colors[c0].g);
+ this._mesh._colors[0].push(colors[c0].b);
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ }
+
+ lineCnt++;
+ break;
+ default:
+ }
+ }
+
+ //if the LineSet is too large for 16 bit indices, split it!
+ if (positions.length > x3dom.Utils.maxIndexableCoords)
+ this._mesh.splitMesh(2);
+ } // if isMulti
+ else
+ {
+ var n = indexes.length;
+ t = 0;
+
+ for (i=0; i < n; ++i)
+ {
+ if (indexes[i] == -1) {
+ t = 0;
+ continue;
+ }
+
+ switch (t) {
+ case 0: p0 = +indexes[i]; t = 1; break;
+ case 1: p1 = +indexes[i]; t = 2; this._mesh._indices[0].push(p0, p1); break;
+ case 2: p0 = p1; p1 = +indexes[i]; this._mesh._indices[0].push(p0, p1); break;
+ }
+ }
+
+ this._mesh._positions[0] = positions.toGL();
+
+ if (hasColor) {
+ this._mesh._colors[0] = colors.toGL();
+ this._mesh._numColComponents = numColComponents;
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numCoords = 0;
+
+ for (i=0; i<this._mesh._indices.length; i++) {
+ this._mesh._numCoords += this._mesh._positions[i].length / 3;
+ }
+
+ var time1 = new Date().getTime() - time0;
+ //x3dom.debug.logInfo("Mesh load time: " + time1 + " ms");
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ var pnts = null;
+
+ if (fieldName == "coord")
+ {
+ pnts = this._cf.coord.node._vf.point;
+
+ this._mesh._positions[0] = pnts.toGL();
+
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color")
+ {
+ pnts = this._cf.color.node._vf.color;
+
+ this._mesh._colors[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ else if (fieldName == "coordIndex") {
+ this._mesh._indices[0] = [];
+
+ var indexes = this._vf.coordIndex;
+ var p0, p1, t = 0;
+
+ for (var i=0, n=indexes.length; i < n; ++i) {
+ if (indexes[i] == -1) {
+ t = 0;
+ }
+ else {
+ switch (t) {
+ case 0: p0 = +indexes[i]; t = 1; break;
+ case 1: p1 = +indexes[i]; t = 2; this._mesh._indices[0].push(p0, p1); break;
+ case 2: p0 = p1; p1 = +indexes[i]; this._mesh._indices[0].push(p0, p1); break;
+ }
+ }
+ }
+
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.indexes = true;
+ node.invalidateVolume();
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### IndexedTriangleSet ### */
+x3dom.registerNodeType(
+ "IndexedTriangleSet",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DComposedGeometryNode,
+
+ /**
+ * Constructor for IndexedTriangleSet
+ * @constructs x3dom.nodeTypes.IndexedTriangleSet
+ * @x3d 3.3
+ * @component Rendering
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DComposedGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc IndexedTriangleSet is a geometry node that can contain a Color, Coordinate, Normal and TextureCoordinate node.
+ * Hint: insert a Shape node before adding geometry or Appearance.
+ * You can also substitute a type-matched ProtoInstance for content.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.IndexedTriangleSet.superClass.call(this, ctx);
+
+
+ /**
+ * index specifies triangles by connecting Coordinate vertices.
+ * @var {x3dom.fields.MFInt32} index
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.IndexedTriangleSet
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'index', []);
+
+ },
+ {
+ nodeChanged: function()
+ {
+ var time0 = new Date().getTime();
+
+ this.handleAttribs();
+
+ var colPerVert = this._vf.colorPerVertex;
+ var normPerVert = this._vf.normalPerVertex;
+
+ var indexes = this._vf.index;
+
+ var hasNormal = false, hasTexCoord = false, hasColor = false;
+ var positions, normals, texCoords, colors;
+
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode);
+ positions = coordNode._vf.point;
+
+ var normalNode = this._cf.normal.node;
+ if (normalNode) {
+ hasNormal = true;
+ normals = normalNode._vf.vector;
+ }
+ else {
+ hasNormal = false;
+ }
+
+ var texMode = "", numTexComponents = 2;
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ if (texCoordNode) {
+ if (texCoordNode._vf.point) {
+ hasTexCoord = true;
+ texCoords = texCoordNode._vf.point;
+
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.TextureCoordinate3D)) {
+ numTexComponents = 3;
+ }
+ }
+ else if (texCoordNode._vf.mode) {
+ texMode = texCoordNode._vf.mode;
+ }
+ }
+ else {
+ hasTexCoord = false;
+ }
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ if (colorNode) {
+ hasColor = true;
+ colors = colorNode._vf.color;
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+ else {
+ hasColor = false;
+ }
+
+ this._mesh._indices[0] = [];
+ this._mesh._positions[0] = [];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+ this._mesh._colors[0] = [];
+
+ var i, t, cnt, faceCnt, posMax;
+ var p0, p1, p2, n0, n1, n2, t0, t1, t2, c0, c1, c2;
+
+ // if positions array too short add degenerate triangle
+ while (positions.length % 3 > 0) {
+ positions.push(positions.length-1);
+ }
+ posMax = positions.length;
+
+ if (!normPerVert || posMax > x3dom.Utils.maxIndexableCoords)
+ {
+ t = 0;
+ cnt = 0;
+ faceCnt = 0;
+ this._mesh._multiIndIndices = [];
+ this._mesh._posSize = positions.length;
+
+ for (i=0; i < indexes.length; ++i)
+ {
+ // Convert non-triangular polygons to a triangle fan
+ // (TODO: this assumes polygons are convex)
+
+ if ((i > 0) && (i % 3 === 0 )) {
+ t = 0;
+ faceCnt++;
+ }
+
+ //TODO: OPTIMIZE but think about cache coherence regarding arrays!!!
+ switch (t)
+ {
+ case 0:
+ p0 = +indexes[i];
+ if (normPerVert) {
+ n0 = p0;
+ } else if (!normPerVert) {
+ n0 = faceCnt;
+ }
+ t0 = p0;
+ if (colPerVert) {
+ c0 = p0;
+ } else if (!colPerVert) {
+ c0 = faceCnt;
+ }
+ t = 1;
+ break;
+ case 1:
+ p1 = +indexes[i];
+ if (normPerVert) {
+ n1 = p1;
+ } else if (!normPerVert) {
+ n1 = faceCnt;
+ }
+ t1 = p1;
+ if (colPerVert) {
+ c1 = p1;
+ } else if (!colPerVert) {
+ c1 = faceCnt;
+ }
+ t = 2;
+ break;
+ case 2:
+ p2 = +indexes[i];
+ if (normPerVert) {
+ n2 = p2;
+ } else if (!normPerVert) {
+ n2 = faceCnt;
+ }
+ t2 = p2;
+ if (colPerVert) {
+ c2 = p2;
+ } else if (!colPerVert) {
+ c2 = faceCnt;
+ }
+ t = 3;
+
+ this._mesh._indices[0].push(cnt++, cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p0].x);
+ this._mesh._positions[0].push(positions[p0].y);
+ this._mesh._positions[0].push(positions[p0].z);
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+ this._mesh._positions[0].push(positions[p2].x);
+ this._mesh._positions[0].push(positions[p2].y);
+ this._mesh._positions[0].push(positions[p2].z);
+
+ if (hasNormal) {
+ this._mesh._normals[0].push(normals[n0].x);
+ this._mesh._normals[0].push(normals[n0].y);
+ this._mesh._normals[0].push(normals[n0].z);
+ this._mesh._normals[0].push(normals[n1].x);
+ this._mesh._normals[0].push(normals[n1].y);
+ this._mesh._normals[0].push(normals[n1].z);
+ this._mesh._normals[0].push(normals[n2].x);
+ this._mesh._normals[0].push(normals[n2].y);
+ this._mesh._normals[0].push(normals[n2].z);
+ }
+ else {
+ this._mesh._multiIndIndices.push(p0, p1, p2);
+ //this._mesh._multiIndIndices.push(cnt-3, cnt-2, cnt-1);
+ }
+
+ if (hasColor) {
+ this._mesh._colors[0].push(colors[c0].r);
+ this._mesh._colors[0].push(colors[c0].g);
+ this._mesh._colors[0].push(colors[c0].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c0].a);
+ }
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c1].a);
+ }
+ this._mesh._colors[0].push(colors[c2].r);
+ this._mesh._colors[0].push(colors[c2].g);
+ this._mesh._colors[0].push(colors[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c2].a);
+ }
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(texCoords[t0].x);
+ this._mesh._texCoords[0].push(texCoords[t0].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t0].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t1].x);
+ this._mesh._texCoords[0].push(texCoords[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t1].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t2].x);
+ this._mesh._texCoords[0].push(texCoords[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t2].z);
+ }
+ }
+
+ //faceCnt++;
+ break;
+ default:
+ }
+ }
+
+ if (!hasNormal) {
+ this._mesh.calcNormals(normPerVert ? Math.PI : 0);
+ }
+ if (!hasTexCoord) {
+ this._mesh.calcTexCoords(texMode);
+ }
+
+ this._mesh.splitMesh();
+
+ //x3dom.debug.logInfo(this._mesh._indices.length);
+ } // if isMulti
+ else
+ {
+ faceCnt = 0;
+ for (i=0; i<indexes.length; i++)
+ {
+ if ((i > 0) && (i % 3 === 0 )) {
+ faceCnt++;
+ }
+
+ this._mesh._indices[0].push(indexes[i]);
+
+ if(!normPerVert && hasNormal) {
+ this._mesh._normals[0].push(normals[faceCnt].x);
+ this._mesh._normals[0].push(normals[faceCnt].y);
+ this._mesh._normals[0].push(normals[faceCnt].z);
+ }
+ if(!colPerVert && hasColor) {
+ this._mesh._colors[0].push(colors[faceCnt].r);
+ this._mesh._colors[0].push(colors[faceCnt].g);
+ this._mesh._colors[0].push(colors[faceCnt].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[faceCnt].a);
+ }
+ }
+ }
+
+ this._mesh._positions[0] = positions.toGL();
+
+ if (hasNormal) {
+ this._mesh._normals[0] = normals.toGL();
+ }
+ else {
+ this._mesh.calcNormals(normPerVert ? Math.PI : 0);
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0] = texCoords.toGL();
+ this._mesh._numTexComponents = numTexComponents;
+ }
+ else {
+ this._mesh.calcTexCoords(texMode);
+ }
+
+ if (hasColor && colPerVert) {
+ this._mesh._colors[0] = colors.toGL();
+ this._mesh._numColComponents = numColComponents;
+ }
+ }
+
+ this.invalidateVolume();
+
+ this._mesh._numFaces = 0;
+ this._mesh._numCoords = 0;
+ for (i=0; i<this._mesh._indices.length; i++) {
+ this._mesh._numFaces += this._mesh._indices[i].length / 3;
+ this._mesh._numCoords += this._mesh._positions[i].length / 3;
+ }
+
+ var time1 = new Date().getTime() - time0;
+ //x3dom.debug.logInfo("Mesh load time: " + time1 + " ms");
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ var pnts = this._cf.coord.node._vf.point;
+
+ if ( pnts.length > x3dom.Utils.maxIndexableCoords ) // are there other problematic cases?
+ {
+ // TODO; implement
+ x3dom.debug.logWarning("IndexedTriangleSet: fieldChanged with " +
+ "too many coordinates not yet implemented!");
+ return;
+ }
+
+ if (fieldName == "coord")
+ {
+ this._mesh._positions[0] = pnts.toGL();
+
+ // tells the mesh that its bbox requires update
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color")
+ {
+ pnts = this._cf.color.node._vf.color;
+
+ if (this._vf.colorPerVertex) {
+
+ this._mesh._colors[0] = pnts.toGL();
+
+ } else if (!this._vf.colorPerVertex) {
+
+ var faceCnt = 0;
+ var numColComponents = 3;
+ if (x3dom.isa(this._cf.color.node, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+
+ this._mesh._colors[0] = [];
+
+ var indexes = this._vf.index;
+ for (var i=0; i < indexes.length; ++i)
+ {
+ if ((i > 0) && (i % 3 === 0 )) {
+ faceCnt++;
+ }
+
+ this._mesh._colors[0].push(pnts[faceCnt].r);
+ this._mesh._colors[0].push(pnts[faceCnt].g);
+ this._mesh._colors[0].push(pnts[faceCnt].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(pnts[faceCnt].a);
+ }
+ }
+ }
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ else if (fieldName == "normal")
+ {
+ pnts = this._cf.normal.node._vf.vector;
+
+ if (this._vf.normalPerVertex) {
+
+ this._mesh._normals[0] = pnts.toGL();
+
+ } else if (!this._vf.normalPerVertex) {
+
+ var indexes = this._vf.index;
+ this._mesh._normals[0] = [];
+
+ var faceCnt = 0;
+ for (var i=0; i < indexes.length; ++i)
+ {
+ if ((i > 0) && (i % 3 === 0 )) {
+ faceCnt++;
+ }
+
+ this._mesh._normals[0].push(pnts[faceCnt].x);
+ this._mesh._normals[0].push(pnts[faceCnt].y);
+ this._mesh._normals[0].push(pnts[faceCnt].z);
+ }
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.normals = true;
+ });
+ }
+ else if (fieldName == "texCoord")
+ {
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ pnts = texCoordNode._vf.point;
+
+ this._mesh._texCoords[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.texcoords = true;
+ });
+ }
+ // TODO: index
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### IndexedTriangleStripSet ### */
+x3dom.registerNodeType(
+ "IndexedTriangleStripSet",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DComposedGeometryNode,
+
+ /**
+ * Constructor for IndexedTriangleStripSet
+ * @constructs x3dom.nodeTypes.IndexedTriangleStripSet
+ * @x3d 3.3
+ * @component Rendering
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DComposedGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc IndexedTriangleStripSet is a geometry node that can contain a Color, Coordinate, Normal and TextureCoordinate node.
+ * Hint: insert a Shape node before adding geometry or Appearance. You can also substitute a type-matched ProtoInstance for content.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.IndexedTriangleStripSet.superClass.call(this, ctx);
+
+
+ /**
+ * Index specifies triangles by connecting Coordinate vertices.
+ * @var {x3dom.fields.MFInt32} index
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.IndexedTriangleStripSet
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'index', []);
+
+ this._hasIndexOffset = false;
+ this._indexOffset = null;
+
+ },
+ {
+ hasIndexOffset: function() {
+ return this._hasIndexOffset;
+ },
+
+ nodeChanged: function()
+ {
+ this.handleAttribs(); // check if method is still functional
+
+ var hasNormal = false, hasTexCoord = false, hasColor = false;
+
+ var colPerVert = this._vf.colorPerVertex;
+ var normPerVert = this._vf.normalPerVertex;
+
+ var indexes = this._vf.index;
+ var positions, normals, texCoords, colors;
+
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode);
+ positions = coordNode._vf.point;
+
+ var normalNode = this._cf.normal.node;
+ if (normalNode) {
+ hasNormal = true;
+ normals = normalNode._vf.vector;
+ }
+ else {
+ hasNormal = false;
+ }
+
+ var texMode = "", numTexComponents = 2;
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ if (texCoordNode) {
+ if (texCoordNode._vf.point) {
+ hasTexCoord = true;
+ texCoords = texCoordNode._vf.point;
+
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.TextureCoordinate3D)) {
+ numTexComponents = 3;
+ }
+ }
+ else if (texCoordNode._vf.mode) {
+ texMode = texCoordNode._vf.mode;
+ }
+ }
+ else {
+ hasTexCoord = false;
+ }
+ this._mesh._numTexComponents = numTexComponents;
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ if (colorNode) {
+ hasColor = true;
+ colors = colorNode._vf.color;
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+ else {
+ hasColor = false;
+ }
+ this._mesh._numColComponents = numColComponents;
+
+ this._mesh._indices[0] = [];
+ this._mesh._positions[0] = [];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+ this._mesh._colors[0] = [];
+
+ this.invalidateVolume();
+ this._mesh._numFaces = 0;
+ this._mesh._numCoords = 0;
+
+ var faceCnt = 0, cnt = 0;
+
+ if (hasNormal && positions.length <= x3dom.Utils.maxIndexableCoords)
+ {
+ this._hasIndexOffset = true;
+ this._indexOffset = [];
+ this._mesh._primType = 'TRIANGLESTRIP';
+
+ var indexOffset = [ 0 ];
+
+ for (i=0; i<indexes.length; i++)
+ {
+ if (indexes[i] == -1) {
+ faceCnt++;
+ indexOffset.push(this._mesh._indices[0].length);
+ }
+ else {
+ this._mesh._indices[0].push(+indexes[i]);
+
+ if(!normPerVert) {
+ this._mesh._normals[0].push(normals[faceCnt].x);
+ this._mesh._normals[0].push(normals[faceCnt].y);
+ this._mesh._normals[0].push(normals[faceCnt].z);
+ }
+ if(!colPerVert) {
+ this._mesh._colors[0].push(colors[faceCnt].r);
+ this._mesh._colors[0].push(colors[faceCnt].g);
+ this._mesh._colors[0].push(colors[faceCnt].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[faceCnt].a);
+ }
+ }
+ }
+ }
+
+ this._mesh._positions[0] = positions.toGL();
+
+ if(normPerVert) {
+ this._mesh._normals[0] = normals.toGL();
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0] = texCoords.toGL();
+ this._mesh._numTexComponents = numTexComponents;
+ }
+ else {
+ x3dom.debug.logWarning("IndexedTriangleStripSet: no texCoords given and won't calculate!");
+ }
+
+ if (hasColor) {
+ if(colPerVert) {
+ this._mesh._colors[0] = colors.toGL();
+ }
+ this._mesh._numColComponents = numColComponents;
+ }
+
+ for (i=1; i<indexOffset.length; i++) {
+ var triCnt = indexOffset[i] - indexOffset[i-1];
+ this._indexOffset.push( {
+ count: triCnt,
+ offset: 2 * indexOffset[i-1]
+ } );
+
+ this._mesh._numFaces += (triCnt - 2);
+ }
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+ }
+ else
+ {
+ this._hasIndexOffset = false;
+
+ var p1, p2 , p3, n1, n2, n3, t1, t2, t3, c1, c2, c3;
+
+ var swapOrder = false;
+
+ for (var i=1; i < indexes.length-2; ++i)
+ {
+ if (indexes[i+1] == -1) {
+ i = i+2;
+ faceCnt++;
+ continue;
+ }
+
+ // care for counterclockwise point order
+ if (swapOrder) {
+ p1 = indexes[i];
+ p2 = indexes[i-1];
+ p3 = indexes[i+1];
+ }
+ else {
+ p1 = indexes[i-1];
+ p2 = indexes[i];
+ p3 = indexes[i+1];
+ }
+ swapOrder = !swapOrder;
+
+ if (normPerVert) {
+ n1 = p1;
+ n2 = p2;
+ n3 = p3;
+ } else if (!normPerVert) {
+ n1 = n2 = n3 = faceCnt;
+ }
+
+ t1 = p1;
+ t2 = p2;
+ t3 = p3;
+
+ if (colPerVert) {
+ c1 = p1;
+ c2 = p2;
+ c3 = p3;
+ } else if (!colPerVert) {
+ c1 = c2 = c3 = faceCnt;
+ }
+
+ this._mesh._indices[0].push(cnt++, cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+ this._mesh._positions[0].push(positions[p2].x);
+ this._mesh._positions[0].push(positions[p2].y);
+ this._mesh._positions[0].push(positions[p2].z);
+ this._mesh._positions[0].push(positions[p3].x);
+ this._mesh._positions[0].push(positions[p3].y);
+ this._mesh._positions[0].push(positions[p3].z);
+
+ if (hasNormal) {
+ this._mesh._normals[0].push(normals[n1].x);
+ this._mesh._normals[0].push(normals[n1].y);
+ this._mesh._normals[0].push(normals[n1].z);
+ this._mesh._normals[0].push(normals[n2].x);
+ this._mesh._normals[0].push(normals[n2].y);
+ this._mesh._normals[0].push(normals[n2].z);
+ this._mesh._normals[0].push(normals[n3].x);
+ this._mesh._normals[0].push(normals[n3].y);
+ this._mesh._normals[0].push(normals[n3].z);
+ }
+
+ if (hasColor) {
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c1].a);
+ }
+ this._mesh._colors[0].push(colors[c2].r);
+ this._mesh._colors[0].push(colors[c2].g);
+ this._mesh._colors[0].push(colors[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c2].a);
+ }
+ this._mesh._colors[0].push(colors[c3].r);
+ this._mesh._colors[0].push(colors[c3].g);
+ this._mesh._colors[0].push(colors[c3].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c3].a);
+ }
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(texCoords[t1].x);
+ this._mesh._texCoords[0].push(texCoords[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t1].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t2].x);
+ this._mesh._texCoords[0].push(texCoords[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t2].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t3].x);
+ this._mesh._texCoords[0].push(texCoords[t3].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t3].z);
+ }
+ }
+ }
+
+ if (!hasNormal) {
+ this._mesh.calcNormals(Math.PI);
+ }
+
+ if (!hasTexCoord) {
+ this._mesh.calcTexCoords(texMode);
+ }
+
+ this._mesh.splitMesh();
+
+ this.invalidateVolume();
+
+ for (i=0; i<this._mesh._indices.length; i++) {
+ this._mesh._numFaces += this._mesh._indices[i].length / 3;
+ this._mesh._numCoords += this._mesh._positions[i].length / 3;
+ }
+ }
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName != "coord" && fieldName != "normal" &&
+ fieldName != "texCoord" && fieldName != "color")
+ {
+ x3dom.debug.logWarning("IndexedTriangleStripSet: fieldChanged for " +
+ fieldName + " not yet implemented!");
+ return;
+ }
+
+ var pnts = this._cf.coord.node._vf.point;
+
+ if ((this._cf.normal.node === null) || (pnts.length > x3dom.Utils.maxIndexableCoords))
+ {
+ if (fieldName == "coord") {
+ this._mesh._positions[0] = [];
+ this._mesh._indices[0] =[];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] =[];
+
+ var hasNormal = false, hasTexCoord = false, hasColor = false;
+
+ var colPerVert = this._vf.colorPerVertex;
+ var normPerVert = this._vf.normalPerVertex;
+
+ var indexes = this._vf.index;
+ var positions, normals, texCoords, colors;
+
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode);
+ positions = coordNode._vf.point;
+
+ var normalNode = this._cf.normal.node;
+ if (normalNode) {
+ hasNormal = true;
+ normals = normalNode._vf.vector;
+ }
+ else {
+ hasNormal = false;
+ }
+
+ var texMode = "", numTexComponents = 2;
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ if (texCoordNode) {
+ if (texCoordNode._vf.point) {
+ hasTexCoord = true;
+ texCoords = texCoordNode._vf.point;
+
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.TextureCoordinate3D)) {
+ numTexComponents = 3;
+ }
+ }
+ else if (texCoordNode._vf.mode) {
+ texMode = texCoordNode._vf.mode;
+ }
+ }
+ else {
+ hasTexCoord = false;
+ }
+ this._mesh._numTexComponents = numTexComponents;
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ if (colorNode) {
+ hasColor = true;
+ colors = colorNode._vf.color;
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+ else {
+ hasColor = false;
+ }
+ this._mesh._numColComponents = numColComponents;
+
+ this._mesh._indices[0] = [];
+ this._mesh._positions[0] = [];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+ this._mesh._colors[0] = [];
+
+ var faceCnt = 0, cnt = 0;
+ var p1, p2 , p3, n1, n2, n3, t1, t2, t3, c1, c2, c3;
+ var swapOrder = false;
+
+ if ( hasNormal || hasTexCoord || hasColor) {
+
+ for (var i=1; i < indexes.length-2; ++i)
+ {
+ if (indexes[i+1] == -1) {
+ i = i+2;
+ faceCnt++;
+ continue;
+ }
+
+ if (swapOrder) {
+ p1 = indexes[i];
+ p2 = indexes[i-1];
+ p3 = indexes[i+1];
+ }
+ else {
+ p1 = indexes[i-1];
+ p2 = indexes[i];
+ p3 = indexes[i+1];
+ }
+ swapOrder = !swapOrder;
+
+ if (normPerVert) {
+ n1 = p1;
+ n2 = p2;
+ n3 = p3;
+ } else if (!normPerVert) {
+ n1 = n2 = n3 = faceCnt;
+ }
+
+ t1 = p1;
+ t2 = p2;
+ t3 = p3;
+
+ if (colPerVert) {
+ c1 = p1;
+ c2 = p2;
+ c3 = p3;
+ } else if (!colPerVert) {
+ c1 = c2 = c3 = faceCnt;
+ }
+
+ this._mesh._indices[0].push(cnt++, cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+ this._mesh._positions[0].push(positions[p2].x);
+ this._mesh._positions[0].push(positions[p2].y);
+ this._mesh._positions[0].push(positions[p2].z);
+ this._mesh._positions[0].push(positions[p3].x);
+ this._mesh._positions[0].push(positions[p3].y);
+ this._mesh._positions[0].push(positions[p3].z);
+
+ if (hasNormal) {
+ this._mesh._normals[0].push(normals[n1].x);
+ this._mesh._normals[0].push(normals[n1].y);
+ this._mesh._normals[0].push(normals[n1].z);
+ this._mesh._normals[0].push(normals[n2].x);
+ this._mesh._normals[0].push(normals[n2].y);
+ this._mesh._normals[0].push(normals[n2].z);
+ this._mesh._normals[0].push(normals[n3].x);
+ this._mesh._normals[0].push(normals[n3].y);
+ this._mesh._normals[0].push(normals[n3].z);
+ }
+
+ if (hasColor) {
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c1].a);
+ }
+ this._mesh._colors[0].push(colors[c2].r);
+ this._mesh._colors[0].push(colors[c2].g);
+ this._mesh._colors[0].push(colors[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c2].a);
+ }
+ this._mesh._colors[0].push(colors[c3].r);
+ this._mesh._colors[0].push(colors[c3].g);
+ this._mesh._colors[0].push(colors[c3].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c3].a);
+ }
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(texCoords[t1].x);
+ this._mesh._texCoords[0].push(texCoords[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t1].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t2].x);
+ this._mesh._texCoords[0].push(texCoords[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t2].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t3].x);
+ this._mesh._texCoords[0].push(texCoords[t3].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t3].z);
+ }
+ }
+ }
+
+ if (!hasNormal) {
+ this._mesh.calcNormals(Math.PI);
+ }
+
+ if (!hasTexCoord) {
+ this._mesh.calcTexCoords(texMode);
+ }
+
+ this._mesh.splitMesh();
+
+ } else {
+ var swapOrder = false;
+ for (var i = 1; i < indexes.length; ++i)
+ {
+ if (indexes[i+1] == -1) {
+ i = i+2;
+ continue;
+ }
+
+ if (swapOrder) {
+ this._mesh._indices[0].push(indexes[i]);
+ this._mesh._indices[0].push(indexes[i-1]);
+ this._mesh._indices[0].push(indexes[i+1]);
+ }
+ else {
+ this._mesh._indices[0].push(indexes[i-1]);
+ this._mesh._indices[0].push(indexes[i]);
+ this._mesh._indices[0].push(indexes[i+1]);
+ }
+ swapOrder = !swapOrder;
+ }
+
+ this._mesh._positions[0] = positions.toGL();
+
+ if (hasNormal) {
+ this._mesh._normals[0] = normals.toGL();
+ }
+ else {
+ this._mesh.calcNormals(Math.PI);
+ }
+ if (hasTexCoord) {
+ this._mesh._texCoords[0] = texCoords.toGL();
+ this._mesh._numTexComponents = numTexComponents;
+ }
+ else {
+ this._mesh.calcTexCoords(texMode);
+ }
+ if (hasColor) {
+ this._mesh._colors[0] = colors.toGL();
+ this._mesh._numColComponents = numColComponents;
+ }
+
+ }
+
+ this.invalidateVolume();
+ this._mesh._numFaces = 0;
+ this._mesh._numCoords = 0;
+
+ for (i=0; i<this._mesh._indices.length; i++) {
+ this._mesh._numFaces += this._mesh._indices[i].length / 3;
+ this._mesh._numCoords += this._mesh._positions[i].length / 3;
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node.setAllDirty();
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color") {
+ var col = this._cf.color.node._vf.color;
+ var faceCnt = 0;
+ var c1 = c2 = c3 = 0;
+
+ var numColComponents = 3;
+
+ if (x3dom.isa(this._cf.color.node, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+
+ this._mesh._colors[0] = [];
+
+ var indexes = this._vf.index;
+ var swapOrder = false;
+
+ for (i=1; i < indexes.length-2; ++i)
+ {
+ if (indexes[i+1] == -1) {
+ i = i+2;
+ faceCnt++;
+ continue;
+ }
+
+ if (this._vf.colorPerVertex) {
+ if (swapOrder) {
+ c1 = indexes[i];
+ c2 = indexes[i-1];
+ c3 = indexes[i+1];
+ }
+ else {
+ c1 = indexes[i-1];
+ c2 = indexes[i];
+ c3 = indexes[i+1];
+ }
+ swapOrder = !swapOrder;
+ } else if (!this._vf.colorPerVertex) {
+ c1 = c2 = c3 = faceCnt;
+ }
+ this._mesh._colors[0].push(col[c1].r);
+ this._mesh._colors[0].push(col[c1].g);
+ this._mesh._colors[0].push(col[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(col[c1].a);
+ }
+ this._mesh._colors[0].push(col[c2].r);
+ this._mesh._colors[0].push(col[c2].g);
+ this._mesh._colors[0].push(col[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(col[c2].a);
+ }
+ this._mesh._colors[0].push(col[c3].r);
+ this._mesh._colors[0].push(col[c3].g);
+ this._mesh._colors[0].push(col[c3].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(col[c3].a);
+ }
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ else if (fieldName == "normal") {
+ var nor = this._cf.normal.node._vf.vector;
+ var faceCnt = 0;
+ var n1 = n2 = n3 = 0;
+
+ this._mesh._normals[0] = [];
+
+ var indexes = this._vf.index;
+ var swapOrder = false;
+
+ for (i=1; i < indexes.length-2; ++i)
+ {
+ if (indexes[i+1] == -1) {
+ i = i+2;
+ faceCnt++;
+ continue;
+ }
+
+ if (this._vf.normalPerVertex) {
+ if (swapOrder) {
+ n1 = indexes[i];
+ n2 = indexes[i-1];
+ n3 = indexes[i+1];
+ }
+ else {
+ n1 = indexes[i-1];
+ n2 = indexes[i];
+ n3 = indexes[i+1];
+ }
+ swapOrder = !swapOrder;
+ } else if (!this._vf.normalPerVertex) {
+ n1 = n2 = n3 = faceCnt;
+ }
+ this._mesh._normals[0].push(nor[n1].x);
+ this._mesh._normals[0].push(nor[n1].y);
+ this._mesh._normals[0].push(nor[n1].z);
+ this._mesh._normals[0].push(nor[n2].x);
+ this._mesh._normals[0].push(nor[n2].y);
+ this._mesh._normals[0].push(nor[n2].z);
+ this._mesh._normals[0].push(nor[n3].x);
+ this._mesh._normals[0].push(nor[n3].y);
+ this._mesh._normals[0].push(nor[n3].z);
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.normals = true;
+ });
+ }
+ else if (fieldName == "texCoord") {
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ var tex = texCoordNode._vf.point;
+ var t1 = t2 = t3 = 0;
+
+ var numTexComponents = 2;
+
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.TextureCoordinate3D)) {
+ numTexComponents = 3;
+ }
+
+ this._mesh._texCoords[0] = [];
+ var indexes = this._vf.index;
+ var swapOrder = false;
+
+ for (i=1; i < indexes.length-2; ++i)
+ {
+ if (indexes[i+1] == -1) {
+ i = i+2;
+ continue;
+ }
+
+ if (swapOrder) {
+ t1 = indexes[i];
+ t2 = indexes[i-1];
+ t3 = indexes[i+1];
+ }
+ else {
+ t1 = indexes[i-1];
+ t2 = indexes[i];
+ t3 = indexes[i+1];
+ }
+ swapOrder = !swapOrder;
+
+ this._mesh._texCoords[0].push(tex[t1].x);
+ this._mesh._texCoords[0].push(tex[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(tex[t1].z);
+ }
+ this._mesh._texCoords[0].push(tex[t2].x);
+ this._mesh._texCoords[0].push(tex[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].tex(col[t2].z);
+ }
+ this._mesh._texCoords[0].push(tex[t3].x);
+ this._mesh._texCoords[0].push(tex[t3].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(tex[t3].z);
+ }
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.texcoords = true;
+ });
+ }
+ }
+ else
+ {
+ if (fieldName == "coord")
+ {
+ this._mesh._positions[0] = pnts.toGL();
+
+ // tells the mesh that its bbox requires update
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color")
+ {
+ pnts = this._cf.color.node._vf.color;
+
+ if (this._vf.colorPerVertex) {
+
+ this._mesh._colors[0] = pnts.toGL();
+
+ } else if (!this._vf.colorPerVertex) {
+
+ var faceCnt = 0;
+ var numColComponents = 3;
+
+ if (x3dom.isa(this._cf.color.node, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+
+ this._mesh._colors[0] = [];
+
+ var indexes = this._vf.index;
+ for (i=0; i < indexes.length; ++i)
+ {
+ if (indexes[i] == -1) {
+ faceCnt++;
+ continue;
+ }
+
+ this._mesh._colors[0].push(pnts[faceCnt].r);
+ this._mesh._colors[0].push(pnts[faceCnt].g);
+ this._mesh._colors[0].push(pnts[faceCnt].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(pnts[faceCnt].a);
+ }
+ }
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ else if (fieldName == "normal")
+ {
+ pnts = this._cf.normal.node._vf.vector;
+
+ if (this._vf.normalPerVertex) {
+
+ this._mesh._normals[0] = pnts.toGL();
+
+ } else if (!this._vf.normalPerVertex) {
+
+ var indexes = this._vf.index;
+ this._mesh._normals[0] = [];
+
+ var faceCnt = 0;
+ for (i=0; i < indexes.length; ++i)
+ {
+ if (indexes[i] == -1) {
+ faceCnt++;
+ continue;
+ }
+
+ this._mesh._normals[0].push(pnts[faceCnt].x);
+ this._mesh._normals[0].push(pnts[faceCnt].y);
+ this._mesh._normals[0].push(pnts[faceCnt].z);
+ }
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.normals = true;
+ });
+ }
+ else if (fieldName == "texCoord")
+ {
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ pnts = texCoordNode._vf.point;
+
+ this._mesh._texCoords[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.texcoords = true;
+ });
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DGeometricPropertyNode ### */
+x3dom.registerNodeType(
+ "X3DGeometricPropertyNode",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for X3DGeometricPropertyNode
+ * @constructs x3dom.nodeTypes.X3DGeometricPropertyNode
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all geometric property node types defined in X3D.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DGeometricPropertyNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DCoordinateNode ### */
+x3dom.registerNodeType(
+ "X3DCoordinateNode",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometricPropertyNode,
+
+ /**
+ * Constructor for X3DCoordinateNode
+ * @constructs x3dom.nodeTypes.X3DCoordinateNode
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGeometricPropertyNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all coordinate node types in X3D.
+ * All coordinates are specified in nodes derived from this abstract node type.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DCoordinateNode.superClass.call(this, ctx);
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName === "coord" || fieldName === "point") {
+ Array.forEach(this._parentNodes, function (node) {
+ node.fieldChanged("coord");
+ });
+ }
+ },
+
+ parentAdded: function (parent) {
+ if (parent._mesh && parent._cf.coord.node !== this) {
+ parent.fieldChanged("coord");
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Coordinate ### */
+x3dom.registerNodeType(
+ "Coordinate",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DCoordinateNode,
+
+ /**
+ * Constructor for Coordinate
+ * @constructs x3dom.nodeTypes.Coordinate
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DCoordinateNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Coordinate builds geometry using a set of 3D coordinates.
+ * Coordinate is used by IndexedFaceSet, IndexedLineSet, LineSet and PointSet.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Coordinate.superClass.call(this, ctx);
+
+
+ /**
+ * Contains the 3D coordinates
+ * @var {x3dom.fields.MFVec3f} point
+ * @memberof x3dom.nodeTypes.Coordinate
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'point', []);
+
+ },
+ {
+ getPoints: function() {
+ return this._vf.point;
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Normal ### */
+x3dom.registerNodeType(
+ "Normal",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometricPropertyNode,
+
+ /**
+ * Constructor for Normal
+ * @constructs x3dom.nodeTypes.Normal
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGeometricPropertyNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Normal is a set of 3D surface-normal vectors Normal values are optional perpendicular directions, used per-polygon or per-vertex for lighting and shading.
+ * Hint: used by IndexedFaceSet and ElevationGrid.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Normal.superClass.call(this, ctx);
+
+
+ /**
+ * set of unit-length normal vectors, corresponding to indexed polygons or vertices.
+ * @var {x3dom.fields.MFVec3f} vector
+ * @range [-1, 1]
+ * @memberof x3dom.nodeTypes.Normal
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'vector', []);
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName === "normal" || fieldName === "vector") {
+ Array.forEach(this._parentNodes, function (node) {
+ node.fieldChanged("normal");
+ });
+ }
+ },
+
+ parentAdded: function (parent) {
+ if (parent._mesh && //parent._cf.coord.node &&
+ parent._cf.normal.node !== this) {
+ parent.fieldChanged("normal");
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DColorNode ### */
+x3dom.registerNodeType(
+ "X3DColorNode",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DGeometricPropertyNode,
+
+ /**
+ * Constructor for X3DColorNode
+ * @constructs x3dom.nodeTypes.X3DColorNode
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGeometricPropertyNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for color specifications in X3D.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DColorNode.superClass.call(this, ctx);
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName === "color") {
+ Array.forEach(this._parentNodes, function (node) {
+ node.fieldChanged("color");
+ });
+ }
+ },
+
+ parentAdded: function (parent) {
+ if (parent._mesh && //parent._cf.coord.node &&
+ parent._cf.color.node !== this) {
+ parent.fieldChanged("color");
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Color ### */
+x3dom.registerNodeType(
+ "Color",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DColorNode,
+
+ /**
+ * Constructor for Color
+ * @constructs x3dom.nodeTypes.Color
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DColorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This node defines a set of RGB colors to be used in the fields of another node.
+ * Color nodes are only used to specify multiple colours for a single geometric shape, such as colours for the faces or vertices of an IndexedFaceSet.
+ * A Material node is used to specify the overall material parameters of lit geometry.
+ * If both a Material node and a Color node are specified for a geometric shape, the colours shall replace the diffuse component of the material.
+ * RGB or RGBA textures take precedence over colours; specifying both an RGB or RGBA texture and a Color node for geometric shape will result in the Color node being ignored.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Color.superClass.call(this, ctx);
+
+
+ /**
+ * The RGB colors.
+ * @var {x3dom.fields.MFColor} color
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.Color
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFColor(ctx, 'color', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ColorRGBA ### */
+x3dom.registerNodeType(
+ "ColorRGBA",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DColorNode,
+
+ /**
+ * Constructor for ColorRGBA
+ * @constructs x3dom.nodeTypes.ColorRGBA
+ * @x3d 3.3
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DColorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This node defines a set of RGBA colours to be used in the fields of another node.
+ * RGBA color nodes are only used to specify multiple colours with alpha for a single geometric shape, such as colours for the faces or vertices of an IndexedFaceSet.
+ * A Material node is used to specify the overall material parameters of lit geometry.
+ * If both a Material node and a ColorRGBA node are specified for a geometric shape, the colours shall replace the diffuse and transparency components of the material.
+ * RGB or RGBA textures take precedence over colours; specifying both an RGB or RGBA texture and a ColorRGBA node for geometric shape will result in the ColorRGBA node being ignored.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ColorRGBA.superClass.call(this, ctx);
+
+
+ /**
+ * The set of RGBA colors
+ * @var {x3dom.fields.MFColorRGBA} color
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.ColorRGBA
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFColorRGBA(ctx, 'color', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* This is only a first stub */
+
+/* ### ParticleSet ### */
+x3dom.registerNodeType(
+ "ParticleSet",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.PointSet,
+
+ /**
+ * Constructor for ParticleSet
+ * @constructs x3dom.nodeTypes.ParticleSet
+ * @x3d x.x
+ * @component Rendering
+ * @status experimental
+ * @extends x3dom.nodeTypes.PointSet
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ParticleSet is a geometry node used in combination with a ParticleSystem node.
+ * Attention: So far this is only a stub.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ParticleSet.superClass.call(this, ctx);
+
+ /**
+ * Drawing mode: "ViewDirQuads" - Draws quads directed to the viewpoint (default). "Points" - Draw points.
+ * "Lines" - Draw lines. These modes must not match the finally supported modes.
+ * @var {x3dom.fields.SFString} mode
+ * @memberof x3dom.nodeTypes.ParticleSet
+ * @initvalue ViewDirQuads
+ * @range [ViewDirQuads, Points, Lines, Arrows, ViewerArrows, ViewerQuads, Rectangles]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'mode', 'ViewDirQuads'); // only default value supported
+
+ /**
+ * Defines the drawing order for the particles. Possible values: "Any" - The order is undefined.
+ * "BackToFront" - Draw from back to front. "FrontToBack" - Draw from front to back.
+ * @var {x3dom.fields.SFString} drawOrder
+ * @memberof x3dom.nodeTypes.ParticleSet
+ * @initvalue Any
+ * @range [Any, BackToFront, FrontToBack]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'drawOrder', 'Any');
+
+ // THINKABOUTME; does this very special field makes sense for being impl. in WebGL?
+ //this.addField_SFNode('secCoord', x3dom.nodeTypes.X3DCoordinateNode); // NOT YET SUPPORTED!
+
+ /**
+ * Stores a Normal node containing the normals of the particles.
+ * @var {x3dom.fields.SFNode} normal
+ * @memberof x3dom.nodeTypes.ParticleSet
+ * @initvalue null
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('normal', x3dom.nodeTypes.Normal); // NOT YET SUPPORTED
+
+ /**
+ * An MFVec3f field containing the sizes of the particles.
+ * @var {x3dom.fields.MFVec3f} size
+ * @memberof x3dom.nodeTypes.ParticleSet
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'size', []);
+
+ /**
+ * An MFInt32 field containing indices which specify the order of the vertices in the "coord" field.
+ * @var {x3dom.fields.MFInt32} index
+ * @memberof x3dom.nodeTypes.ParticleSet
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'index', []);
+
+ /**
+ * An MFFloat field containing z-values for the texture of a particle (used with 3D textures).
+ * @var {x3dom.fields.MFFloat} textureZ
+ * @memberof x3dom.nodeTypes.ParticleSet
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'textureZ', []); // NOT YET SUPPORTED! (3D textures not supported in WebGL)
+
+ this._mesh._primType = 'POINTS';
+ },
+ {
+ drawOrder: function() {
+ return this._vf.drawOrder.toLowerCase();
+ },
+
+ nodeChanged: function()
+ {
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode, "ParticleSet without coord node!");
+ var positions = coordNode.getPoints();
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ var colors = new x3dom.fields.MFColor();
+ if (colorNode) {
+ colors = colorNode._vf.color;
+ x3dom.debug.assert(positions.length == colors.length, "Size of color and coord array differs!");
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+
+ var normalNode = this._cf.normal.node;
+ var normals = new x3dom.fields.MFVec3f();
+ if (normalNode) {
+ normals = normalNode._vf.vector;
+ }
+
+ var indices = [];
+ if (this.drawOrder() != "any") {
+ indices = this._vf.index.toGL();
+
+ // generate indices since also used for sorting
+ if (indices.length == 0) {
+ var i, n = positions.length;
+ indices = new Array(n);
+ for (i = 0; i < n; i++) {
+ indices[i] = i;
+ }
+ }
+ }
+
+ this._mesh._numColComponents = numColComponents;
+ this._mesh._lit = false;
+
+ this._mesh._indices[0] = indices;
+ this._mesh._positions[0] = positions.toGL();
+ this._mesh._colors[0] = colors.toGL();
+ this._mesh._normals[0] = normals.toGL();
+ this._mesh._texCoords[0] = [];
+
+ this.invalidateVolume();
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ var pnts = null;
+
+ if (fieldName == "index")
+ {
+ this._mesh._indices[0] = this._vf.index.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.indexes = true;
+ });
+ }
+ else if (fieldName == "size")
+ {
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.specialAttribs = true;
+ });
+ }
+ else if (fieldName == "coord")
+ {
+ pnts = this._cf.coord.node.getPoints();
+
+ this._mesh._positions[0] = pnts.toGL();
+
+ var indices = [];
+ if (this.drawOrder() != "any") {
+ indices = this._vf.index.toGL();
+
+ // generate indices since also used for sorting
+ if (indices.length == 0) {
+ var i, n = pnts.length;
+ indices = new Array(n);
+ for (i = 0; i < n; i++) {
+ indices[i] = i;
+ }
+ }
+ }
+ this._mesh._indices[0] = indices;
+
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node._dirty.indexes = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color")
+ {
+ pnts = this._cf.color.node._vf.color;
+
+ this._mesh._colors[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ClipPlane ### */
+x3dom.registerNodeType(
+ "ClipPlane",
+ "Rendering",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for ClipPlane
+ * @constructs x3dom.nodeTypes.ClipPlane
+ * @x3d 3.2
+ * @component Rendering
+ * @status full
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc A clip plane is defined as a plane that generates two half-spaces. The effected geometry in the
+ * half-space that is defined as being outside the plane is removed from the rendered image as a result of a
+ * clipping operation.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ClipPlane.superClass.call(this, ctx);
+
+
+ /**
+ * Defines activation state of the clip plane.
+ * @var {x3dom.fields.SFBool} enabled
+ * @memberof x3dom.nodeTypes.ClipPlane
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'enabled', true);
+
+ /**
+ * The ClipPlane node specifies a single plane equation that will be used to clip the geometry.
+ * The plane field specifies a four-component plane equation that describes the inside and outside half
+ * space. The first three components are a normalized vector describing the direction of the plane's
+ * normal direction.
+ * @var {x3dom.fields.SFVec4f} plane
+ * @memberof x3dom.nodeTypes.ClipPlane
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec4f(ctx, 'plane', 0, 1, 0, 0);
+
+ /**
+ * Defines the strength of the capping.
+ * @var {x3dom.fields.SFFloat} cappingStrength
+ * @memberof x3dom.nodeTypes.ClipPlane
+ * @initvalue 0.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'cappingStrength', 0.0);
+
+ /**
+ * Defines the color of the capping.
+ * @var {x3dom.fields.SFColor} cappingColor
+ * @memberof x3dom.nodeTypes.ClipPlane
+ * @initvalue 1.0,1.0,1.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'cappingColor', 1.0, 1.0, 1.0);
+
+
+ /**
+ * Enables/disables this effector (e.g. light)
+ * @var {x3dom.fields.SFBool} on
+ * @memberof x3dom.nodeTypes.ClipPlane
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'on', true);
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName == "enabled" || fieldName == "on") {
+ //TODO
+ }
+ },
+
+ nodeChanged: function () {
+ x3dom.nodeTypes.ClipPlane.count++;
+ },
+
+ onRemove: function() {
+ x3dom.nodeTypes.ClipPlane.count--;
+ },
+
+ parentAdded: function(parent) {
+ },
+
+ parentRemoved: function(parent) {
+ //TODO
+ }
+ }
+ )
+);
+
+/** Static class ID counter (needed for caching) */
+x3dom.nodeTypes.ClipPlane.count = 0;
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DAppearanceNode ### */
+x3dom.registerNodeType(
+ "X3DAppearanceNode",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for X3DAppearanceNode
+ * @constructs x3dom.nodeTypes.X3DAppearanceNode
+ * @x3d 3.3
+ * @component Shape
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all Appearance nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DAppearanceNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Appearance ### */
+x3dom.registerNodeType(
+ "Appearance",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DAppearanceNode,
+
+ /**
+ * Constructor for Appearance
+ * @constructs x3dom.nodeTypes.Appearance
+ * @x3d 3.3
+ * @component Shape
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DAppearanceNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Appearance node specifies the visual properties of geometry.
+ * The value for each of the fields in this node may be NULL.
+ * However, if the field is non-NULL, it shall contain one node of the appropriate type.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Appearance.superClass.call(this, ctx);
+
+
+ /**
+ * The material field, if specified, shall contain a Material node.
+ * If the material field is NULL or unspecified, lighting is off (all lights are ignored during rendering of the object that references this Appearance) and the unlit object colour is (1, 1, 1).
+ * @var {x3dom.fields.SFNode} material
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.X3DMaterialNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('material', x3dom.nodeTypes.X3DMaterialNode);
+
+ /**
+ * The texture field, if specified, shall contain a texture nodes.
+ * If the texture node is NULL or the texture field is unspecified, the object that references this Appearance is not textured.
+ * @var {x3dom.fields.SFNode} texture
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('texture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * The textureTransform field, if specified, shall contain a TextureTransform node. If the textureTransform is NULL or unspecified, the textureTransform field has no effect.
+ * @var {x3dom.fields.SFNode} textureTransform
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.X3DTextureTransformNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('textureTransform', x3dom.nodeTypes.X3DTextureTransformNode);
+
+ /**
+ * The lineProperties field, if specified, shall contain a LineProperties node. If lineProperties is NULL or unspecified, the lineProperties field has no effect.
+ * @var {x3dom.fields.SFNode} lineProperties
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.LineProperties
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('lineProperties', x3dom.nodeTypes.LineProperties);
+
+ /**
+ * Holds a ColorMaskMode node.
+ * @var {x3dom.fields.SFNode} colorMaskMode
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.ColorMaskMode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('colorMaskMode', x3dom.nodeTypes.ColorMaskMode);
+
+ /**
+ * Holds the BlendMode node, that is needed for correct transparency.
+ * @var {x3dom.fields.SFNode} blendMode
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.BlendMode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('blendMode', x3dom.nodeTypes.BlendMode);
+
+ /**
+ * Holds the depthMode node.
+ * @var {x3dom.fields.SFNode} depthMode
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.DepthMode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('depthMode', x3dom.nodeTypes.DepthMode);
+
+ /**
+ * Contains ProgramShader (Cg) or ComposedShader (GLSL).
+ * @var {x3dom.fields.MFNode} shaders
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue x3dom.nodeTypes.X3DShaderNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFNode('shaders', x3dom.nodeTypes.X3DShaderNode);
+
+ /**
+ * Defines the shape type for sorting.
+ * @var {x3dom.fields.SFString} sortType
+ * @range [auto, transparent, opaque]
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue 'auto'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'sortType', 'auto');
+
+ /**
+ * Change render order manually.
+ * @var {x3dom.fields.SFInt32} sortKey
+ * @memberof x3dom.nodeTypes.Appearance
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'sortKey', 0);
+
+ // shortcut to shader program
+ this._shader = null;
+
+ },
+ {
+ nodeChanged: function() {
+ //TODO delete this if all works fine
+ if (!this._cf.material.node) {
+ //Unlit
+ //this.addChild(x3dom.nodeTypes.Material.defaultNode());
+ }
+
+ if (this._cf.shaders.nodes.length) {
+ this._shader = this._cf.shaders.nodes[0];
+ }
+ else if(this._shader)
+ this._shader=null;
+
+ Array.forEach(this._parentNodes, function (shape) {
+ shape.setAppDirty();
+ });
+
+ this.checkSortType();
+ },
+
+ checkSortType: function() {
+ if (this._vf.sortType == 'auto') {
+ if (this._cf.material.node && (this._cf.material.node._vf.transparency > 0 ||
+ this._cf.material.node._vf.backTransparency && this._cf.material.node._vf.backTransparency > 0)) {
+ this._vf.sortType = 'transparent';
+ }
+ else if (this._cf.texture.node && this._cf.texture.node._vf.url.length) {
+ // uhh, this is a rather coarse guess...
+ if (this._cf.texture.node._vf.url[0].toLowerCase().indexOf('.'+'png') >= 0) {
+ this._vf.sortType = 'transparent';
+ }
+ else {
+ this._vf.sortType = 'opaque';
+ }
+ }
+ else {
+ this._vf.sortType = 'opaque';
+ }
+ }
+ },
+
+ texTransformMatrix: function() {
+ if (this._cf.textureTransform.node === null) {
+ return x3dom.fields.SFMatrix4f.identity();
+ }
+ else {
+ return this._cf.textureTransform.node.texTransformMatrix();
+ }
+ },
+
+ parentAdded: function(parent) {
+ if (this != x3dom.nodeTypes.Appearance._defaultNode) {
+ /*if (parent._cleanupGLObjects) {
+ parent._cleanupGLObjects(true);
+ }*/
+ parent.setAppDirty();
+ }
+ }
+ }
+ )
+);
+
+x3dom.nodeTypes.Appearance.defaultNode = function() {
+ if (!x3dom.nodeTypes.Appearance._defaultNode) {
+ x3dom.nodeTypes.Appearance._defaultNode = new x3dom.nodeTypes.Appearance();
+ x3dom.nodeTypes.Appearance._defaultNode.nodeChanged();
+ }
+ return x3dom.nodeTypes.Appearance._defaultNode;
+};
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DAppearanceChildNode ### */
+x3dom.registerNodeType(
+ "X3DAppearanceChildNode",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for X3DAppearanceChildNode
+ * @constructs x3dom.nodeTypes.X3DAppearanceChildNode
+ * @x3d 3.3
+ * @component Shape
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for the child nodes of the X3DAppearanceNode type.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DAppearanceChildNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### BlendMode ### */
+x3dom.registerNodeType(
+ "BlendMode",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for BlendMode
+ * @constructs x3dom.nodeTypes.BlendMode
+ * @x3d x.x
+ * @component Shape
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The BlendMode controls blending and alpha test.
+ * Pixels can be drawn using a function that blends the incoming (source) RGBA values with the RGBA values that are already in the frame buffer (the destination values).
+ */
+ function (ctx) {
+ x3dom.nodeTypes.BlendMode.superClass.call(this, ctx);
+
+
+ /**
+ * The incoming pixel is scaled according to the method defined by the source factor.
+ * @var {x3dom.fields.SFString} srcFactor
+ * @range [none, zero, one, dst_color, src_color, one_minus_dst_color, one_minus_src_color, src_alpha, one_minus_src_alpha, dst_alpha, one_minus_dst_alpha, src_alpha_saturate, constant_color, one_minus_constant_color, constant_alpha, one_minus_constant_alpha]
+ * @memberof x3dom.nodeTypes.BlendMode
+ * @initvalue "src_alpha"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'srcFactor', "src_alpha");
+
+ /**
+ * The frame buffer pixel is scaled according to the method defined by the destination factor.
+ * @var {x3dom.fields.SFString} destFactor
+ * @range [none, zero, one, dst_color, src_color, one_minus_dst_color, one_minus_src_color, src_alpha, one_minus_src_alpha, dst_alpha, one_minus_dst_alpha, src_alpha_saturate, constant_color, one_minus_constant_color, constant_alpha, one_minus_constant_alpha]
+ * @memberof x3dom.nodeTypes.BlendMode
+ * @initvalue "one_minus_src_alpha"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'destFactor', "one_minus_src_alpha");
+
+ /**
+ * This is the constant color used by blend modes constant.
+ * @var {x3dom.fields.SFColor} color
+ * @memberof x3dom.nodeTypes.BlendMode
+ * @initvalue 1,1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'color', 1, 1, 1);
+
+ /**
+ * This is the constant alpha used by blend modes constant.
+ * @var {x3dom.fields.SFFloat} colorTransparency
+ * @memberof x3dom.nodeTypes.BlendMode
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'colorTransparency', 0);
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} alphaFunc
+ * @memberof x3dom.nodeTypes.BlendMode
+ * @initvalue "none"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'alphaFunc', "none");
+
+ /**
+ * The alphaFunc defines how fragments which do not fulfill a certain condition are handled.
+ * @var {x3dom.fields.SFFloat} alphaFuncValue
+ * @range [none, never, less, equal, lequal, greater, notequal, gequal, always]
+ * @memberof x3dom.nodeTypes.BlendMode
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'alphaFuncValue', 0);
+
+ /**
+ * An additional equation used to combine source, destination and the constant value.
+ * @var {x3dom.fields.SFString} equation
+ * @range [none, func_add, func_subtract, func_reverse_subtract, min, max, logic_op]
+ * @memberof x3dom.nodeTypes.BlendMode
+ * @initvalue "none"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'equation', "none");
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### DepthMode ### */
+x3dom.registerNodeType(
+ "DepthMode",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for DepthMode
+ * @constructs x3dom.nodeTypes.DepthMode
+ * @x3d x.x
+ * @component Shape
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The depth mode contains the parameters that are specific for depth control, like the value used for depth buffer comparisons.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.DepthMode.superClass.call(this, ctx);
+
+
+ /**
+ * Whether the depth test should be enabled or not.
+ * @var {x3dom.fields.SFBool} enableDepthTest
+ * @memberof x3dom.nodeTypes.DepthMode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'enableDepthTest', true);
+
+ /**
+ * The depth function to use. If "none", it's not changed, the default is "lequal".
+ * @var {x3dom.fields.SFString} depthFunc
+ * @range [NONE, NEVER, LESS, EQUAL, LEQUAL, GREATER, NOTEQUAL, GEQUAL, ALWAYS]
+ * @memberof x3dom.nodeTypes.DepthMode
+ * @initvalue "none"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'depthFunc', "none");
+
+ /**
+ * Whether the depth buffer is enabled for writing or not.
+ * @var {x3dom.fields.SFBool} readOnly
+ * @memberof x3dom.nodeTypes.DepthMode
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'readOnly', false);
+
+ /**
+ * The near value for the depth range. Ignored if less than 0, defaults to -1.
+ * @var {x3dom.fields.SFFloat} zNearRange
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.DepthMode
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zNearRange', -1);
+
+ /**
+ * The far value for the depth range. Ignored if less than 0, defaults to -1.
+ * @var {x3dom.fields.SFFloat} zFarRange
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.DepthMode
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zFarRange', -1);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ColorMaskMode ### */
+x3dom.registerNodeType(
+ "ColorMaskMode",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for ColorMaskMode
+ * @constructs x3dom.nodeTypes.ColorMaskMode
+ * @x3d x.x
+ * @component Shape
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ColorMaskMode node affects drawing in RGBA mode. The 4 masks control whether the corresponding component is written.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ColorMaskMode.superClass.call(this, ctx);
+
+
+ /**
+ * Masks r color channel.
+ * @var {x3dom.fields.SFBool} maskR
+ * @memberof x3dom.nodeTypes.ColorMaskMode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'maskR', true);
+
+ /**
+ * Masks g color channel.
+ * @var {x3dom.fields.SFBool} maskG
+ * @memberof x3dom.nodeTypes.ColorMaskMode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'maskG', true);
+
+ /**
+ * Masks b color channel.
+ * @var {x3dom.fields.SFBool} maskB
+ * @memberof x3dom.nodeTypes.ColorMaskMode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'maskB', true);
+
+ /**
+ * Masks a color channel.
+ * @var {x3dom.fields.SFBool} maskA
+ * @memberof x3dom.nodeTypes.ColorMaskMode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'maskA', true);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### LineProperties ### */
+x3dom.registerNodeType(
+ "LineProperties",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for LineProperties
+ * @constructs x3dom.nodeTypes.LineProperties
+ * @x3d 3.3
+ * @component Shape
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The LineProperties node specifies additional properties to be applied to all line geometry. The colour of the line is specified by the associated Material node.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.LineProperties.superClass.call(this, ctx);
+
+ // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/components/shape.html#LineProperties
+ // THINKABOUTME: to my mind, the only useful, but missing, field is linewidth (scaleFactor is overhead)
+
+ /**
+ * The linetype and linewidth shall only be applied when the applied field has value TRUE.
+ * When the value of the applied field is FALSE, a solid line of nominal width shall be produced.
+ * @var {x3dom.fields.SFBool} applied
+ * @memberof x3dom.nodeTypes.LineProperties
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'applied', true);
+
+ /**
+ * The linetype field selects a line pattern.
+ * @var {x3dom.fields.SFInt32} linetype
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.LineProperties
+ * @initvalue 1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'linetype', 1);
+
+ /**
+ * The linewidthScaleFactor is a multiplicative value that scales a the linewidth. This resulting value shall then be mapped to the nearest available line width. A value less than or equal to zero refers to the minimum available line width.
+ * @var {x3dom.fields.SFFloat} linewidthScaleFactor
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.LineProperties
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'linewidthScaleFactor', 0);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DMaterialNode ### */
+x3dom.registerNodeType(
+ "X3DMaterialNode",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for X3DMaterialNode
+ * @constructs x3dom.nodeTypes.X3DMaterialNode
+ * @x3d 3.3
+ * @component Shape
+ * @status full
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all Material nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DMaterialNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Material ### */
+x3dom.registerNodeType(
+ "Material",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DMaterialNode,
+
+ /**
+ * Constructor for Material
+ * @constructs x3dom.nodeTypes.Material
+ * @x3d 3.3
+ * @component Shape
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMaterialNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Material node specifies surface material properties for associated geometry nodes and is used by the X3D lighting equations during rendering.
+ * All of the fields in the Material node range from 0.0 to 1.0.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Material.superClass.call(this, ctx);
+
+ /**
+ * The ambientIntensity field specifies how much ambient light from light sources this surface shall reflect.
+ * Ambient light is omnidirectional and depends only on the number of light sources, not their positions with respect to the surface.
+ * Ambient colour is calculated as ambientIntensity × diffuseColor.
+ * @var {x3dom.fields.SFFloat} ambientIntensity
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.X3DMaterialNode
+ * @initvalue 0.2
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'ambientIntensity', 0.2);
+
+ /**
+ * The diffuseColor field reflects all X3D light sources depending on the angle of the surface with respect to the light source.
+ * The more directly the surface faces the light, the more diffuse light reflects.
+ * The emissiveColor field models "glowing" objects.
+ * This can be useful for displaying pre-lit models (where the light energy of the room is computed explicitly), or for displaying scientific data.
+ * @var {x3dom.fields.SFColor} diffuseColor
+ * @memberof x3dom.nodeTypes.X3DMaterialNode
+ * @initvalue 0.8,0.8,0.8
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'diffuseColor', 0.8, 0.8, 0.8);
+
+ /**
+ * The emissiveColor field models "glowing" objects.
+ * This can be useful for displaying pre-lit models (where the light energy of the room is computed explicitly), or for displaying scientific data.
+ * @var {x3dom.fields.SFColor} emissiveColor
+ * @memberof x3dom.nodeTypes.X3DMaterialNode
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'emissiveColor', 0, 0, 0);
+
+ /**
+ * The specularColor and shininess fields determine the specular highlights (e.g., the shiny spots on an apple).
+ * When the angle from the light to the surface is close to the angle from the surface to the viewer, the specularColor is added to the diffuse and ambient colour calculations.
+ * Lower shininess values produce soft glows, while higher values result in sharper, smaller highlights.
+ * @var {x3dom.fields.SFFloat} shininess
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.X3DMaterialNode
+ * @initvalue 0.2
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shininess', 0.2);
+
+ /**
+ * The specularColor and shininess fields determine the specular highlights (e.g., the shiny spots on an apple).
+ * When the angle from the light to the surface is close to the angle from the surface to the viewer, the specularColor is added to the diffuse and ambient colour calculations.
+ * Lower shininess values produce soft glows, while higher values result in sharper, smaller highlights.
+ * @var {x3dom.fields.SFColor} specularColor
+ * @memberof x3dom.nodeTypes.X3DMaterialNode
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'specularColor', 0, 0, 0);
+
+ /**
+ * The transparency field specifies how "clear" an object is, with 1.0 being completely transparent, and 0.0 completely opaque.
+ * @var {x3dom.fields.SFFloat} transparency
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.X3DMaterialNode
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'transparency', 0);
+
+ },
+ {
+ fieldChanged: function(fieldName) {
+ if (fieldName == "ambientIntensity" || fieldName == "diffuseColor" ||
+ fieldName == "emissiveColor" || fieldName == "shininess" ||
+ fieldName == "specularColor" || fieldName == "transparency")
+ {
+ Array.forEach(this._parentNodes, function (app) {
+ Array.forEach(app._parentNodes, function (shape) {
+ shape._dirty.material = true;
+ });
+ app.checkSortType();
+ });
+ }
+ }
+ }
+ )
+);
+
+x3dom.nodeTypes.Material.defaultNode = function() {
+ if (!x3dom.nodeTypes.Material._defaultNode) {
+ x3dom.nodeTypes.Material._defaultNode = new x3dom.nodeTypes.Material();
+ x3dom.nodeTypes.Material._defaultNode.nodeChanged();
+ }
+ return x3dom.nodeTypes.Material._defaultNode;
+};
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TwoSidedMaterial ### */
+x3dom.registerNodeType(
+ "TwoSidedMaterial",
+ "Shape",
+ defineClass(x3dom.nodeTypes.Material,
+
+ /**
+ * Constructor for TwoSidedMaterial
+ * @constructs x3dom.nodeTypes.TwoSidedMaterial
+ * @x3d 3.3
+ * @component Shape
+ * @status full
+ * @extends x3dom.nodeTypes.X3DMaterialNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This node defines material properties that can effect both the front and back side of a polygon individually.
+ * These materials are used for both the front and back side of the geometry whenever the X3D lighting model is active.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TwoSidedMaterial.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the ambient intensity for the back side.
+ * @var {x3dom.fields.SFFloat} backAmbientIntensity
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.TwoSidedMaterial
+ * @initvalue 0.2
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'backAmbientIntensity', 0.2);
+
+ /**
+ * Defines the diffuse color for the back side.
+ * @var {x3dom.fields.SFColor} backDiffuseColor
+ * @memberof x3dom.nodeTypes.TwoSidedMaterial
+ * @initvalue 0.8,0.8,0.8
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'backDiffuseColor', 0.8, 0.8, 0.8);
+
+ /**
+ * Defines the emissive color for the back side.
+ * @var {x3dom.fields.SFColor} backEmissiveColor
+ * @memberof x3dom.nodeTypes.TwoSidedMaterial
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'backEmissiveColor', 0, 0, 0);
+
+ /**
+ * Defines the shininess for the back side.
+ * @var {x3dom.fields.SFFloat} backShininess
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.TwoSidedMaterial
+ * @initvalue 0.2
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'backShininess', 0.2);
+
+ /**
+ * Defines the specular color for the back side.
+ * @var {x3dom.fields.SFColor} backSpecularColor
+ * @memberof x3dom.nodeTypes.TwoSidedMaterial
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'backSpecularColor', 0, 0, 0);
+
+ /**
+ * Defines the transparency for the back side.
+ * @var {x3dom.fields.SFFloat} backTransparency
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.TwoSidedMaterial
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'backTransparency', 0);
+
+ /**
+ * If the separateBackColor field is set to TRUE, the rendering shall render the front and back faces of the geometry with different values.
+ * If the value is FALSE, the front colours are used for both the front and back side of the polygon, as per the existing X3D lighting rules.
+ * @var {x3dom.fields.SFBool} separateBackColor
+ * @memberof x3dom.nodeTypes.TwoSidedMaterial
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'separateBackColor', false);
+
+ },
+ {
+ fieldChanged: function(fieldName) {
+ if (fieldName == "ambientIntensity" || fieldName == "diffuseColor" ||
+ fieldName == "emissiveColor" || fieldName == "shininess" ||
+ fieldName == "specularColor" || fieldName == "transparency" ||
+ fieldName == "backAmbientIntensity" || fieldName == "backDiffuseColor" ||
+ fieldName == "backEmissiveColor" || fieldName == "backShininess" ||
+ fieldName == "backSpecularColor" || fieldName == "backTransparency" ||
+ fieldName == "separateBackColor")
+ {
+ Array.forEach(this._parentNodes, function (app) {
+ Array.forEach(app._parentNodes, function (shape) {
+ shape._dirty.material = true;
+ });
+ app.checkSortType();
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DShapeNode ### */
+x3dom.registerNodeType(
+ "X3DShapeNode",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DBoundedObject,
+
+ /**
+ * Constructor for X3DShapeNode
+ * @constructs x3dom.nodeTypes.X3DShapeNode
+ * @x3d 3.3
+ * @component Shape
+ * @status full
+ * @extends x3dom.nodeTypes.X3DBoundedObject
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the base node type for all Shape nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DShapeNode.superClass.call(this, ctx);
+
+
+ /**
+ * Defines whether the shape is pickable.
+ * @var {x3dom.fields.SFBool} isPickable
+ * @memberof x3dom.nodeTypes.X3DShapeNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'isPickable', true);
+
+ /**
+ * Holds the id offset for MultiPart picking.
+ * @var {x3dom.fields.SFInt32} isPickable
+ * @memberof x3dom.nodeTypes.X3DShapeNode
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'idOffset', 0);
+
+ /**
+ * Holds the appearance node.
+ * @var {x3dom.fields.SFNode} appearance
+ * @memberof x3dom.nodeTypes.X3DShapeNode
+ * @initvalue x3dom.nodeTypes.X3DAppearanceNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('appearance', x3dom.nodeTypes.X3DAppearanceNode);
+
+ /**
+ * Holds the geometry node.
+ * @var {x3dom.fields.SFNode} geometry
+ * @memberof x3dom.nodeTypes.X3DShapeNode
+ * @initvalue x3dom.nodeTypes.X3DGeometryNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('geometry', x3dom.nodeTypes.X3DGeometryNode);
+
+ this._objectID = 0;
+ this._shaderProperties = null;
+ this._clipPlanes = [];
+
+ // in WebGL-based renderer a clean-up function is attached
+ this._cleanupGLObjects = null;
+
+ this._dirty = {
+ positions: true,
+ normals: true,
+ texcoords: true,
+ colors: true,
+ specialAttribs: true, // e.g., particleSize, IDs,...
+ indexes: true,
+ texture: true,
+ material: true,
+ text: true,
+ shader: true
+ };
+
+ // FIXME; move somewhere else and allow generic values!!!
+ this._coordStrideOffset = [0, 0];
+ this._normalStrideOffset = [0, 0];
+ this._texCoordStrideOffset = [0, 0];
+ this._colorStrideOffset = [0, 0];
+
+ this._tessellationProperties = [];
+ },
+ {
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ // attention, in contrast to other collectDrawableObjects()
+ // this one has boolean return type to better work with RSG
+ var graphState = this.graphState();
+
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ if (!this._cf.geometry.node ||
+ drawableCollection.cull(transform, graphState, singlePath, planeMask) <= 0) {
+ return false;
+ }
+
+ if (singlePath && !this._graph.globalMatrix)
+ this._graph.globalMatrix = transform;
+
+ if (this._clipPlanes.length != clipPlanes.length)
+ {
+ this._dirty.shader = true;
+ }
+
+ this._clipPlanes = clipPlanes;
+
+ drawableCollection.addShape(this, transform, graphState);
+
+ return true;
+ },
+
+ getVolume: function()
+ {
+ var vol = this._graph.volume;
+
+ if (!this.volumeValid() && this._vf.render)
+ {
+ var geo = this._cf.geometry.node;
+ var childVol = geo ? geo.getVolume() : null;
+
+ if (childVol && childVol.isValid())
+ vol.extendBounds(childVol.min, childVol.max);
+ }
+
+ return vol;
+ },
+
+ getCenter: function() {
+ var geo = this._cf.geometry.node;
+ return (geo ? geo.getCenter() : new x3dom.fields.SFVec3f(0,0,0));
+ },
+
+ getDiameter: function() {
+ var geo = this._cf.geometry.node;
+ return (geo ? geo.getDiameter() : 0);
+ },
+
+ doIntersect: function(line) {
+ return this._cf.geometry.node.doIntersect(line);
+ },
+
+ forceUpdateCoverage: function()
+ {
+ var geo = this._cf.geometry.node;
+ return (geo ? geo.forceUpdateCoverage() : false);
+ },
+
+ tessellationProperties: function()
+ {
+ // some geometries require offset and count into index array
+ var geo = this._cf.geometry.node;
+ if (geo && geo._indexOffset)
+ return geo._indexOffset; // IndexedTriangleStripSet
+ else
+ return this._tessellationProperties; // BVHRefiner-Patch
+ },
+
+ isLit: function() {
+ return this._cf.geometry.node._vf.lit;
+ },
+
+ isSolid: function() {
+ var twoSidedMat = (this._cf.appearance.node && this._cf.appearance.node._cf.material.node &&
+ x3dom.isa(this._cf.appearance.node._cf.material.node, x3dom.nodeTypes.TwoSidedMaterial));
+ return this._cf.geometry.node._vf.solid && !twoSidedMat;
+ },
+
+ isCCW: function() {
+ return this._cf.geometry.node._vf.ccw;
+ },
+
+ parentRemoved: function(parent) {
+ for (var i=0, n=this._childNodes.length; i<n; i++) {
+ var child = this._childNodes[i];
+ if (child) {
+ child.parentRemoved(this);
+ }
+ }
+
+ if (parent)
+ parent.invalidateVolume();
+ if (this._parentNodes.length > 0)
+ this.invalidateVolume();
+
+ // Cleans all GL objects for WebGL-based renderer
+ if (this._cleanupGLObjects) {
+ this._cleanupGLObjects();
+ }
+ },
+
+ unsetDirty: function () {
+ // vertex attributes
+ this._dirty.positions = false;
+ this._dirty.normals = false;
+ this._dirty.texcoords = false;
+ this._dirty.colors = false;
+ this._dirty.specialAttribs = false;
+ // indices/topology
+ this._dirty.indexes = false;
+ // appearance properties
+ this._dirty.texture = false;
+ this._dirty.material = false;
+ this._dirty.text = false;
+ this._dirty.shader = false;
+ },
+
+ unsetGeoDirty: function () {
+ this._dirty.positions = false;
+ this._dirty.normals = false;
+ this._dirty.texcoords = false;
+ this._dirty.colors = false;
+ this._dirty.specialAttribs = false;
+ this._dirty.indexes = false;
+ },
+
+ setAllDirty: function () {
+ // vertex attributes
+ this._dirty.positions = true;
+ this._dirty.normals = true;
+ this._dirty.texcoords = true;
+ this._dirty.colors = true;
+ this._dirty.specialAttribs = true;
+ // indices/topology
+ this._dirty.indexes = true;
+ // appearance properties
+ this._dirty.texture = true;
+ this._dirty.material = true;
+ this._dirty.text = true;
+ this._dirty.shader = true;
+ // finally invalidate volume
+ this.invalidateVolume();
+ },
+
+ setAppDirty: function () {
+ // appearance properties
+ this._dirty.texture = true;
+ this._dirty.material = true;
+ //this._dirty.text = true;
+ this._dirty.shader = true;
+ },
+
+ setGeoDirty: function () {
+ this._dirty.positions = true;
+ this._dirty.normals = true;
+ this._dirty.texcoords = true;
+ this._dirty.colors = true;
+ this._dirty.specialAttribs = true;
+ this._dirty.indexes = true;
+ // finally invalidate volume
+ this.invalidateVolume();
+ },
+
+ getShaderProperties: function(viewarea)
+ {
+ if (this._shaderProperties == null ||
+ this._dirty.shader == true ||
+ (this._webgl !== undefined &&
+ this._webgl.dirtyLighting != x3dom.Utils.checkDirtyLighting(viewarea) ) ||
+ x3dom.Utils.checkDirtyEnvironment(viewarea, this._shaderProperties) == true)
+ {
+ this._shaderProperties = x3dom.Utils.generateProperties(viewarea, this);
+
+ this._dirty.shader = false;
+ if (this._webgl !== undefined)
+ {
+ this._webgl.dirtyLighting = x3dom.Utils.checkDirtyLighting(viewarea);
+ }
+ }
+
+ return this._shaderProperties;
+ },
+
+ getTextures: function() {
+ var textures = [];
+
+ var appearance = this._cf.appearance.node;
+ if (appearance) {
+ var tex = appearance._cf.texture.node;
+ if(tex) {
+ if(x3dom.isa(tex, x3dom.nodeTypes.MultiTexture)) {
+ textures = textures.concat(tex.getTextures());
+ }
+ else {
+ textures.push(tex);
+ }
+ }
+
+ var shader = appearance._cf.shaders.nodes[0];
+ if(shader) {
+ if(x3dom.isa(shader, x3dom.nodeTypes.CommonSurfaceShader)) {
+ textures = textures.concat(shader.getTextures());
+ }
+ }
+ }
+
+ var geometry = this._cf.geometry.node;
+ if (geometry) {
+ if(x3dom.isa(geometry, x3dom.nodeTypes.ImageGeometry)) {
+ textures = textures.concat(geometry.getTextures());
+ }
+ else if(x3dom.isa(geometry, x3dom.nodeTypes.Text)) {
+ textures = textures.concat(geometry);
+ }
+ }
+
+ return textures;
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Shape ### */
+x3dom.registerNodeType(
+ "Shape",
+ "Shape",
+ defineClass(x3dom.nodeTypes.X3DShapeNode,
+
+ /**
+ * Constructor for Shape
+ * @constructs x3dom.nodeTypes.Shape
+ * @x3d 3.3
+ * @component Shape
+ * @status full
+ * @extends x3dom.nodeTypes.X3DShapeNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Shape node has two fields, appearance and geometry, that are used to create rendered objects in the world.
+ * The appearance field contains an Appearance node that specifies the visual attributes (e.g., material and texture) to be applied to the geometry.
+ * The geometry field contains a geometry node. The specified geometry node is rendered with the specified appearance nodes applied.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Shape.superClass.call(this, ctx);
+
+ },
+ {
+ nodeChanged: function () {
+ //TODO delete this if all works fine
+ if (!this._cf.appearance.node) {
+ //Unlit
+ //this.addChild(x3dom.nodeTypes.Appearance.defaultNode());
+ }
+ if (!this._cf.geometry.node) {
+ if (this._DEF)
+ x3dom.debug.logError("No geometry given in Shape/" + this._DEF);
+ }
+ else if (!this._objectID) {
+ this._objectID = ++x3dom.nodeTypes.Shape.objectID;
+ x3dom.nodeTypes.Shape.idMap.nodeID[this._objectID] = this;
+ }
+ this.invalidateVolume();
+ }
+ }
+ )
+);
+
+/** Static class ID counter (needed for caching) */
+x3dom.nodeTypes.Shape.shaderPartID = 0;
+
+/** Static class ID counter (needed for picking) */
+x3dom.nodeTypes.Shape.objectID = 0;
+
+/** Map for Shape node IDs (needed for picking) */
+x3dom.nodeTypes.Shape.idMap = {
+ nodeID: {},
+ remove: function(obj) {
+ for (var prop in this.nodeID) {
+ if (this.nodeID.hasOwnProperty(prop)) {
+ var val = this.nodeID[prop];
+ if (val._objectID && obj._objectID &&
+ val._objectID === obj._objectID)
+ {
+ delete this.nodeID[prop];
+ x3dom.debug.logInfo("Unreg " + val._objectID);
+ // FIXME; handle node removal to unreg from map,
+ // and put free'd ID back to ID pool for reuse
+ }
+ }
+ }
+ }
+};
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DLightNode ### */
+x3dom.registerNodeType(
+ "X3DLightNode",
+ "Lighting",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DLightNode
+ * @constructs x3dom.nodeTypes.X3DLightNode
+ * @x3d 3.3
+ * @component Lighting
+ * @status full
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The X3DLightNode abstract node type is the base type from which all node types that serve as light sources are derived.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DLightNode.superClass.call(this, ctx);
+
+ if (ctx)
+ ctx.doc._nodeBag.lights.push(this);
+ else
+ x3dom.debug.logWarning("X3DLightNode: No runtime context found!");
+
+ this._lightID = 0;
+ this._dirty = true;
+
+
+ /**
+ * The ambientIntensity specifies the intensity of the ambient emission from the light. Light intensity may range from 0.0 (no light emission) to 1.0 (full intensity).
+ * @var {x3dom.fields.SFFloat} ambientIntensity
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'ambientIntensity', 0);
+
+ /**
+ * The color field specifies the spectral colour properties of both the direct and ambient light emission as an RGB value.
+ * @var {x3dom.fields.SFColor} color
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue 1,1,1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'color', 1, 1, 1);
+
+ /**
+ * The intensity field specifies the brightness of the direct emission from the light. Light intensity may range from 0.0 (no light emission) to 1.0 (full intensity).
+ * @var {x3dom.fields.SFFloat} intensity
+ * @range [0, 1]
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue 1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'intensity', 1);
+
+ /**
+ * Specifies whether the light is global or scoped.
+ * Global lights illuminate all objects that fall within their volume of lighting influence.
+ * Scoped lights only illuminate objects that are in the same transformation hierarchy as the light; i.e., only the children and descendants of its enclosing parent group are illuminated.
+ * @var {x3dom.fields.SFBool} global
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'global', false);
+
+ /**
+ * The on field specifies whether the light is enabled or disabled.
+ * @var {x3dom.fields.SFBool} on
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'on', true);
+
+ /**
+ * Defines the attenuation of the shadows
+ * @var {x3dom.fields.SFFloat} shadowIntensity
+ * @range [o, 1]
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shadowIntensity', 0);
+
+ /**
+ * Specifies the resolution of the used shadow map.
+ * @var {x3dom.fields.SFInt32} shadowMapSize
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue 1024
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'shadowMapSize', 1024);
+
+ /**
+ * Sets the smoothness of the shadow umbra.
+ * @var {x3dom.fields.SFInt32} shadowFilterSize
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'shadowFilterSize', 0);
+
+ /**
+ * Defines the shadow offset for the back projection of the shadow map.
+ * @var {x3dom.fields.SFFloat} shadowOffset
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shadowOffset', 0);
+
+ /**
+ * Specifies the placement of the near plane of the light projection.
+ * Objects that are closer to the light source than the near plane do not cast shadows.
+ * If the zNear value is not set, the near plane is placed automatically.
+ * @var {x3dom.fields.SFFloat} zNear
+ * @range -1 or [0, inf]
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zNear', -1);
+
+ /**
+ * Specifies the placement of the far plane of the light projection.
+ * Objects that are farther away from the light source than the far plane do not cast shadows.
+ * If the zFar value is not set, the far plane is placed automatically.
+ * @var {x3dom.fields.SFFloat} zFar
+ * @range -1 or [0, inf]
+ * @memberof x3dom.nodeTypes.X3DLightNode
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zFar', -1);
+
+ },
+ {
+ getViewMatrix: function(vec) {
+ return x3dom.fields.SFMatrix4f.identity;
+ },
+
+ nodeChanged: function () {
+ if(!this._lightID) {
+ this._lightID = ++x3dom.nodeTypes.X3DLightNode.lightID;
+ }
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (this._vf.hasOwnProperty(fieldName)) {
+ this._dirty = true;
+ }
+ },
+
+ parentRemoved: function(parent)
+ {
+ if (this._parentNodes.length === 0) {
+ var doc = this.findX3DDoc();
+
+ for (var i=0, n=doc._nodeBag.lights.length; i<n; i++) {
+ if (doc._nodeBag.lights[i] === this) {
+ doc._nodeBag.lights.splice(i, 1);
+ }
+ }
+ }
+ }
+ }
+ )
+);
+
+/** Static class ID counter (needed for flash performance up) */
+x3dom.nodeTypes.X3DLightNode.lightID = 0;
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### DirectionalLight ### */
+x3dom.registerNodeType(
+ "DirectionalLight",
+ "Lighting",
+ defineClass(x3dom.nodeTypes.X3DLightNode,
+
+ /**
+ * Constructor for DirectionalLight
+ * @constructs x3dom.nodeTypes.DirectionalLight
+ * @x3d 3.3
+ * @component Lighting
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DLightNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The DirectionalLight node defines a directional light source that illuminates along rays parallel to a given 3-dimensional vector.
+ * A directional light source illuminates only the objects in its enclosing parent group.
+ * The light may illuminate everything within this coordinate system, including all children and descendants of its parent group.
+ * The accumulated transformations of the parent nodes affect the light.
+ * DirectionalLight nodes do not attenuate with distance.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.DirectionalLight.superClass.call(this, ctx);
+
+
+ /**
+ * The direction field specifies the direction vector of the illumination emanating from the light source in the local coordinate system.
+ * @var {x3dom.fields.SFVec3f} direction
+ * @memberof x3dom.nodeTypes.DirectionalLight
+ * @initvalue 0,0,-1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'direction', 0, 0, -1);
+
+ /**
+ *
+ * @var {x3dom.fields.SFInt32} shadowCascades
+ * @memberof x3dom.nodeTypes.DirectionalLight
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'shadowCascades', 1);
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} shadowSplitFactor
+ * @memberof x3dom.nodeTypes.DirectionalLight
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shadowSplitFactor', 1);
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} shadowSplitOffset
+ * @memberof x3dom.nodeTypes.DirectionalLight
+ * @initvalue 0.1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shadowSplitOffset', 0.1);
+
+ },
+ {
+ getViewMatrix: function(vec) {
+ var dir = this.getCurrentTransform().multMatrixVec(this._vf.direction).normalize();
+ var orientation = x3dom.fields.Quaternion.rotateFromTo(
+ new x3dom.fields.SFVec3f(0, 0, -1), dir);
+ return orientation.toMatrix().transpose().
+ mult(x3dom.fields.SFMatrix4f.translation(vec.negate()));
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PointLight ### */
+x3dom.registerNodeType(
+ "PointLight",
+ "Lighting",
+ defineClass(x3dom.nodeTypes.X3DLightNode,
+
+ /**
+ * Constructor for PointLight
+ * @constructs x3dom.nodeTypes.PointLight
+ * @x3d 3.3
+ * @component Lighting
+ * @status full
+ * @extends x3dom.nodeTypes.X3DLightNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PointLight node specifies a point light source at a 3D location in the local coordinate system.
+ * A point light source emits light equally in all directions; that is, it is omnidirectional.
+ * PointLight nodes are specified in the local coordinate system and are affected by ancestor transformations.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PointLight.superClass.call(this, ctx);
+
+
+ /**
+ * PointLight node's illumination falls off with distance as specified by three attenuation coefficients. The attenuation factor is:
+ * 1/max(attenuation[0] + attenuation[1] × r + attenuation[2] × r^2, 1)
+ * where r is the distance from the light to the surface being illuminated.
+ * The default is no attenuation.
+ * An attenuation value of (0, 0, 0) is identical to (1, 0, 0). Attenuation values shall be greater than or equal to zero.
+ * @var {x3dom.fields.SFVec3f} attenuation
+ * @memberof x3dom.nodeTypes.PointLight
+ * @initvalue 1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'attenuation', 1, 0, 0);
+
+ /**
+ * The position of the Light
+ * @var {x3dom.fields.SFVec3f} location
+ * @memberof x3dom.nodeTypes.PointLight
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'location', 0, 0, 0);
+
+ /**
+ * A PointLight node illuminates geometry within radius length base units of its location.
+ * Radius is affected by ancestors' transformations.
+ * @var {x3dom.fields.SFFloat} radius
+ * @memberof x3dom.nodeTypes.PointLight
+ * @initvalue 100
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'radius', 100);
+
+ this._vf.global = true;
+
+ },
+ {
+ getViewMatrix: function(vec) {
+ var pos = this.getCurrentTransform().multMatrixPnt(this._vf.location);
+ var orientation = x3dom.fields.Quaternion.rotateFromTo(
+ new x3dom.fields.SFVec3f(0, 0, -1), vec);
+ return orientation.toMatrix().transpose().
+ mult(x3dom.fields.SFMatrix4f.translation(pos.negate()));
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### SpotLight ### */
+x3dom.registerNodeType(
+ "SpotLight",
+ "Lighting",
+ defineClass(x3dom.nodeTypes.X3DLightNode,
+
+ /**
+ * Constructor for SpotLight
+ * @constructs x3dom.nodeTypes.SpotLight
+ * @x3d 3.3
+ * @component Lighting
+ * @status full
+ * @extends x3dom.nodeTypes.X3DLightNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The SpotLight node defines a light source that emits light from a specific point along a specific direction vector and constrained within a solid angle.
+ * Spotlights may illuminate geometry nodes that respond to light sources and intersect the solid angle defined by the SpotLight.
+ * Spotlight nodes are specified in the local coordinate system and are affected by ancestors' transformations.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.SpotLight.superClass.call(this, ctx);
+
+
+ /**
+ * The direction field specifies the direction vector of the light's central axis defined in the local coordinate system.
+ * @var {x3dom.fields.SFVec3f} direction
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 0,0,-1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'direction', 0, 0, -1);
+
+ /**
+ * SpotLight node's illumination falls off with distance as specified by three attenuation coefficients. The attenuation factor is:
+ * 1/max(attenuation[0] + attenuation[1] × r + attenuation[2] × r^2, 1)
+ * where r is the distance from the light to the surface being illuminated.
+ * The default is no attenuation.
+ * An attenuation value of (0, 0, 0) is identical to (1, 0, 0). Attenuation values shall be greater than or equal to zero.
+ * @var {x3dom.fields.SFVec3f} attenuation
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'attenuation', 1, 0, 0);
+
+ /**
+ * The location field specifies a translation offset of the centre point of the light source from the light's local coordinate system origin.
+ * This point is the apex of the solid angle which bounds light emission from the given light source.
+ * Location is affected by ancestors' transformations.
+ * @var {x3dom.fields.SFVec3f} location
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'location', 0, 0, 0);
+
+ /**
+ * The radius field specifies the radial extent of the solid angle and the maximum distance from location that may be illuminated by the light source.
+ * The light source does not emit light outside this radius. The radius shall be greater than or equal to zero.
+ * Radius is affected by ancestors' transformations.
+ * @var {x3dom.fields.SFFloat} radius
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 100
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'radius', 100);
+
+ /**
+ * The beamWidth field specifies an inner solid angle in which the light source emits light at uniform full intensity.
+ * The light source's emission intensity drops off from the inner solid angle (beamWidth) to the outer solid angle (cutOffAngle).
+ * If the beamWidth is greater than the cutOffAngle, beamWidth is defined to be equal to the cutOffAngle and the light source emits full intensity within the entire solid angle defined by cutOffAngle.
+ * @var {x3dom.fields.SFFloat} beamWidth
+ * @range [0, pi/2]
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 1.5707963
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'beamWidth', 1.5707963);
+
+ /**
+ * The cutOffAngle field specifies the outer bound of the solid angle. The light source does not emit light outside of this solid angle.
+ * The light source's emission intensity drops off from the inner solid angle (beamWidth) to the outer solid angle (cutOffAngle).
+ * If the beamWidth is greater than the cutOffAngle, beamWidth is defined to be equal to the cutOffAngle and the light source emits full intensity within the entire solid angle defined by cutOffAngle.
+ * @range [0, pi/2]
+ * @var {x3dom.fields.SFFloat} cutOffAngle
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 1.5707963
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'cutOffAngle', 1.5707963);
+
+ /**
+ *
+ * @var {x3dom.fields.SFInt32} shadowCascades
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'shadowCascades', 1);
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} shadowSplitFactor
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shadowSplitFactor', 1);
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} shadowSplitOffset
+ * @memberof x3dom.nodeTypes.SpotLight
+ * @initvalue 0.1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shadowSplitOffset', 0.1);
+
+ this._vf.global = true;
+
+ },
+ {
+ getViewMatrix: function(vec) {
+ var pos = this.getCurrentTransform().multMatrixPnt(this._vf.location);
+ var dir = this.getCurrentTransform().multMatrixVec(this._vf.direction).normalize();
+ var orientation = x3dom.fields.Quaternion.rotateFromTo(
+ new x3dom.fields.SFVec3f(0, 0, -1), dir);
+ return orientation.toMatrix().transpose().
+ mult(x3dom.fields.SFMatrix4f.translation(pos.negate()));
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DFollowerNode ### */
+x3dom.registerNodeType(
+ "X3DFollowerNode",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DFollowerNode
+ * @constructs x3dom.nodeTypes.X3DFollowerNode
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc An X3DFollowerNode maintains an internal state that consists of a current value and a destination
+ * value. Both values are of the same data type into which the term [S|M]F<type> evaluatesfor a given
+ * specialization. It is the 'data type of the node'. In certain cases of usage, the terms input and output fit
+ * better for destination value and current value, respectively.
+ * Whenever the current value differs from the destination value, the current value gradually changes until it
+ * reaches the destination value producing a smooth transition. It generally moves towards the destination
+ * value but, if a transition triggered by a prevous destination value is still in progress, it may take a
+ * short while until the movement becomes a movement towards the new destination value.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DFollowerNode.superClass.call(this, ctx);
+
+ if (ctx)
+ ctx.doc._nodeBag.followers.push(this);
+ else
+ x3dom.debug.logWarning("X3DFollowerNode: No runtime context found!");
+
+
+ /**
+ * isActive shows if the sensor is active
+ * @var {x3dom.fields.SFBool} isActive
+ * @memberof x3dom.nodeTypes.X3DFollowerNode
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'isActive', false);
+
+ // http://www.web3d.org/files/specifications/19775-1/V3.3/Part01/components/followers.html
+ // [S|M]F<type> [in] set_destination
+ // [S|M]F<type> [in] set_value
+ // [S|M]F<type> [out] value
+ // SFBool [out] isActive
+ // [S|M]F<type> [] initialDestination
+ // [S|M]F<type> [] initialValue
+
+ this._eps = x3dom.fields.Eps; //0.001;
+
+ },
+ {
+ parentRemoved: function(parent)
+ {
+ if (this._parentNodes.length === 0) {
+ var doc = this.findX3DDoc();
+
+ for (var i=0, n=doc._nodeBag.followers.length; i<n; i++) {
+ if (doc._nodeBag.followers[i] === this) {
+ doc._nodeBag.followers.splice(i, 1);
+ }
+ }
+ }
+ },
+
+ tick: function(t) {
+ return false;
+ },
+
+ stepResponse: function(t)
+ {
+ if (t <= 0) {
+ return 0;
+ }
+
+ if (t >= this._vf.duration) {
+ return 1;
+ }
+
+ // When optimizing for speed, the above two if(.) cases can be omitted,
+ // as this function will not be called for values outside of 0..duration.
+ return this.stepResponseCore(t / this._vf.duration);
+ },
+
+ // This function defines the shape of how the output responds to the initialDestination.
+ // It must accept values for T in the range 0 <= T <= 1.
+ // In this._vf.order to create a smooth animation, it should return 0 for T == 0,
+ // 1 for T == 1 and be sufficient smooth in the range 0 <= T <= 1.
+ //
+ // It should be optimized for speed, in this._vf.order for high performance. It's
+ // executed _buffer.length + 1 times each simulation tick.
+ stepResponseCore: function(T)
+ {
+ return 0.5 - 0.5 * Math.cos(T * Math.PI);
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DChaserNode ### */
+x3dom.registerNodeType(
+ "X3DChaserNode",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DFollowerNode,
+
+ /**
+ * Constructor for X3DChaserNode
+ * @constructs x3dom.nodeTypes.X3DChaserNode
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DFollowerNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The X3DChaserNode abstract node type calculates the output on value_changed as a finite impulse
+ * response (FIR).
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DChaserNode.superClass.call(this, ctx);
+
+
+ /**
+ * Duration of the transition
+ * @var {x3dom.fields.SFTime} duration
+ * @memberof x3dom.nodeTypes.X3DChaserNode
+ * @initvalue 1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'duration', 1);
+
+ this._initDone = false;
+ this._stepTime = 0;
+ this._currTime = 0;
+ this._bufferEndTime = 0;
+ this._numSupports = 60;
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DDamperNode ### */
+x3dom.registerNodeType(
+ "X3DDamperNode",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DFollowerNode,
+
+ /**
+ * Constructor for X3DDamperNode
+ * @constructs x3dom.nodeTypes.X3DDamperNode
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DFollowerNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The X3DDamperNode abstract node type creates an IIR response that approaches the destination
+ * value according to the shape of the e-function only asymptotically but very quickly. An X3DDamperNode node
+ * is parameterized by the tau, order and tolerance fields. Internally, it consists of a set of linear
+ * first-order filters each of which processes the output of the previous filter.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DDamperNode.superClass.call(this, ctx);
+
+
+ /**
+ * The field tau specifies the time-constant of the internal filters and thus the speed that the output of
+ * an X3DDamperNode responds to the input. A value of zero for tau means immediate response and the events
+ * received on set_destination are forwarded directly. The field tau specifies how long it takes the output
+ * of an internal filter to reach the value of its input by 63% (1 - 1/e). The remainder after that period
+ * is reduced by 63% during another period of tau seconds provided that the input of the filter does not
+ * change. This behavior can be exposed if order is set to one.
+ * @var {x3dom.fields.SFTime} tau
+ * @memberof x3dom.nodeTypes.X3DDamperNode
+ * @initvalue 0.3
+ * @range [0,inf)
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'tau', 0.3);
+
+ /**
+ * If tolerance is set to its default value -1, the browser implementation is allowed to find a good way for
+ * detecting the end of a transition. Browsers that do not have an elaborate algorithm can just use .001 as
+ * the tolerance value instead. If a value larger than zero is specified for tolerance, the browser shall
+ * calculate the difference between output and input for each internal filter being used and stop the
+ * animation only when all filters fall below that limit or are equal to it. If zero is specified for
+ * tolerance, a transition should be stopped only if input and output match exactly for all internal
+ * filters.
+ * @var {x3dom.fields.SFFloat} tolerance
+ * @memberof x3dom.nodeTypes.X3DDamperNode
+ * @initvalue -1
+ * @range -1 or [0,inf)
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'tolerance', -1);
+
+ /**
+ * The order field specifies the smoothness of the transition.
+ * @var {x3dom.fields.SFInt32} order
+ * @memberof x3dom.nodeTypes.X3DDamperNode
+ * @initvalue 3
+ * @range [0..5]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'order', 3);
+
+ this._eps = this._vf.tolerance < 0 ? this._eps : this._vf.tolerance;
+ this._lastTick = 0;
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ColorChaser ### */
+x3dom.registerNodeType(
+ "ColorChaser",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DChaserNode,
+
+ /**
+ * Constructor for ColorChaser
+ * @constructs x3dom.nodeTypes.ColorChaser
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChaserNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ColorChaser animates transitions for single color values. Whenever the set_destination
+ * field receives a floating point number, the value_changed creates a transition from its current value to
+ * the newly set number. It creates a smooth transition that ends duration seconds after the last number has
+ * been received.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ColorChaser.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value as initialValue unless a transition to a
+ * certain value is to be created right after the scene is loaded or right after the ColorChaser node is
+ * created dynamically.
+ * @var {x3dom.fields.SFColor} initialDestination
+ * @memberof x3dom.nodeTypes.ColorChaser
+ * @initvalue 0.8,0.8,0.8
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'initialDestination', 0.8, 0.8, 0.8);
+
+ /**
+ * The field initialValue can be used to set the initial value.
+ * @var {x3dom.fields.SFColor} initialValue
+ * @memberof x3dom.nodeTypes.ColorChaser
+ * @initvalue 0.8,0.8,0.8
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'initialValue', 0.8, 0.8, 0.8);
+
+
+ /**
+ * The current color value
+ * @var {x3dom.fields.SFColor} value
+ * @memberof x3dom.nodeTypes.ColorChaser
+ * @initvalue 0,0,0
+ * @range [0,1]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'value', 0, 0, 0);
+
+ /**
+ * The target color value
+ * @var {x3dom.fields.SFColor} destination
+ * @memberof x3dom.nodeTypes.ColorChaser
+ * @initvalue 0,0,0
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'destination', 0, 0, 0);
+
+ this._buffer = new x3dom.fields.MFColor();
+ this._previousValue = new x3dom.fields.SFColor(0, 0, 0);
+ this._value = new x3dom.fields.SFColor(0, 0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName.indexOf("destination") >= 0)
+ {
+ this.initialize();
+ this.updateBuffer(this._currTime);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this.initialize();
+
+ this._previousValue.setValues(this._vf.value);
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C].setValues(this._vf.value);
+ }
+
+ this.postMessage('value', this._vf.value);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ /** The following handler code is copy & paste from PositionChaser
+ */
+ initialize: function()
+ {
+ if (!this._initDone)
+ {
+ this._initDone = true;
+
+ this._vf.destination = this._vf.initialDestination;
+
+ this._buffer.length = this._numSupports;
+
+ this._buffer[0] = this._vf.initialDestination;
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C] = this._vf.initialValue;
+ }
+
+ this._previousValue = this._vf.initialValue;
+
+ this._stepTime = this._vf.duration / this._numSupports;
+
+ var active = !this._buffer[0].equals(this._buffer[1], this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ }
+ },
+
+ tick: function(now)
+ {
+ this.initialize();
+ this._currTime = now;
+
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._bufferEndTime)
+ {
+ this._bufferEndTime = now; // on init
+
+ this._value = this._vf.initialValue;
+
+ this.postMessage('value', this._value);
+
+ return true;
+ }
+
+ var Frac = this.updateBuffer(now);
+
+ var Output = this._previousValue;
+
+ var DeltaIn = this._buffer[this._buffer.length - 1].subtract(this._previousValue);
+
+ var DeltaOut = DeltaIn.multiply(this.stepResponse((this._buffer.length - 1 + Frac) * this._stepTime));
+
+ Output = Output.add(DeltaOut);
+
+ for (var C=this._buffer.length - 2; C>=0; C--)
+ {
+ DeltaIn = this._buffer[C].subtract(this._buffer[C + 1]);
+
+ DeltaOut = DeltaIn.multiply(this.stepResponse((C + Frac) * this._stepTime));
+
+ Output = Output.add(DeltaOut);
+ }
+
+ if ( !Output.equals(this._value, this._eps) ) {
+ this._value.setValues(Output);
+
+ this.postMessage('value', this._value);
+ }
+ else {
+ this.postMessage('isActive', false);
+ }
+
+ return this._vf.isActive;
+ },
+
+ updateBuffer: function(now)
+ {
+ var Frac = (now - this._bufferEndTime) / this._stepTime;
+ var C;
+ var NumToShift;
+ var Alpha;
+
+ if (Frac >= 1)
+ {
+ NumToShift = Math.floor(Frac);
+ Frac -= NumToShift;
+
+ if( NumToShift < this._buffer.length)
+ {
+ this._previousValue = this._buffer[this._buffer.length - NumToShift];
+
+ for (C=this._buffer.length - 1; C>=NumToShift; C--) {
+ this._buffer[C] = this._buffer[C - NumToShift];
+ }
+
+ for (C=0; C<NumToShift; C++)
+ {
+ Alpha = C / NumToShift;
+
+ this._buffer[C] = this._buffer[NumToShift].multiply(Alpha).add(this._vf.destination.multiply((1 - Alpha)));
+ }
+ }
+ else
+ {
+ this._previousValue = (NumToShift == this._buffer.length) ? this._buffer[0] : this._vf.destination;
+
+ for (C= 0; C<this._buffer.length; C++) {
+ this._buffer[C] = this._vf.destination;
+ }
+ }
+ this._bufferEndTime += NumToShift * this._stepTime;
+ }
+ return Frac;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ColorDamper ### */
+x3dom.registerNodeType(
+ "ColorDamper",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DDamperNode,
+
+ /**
+ * Constructor for ColorDamper
+ * @constructs x3dom.nodeTypes.ColorDamper
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDamperNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ColorDamper animates color values. Whenever the it receives a color, the ColorDamper node
+ * creates a transition from the current color to the newly set color. The transition created approaches the
+ * newly set position asymptotically during a time period of approximately three to four times the value of
+ * the field tau depending on the desired accuracy and the value of order. The order field specifies the
+ * smoothness of the transition.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ColorDamper.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain color is to be created right after the scene is loaded or right after the ColorDamper node is
+ * created dynamically.
+ * @var {x3dom.fields.SFColor} initialDestination
+ * @memberof x3dom.nodeTypes.ColorDamper
+ * @initvalue 0.8,0.8,0.8
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'initialDestination', 0.8, 0.8, 0.8);
+
+ /**
+ * The field initialValue can be used to set the initial color.
+ * @var {x3dom.fields.SFColor} initialValue
+ * @memberof x3dom.nodeTypes.ColorDamper
+ * @initvalue 0.8,0.8,0.8
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'initialValue', 0.8, 0.8, 0.8);
+
+
+ /**
+ * The current color value
+ * @var {x3dom.fields.SFColor} value
+ * @memberof x3dom.nodeTypes.ColorDamper
+ * @initvalue 0,0,0
+ * @range [0,1]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'value', 0, 0, 0);
+
+ /**
+ * The target color value
+ * @var {x3dom.fields.SFColor} destination
+ * @memberof x3dom.nodeTypes.ColorDamper
+ * @initvalue 0,0,0
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'destination', 0, 0, 0);
+
+ this._value0 = new x3dom.fields.SFColor(0, 0, 0);
+ this._value1 = new x3dom.fields.SFColor(0, 0, 0);
+ this._value2 = new x3dom.fields.SFColor(0, 0, 0);
+ this._value3 = new x3dom.fields.SFColor(0, 0, 0);
+ this._value4 = new x3dom.fields.SFColor(0, 0, 0);
+ this._value5 = new x3dom.fields.SFColor(0, 0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName === "tolerance")
+ {
+ this._eps = this._vf.tolerance < 0 ? 0.001 : this._vf.tolerance;
+ }
+ else if (fieldName.indexOf("destination") >= 0)
+ {
+ if ( !this._value0.equals(this._vf.destination, this._eps) ) {
+ this._value0 = this._vf.destination;
+
+ if (!this._vf.isActive) {
+ //this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this._value1.setValues(this._vf.value);
+ this._value2.setValues(this._vf.value);
+ this._value3.setValues(this._vf.value);
+ this._value4.setValues(this._vf.value);
+ this._value5.setValues(this._vf.value);
+ this._lastTick = 0;
+
+ this.postMessage('value', this._value5);
+
+ if (!this._vf.isActive) {
+ this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ initialize: function()
+ {
+ this._value0.setValues(this._vf.initialDestination);
+ this._value1.setValues(this._vf.initialValue);
+ this._value2.setValues(this._vf.initialValue);
+ this._value3.setValues(this._vf.initialValue);
+ this._value4.setValues(this._vf.initialValue);
+ this._value5.setValues(this._vf.initialValue);
+ this._lastTick = 0;
+
+ var active = !this._value0.equals(this._value1, this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ },
+
+ distance: function(a, b)
+ {
+ var diff = a.subtract(b);
+ return Math.sqrt(diff.r*diff.r + diff.g*diff.g + diff.b*diff.b);
+ },
+
+ // The ColorDamper animates SFColor values not in HSV space
+ // but as proposed in the original PROTO code in RGB space.
+ tick: function(now)
+ {
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._lastTick)
+ {
+ this._lastTick = now;
+ return false;
+ }
+
+ var delta = now - this._lastTick;
+
+ var alpha = Math.exp(-delta / this._vf.tau);
+
+ this._value1 = this._vf.order > 0 && this._vf.tau ?
+ this._value0.add(this._value1.subtract(this._value0).multiply(alpha)) :
+ new x3dom.fields.SFColor(this._value0.r, this._value0.g, this._value0.b);
+
+ this._value2 = this._vf.order > 1 && this._vf.tau ?
+ this._value1.add(this._value2.subtract(this._value1).multiply(alpha)) :
+ new x3dom.fields.SFColor(this._value1.r, this._value1.g, this._value1.b);
+
+ this._value3 = this._vf.order > 2 && this._vf.tau ?
+ this._value2.add(this._value3.subtract(this._value2).multiply(alpha)) :
+ new x3dom.fields.SFColor(this._value2.r, this._value2.g, this._value2.b);
+
+ this._value4 = this._vf.order > 3 && this._vf.tau ?
+ this._value3.add(this._value4.subtract(this._value3).multiply(alpha)) :
+ new x3dom.fields.SFColor(this._value3.r, this._value3.g, this._value3.b);
+
+ this._value5 = this._vf.order > 4 && this._vf.tau ?
+ this._value4.add(this._value5.subtract(this._value4).multiply(alpha)) :
+ new x3dom.fields.SFColor(this._value4.r, this._value4.g, this._value4.b);
+
+ var dist = this.distance(this._value1, this._value0);
+
+ if (this._vf.order > 1)
+ {
+ var dist2 = this.distance(this._value2, this._value1);
+ if (dist2 > dist) { dist = dist2; }
+ }
+ if (this._vf.order > 2)
+ {
+ var dist3 = this.distance(this._value3, this._value2);
+ if (dist3 > dist) { dist = dist3; }
+ }
+ if (this._vf.order > 3)
+ {
+ var dist4 = this.distance(this._value4, this._value3);
+ if (dist4 > dist) { dist = dist4; }
+ }
+ if (this._vf.order > 4)
+ {
+ var dist5 = this.distance(this._value5, this._value4);
+ if (dist5 > dist) { dist = dist5; }
+ }
+
+ if (dist <= this._eps)
+ {
+ this._value1.setValues(this._value0);
+ this._value2.setValues(this._value0);
+ this._value3.setValues(this._value0);
+ this._value4.setValues(this._value0);
+ this._value5.setValues(this._value0);
+
+ this.postMessage('value', this._value0);
+ this.postMessage('isActive', false);
+
+ this._lastTick = 0;
+
+ return false;
+ }
+
+ this.postMessage('value', this._value5);
+
+ this._lastTick = now;
+
+ return true;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### OrientationChaser ### */
+x3dom.registerNodeType(
+ "OrientationChaser",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DChaserNode,
+
+ /**
+ * Constructor for OrientationChaser
+ * @constructs x3dom.nodeTypes.OrientationChaser
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChaserNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The OrientationChaser animates transitions for orientations. If it is routed to a rotation field
+ * of a Transform node that contains an object, whenever the set_destination field receives an orientation, the
+ * OrientationChaser node rotates the object from its current orientation to the newly set orientation.
+ * It creates a smooth transition that ends duration seconds after the last orientation has been received.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.OrientationChaser.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain orientation is to be created right after the scene is loaded or right after the
+ * OrientationChaser node is created dynamically.
+ * @var {x3dom.fields.SFRotation} initialDestination
+ * @memberof x3dom.nodeTypes.OrientationChaser
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'initialDestination', 0, 1, 0, 0);
+
+ /**
+ * The field initialValue can be used to set the initial orientation of the object.
+ * @var {x3dom.fields.SFRotation} initialValue
+ * @memberof x3dom.nodeTypes.OrientationChaser
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'initialValue', 0, 1, 0, 0);
+
+
+ /**
+ * The current orientation value.
+ * @var {x3dom.fields.SFRotation} value
+ * @memberof x3dom.nodeTypes.OrientationChaser
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'value', 0, 1, 0, 0);
+
+ /**
+ * The target orientation value.
+ * @var {x3dom.fields.SFRotation} destination
+ * @memberof x3dom.nodeTypes.OrientationChaser
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'destination', 0, 1, 0, 0);
+
+ this._numSupports = 30;
+ this._buffer = new x3dom.fields.MFRotation();
+ this._previousValue = new x3dom.fields.Quaternion(0, 1, 0, 0);
+ this._value = new x3dom.fields.Quaternion(0, 1, 0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName.indexOf("destination") >= 0)
+ {
+ this.initialize();
+ this.updateBuffer(this._currTime);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this.initialize();
+
+ this._previousValue.setValues(this._vf.value);
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C].setValues(this._vf.value);
+ }
+
+ this.postMessage('value', this._vf.value);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ /** The following handler code was basically taken from
+ * http://www.hersto.com/X3D/Followers
+ */
+ initialize: function()
+ {
+ if (!this._initDone)
+ {
+ this._initDone = true;
+
+ this._vf.destination = x3dom.fields.Quaternion.copy(this._vf.initialDestination);
+
+ this._buffer.length = this._numSupports;
+
+ this._buffer[0] = x3dom.fields.Quaternion.copy(this._vf.initialDestination);
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C] = x3dom.fields.Quaternion.copy(this._vf.initialValue);
+ }
+
+ this._previousValue = x3dom.fields.Quaternion.copy(this._vf.initialValue);
+
+ this._stepTime = this._vf.duration / this._numSupports;
+
+ var active = !this._buffer[0].equals(this._buffer[1], this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ }
+ },
+
+ tick: function(now)
+ {
+ this.initialize();
+ this._currTime = now;
+
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._bufferEndTime)
+ {
+ this._bufferEndTime = now; // first event we received, so we are in the initialization phase.
+
+ this._value = x3dom.fields.Quaternion.copy(this._vf.initialValue);
+
+ this.postMessage('value', this._value);
+
+ return true;
+ }
+
+ var Frac = this.updateBuffer(now);
+ // Frac is a value in 0 <= Frac < 1.
+
+ // now we can calculate the output.
+ // This means we calculate the delta between each entry in _buffer and its previous
+ // entries, calculate the step response of each such step and add it to form the output.
+
+ // The oldest value _buffer[_buffer.length - 1] needs some extra thought, because it has
+ // no previous value. More exactly, we haven't stored a previous value anymore.
+ // However, the step response of that missing previous value has already reached its
+ // destination, so we can - would we have that previous value - use this as a start point
+ // for adding the step responses.
+ // Actually updateBuffer(.) maintains this value in
+
+ var Output = x3dom.fields.Quaternion.copy(this._previousValue);
+
+ var DeltaIn = this._previousValue.inverse().multiply(this._buffer[this._buffer.length - 1]);
+
+ Output = Output.slerp(Output.multiply(DeltaIn), this.stepResponse((this._buffer.length - 1 + Frac) * this._stepTime));
+
+ for (var C=this._buffer.length - 2; C>=0; C--)
+ {
+ DeltaIn = this._buffer[C + 1].inverse().multiply(this._buffer[C]);
+
+ Output = Output.slerp(Output.multiply(DeltaIn), this.stepResponse((C + Frac) * this._stepTime));
+ }
+
+ if ( !Output.equals(this._value, this._eps) ) {
+ Output = Output.normalize(Output);
+ this._value.setValues(Output);
+
+ this.postMessage('value', this._value);
+ }
+ else {
+ this.postMessage('isActive', false);
+ }
+
+ return this._vf.isActive;
+ },
+
+ updateBuffer: function(now)
+ {
+ var Frac = (now - this._bufferEndTime) / this._stepTime;
+ var C;
+ var NumToShift;
+ var Alpha;
+ // is normally < 1. When it has grown to be larger than 1, we have to shift the array because the step response
+ // of the oldest entry has already reached its destination, and it's time for a newer entry.
+ // In the case of a very low frame rate, or a very short _stepTime we may need to shift by more than one entry.
+
+ if (Frac >= 1)
+ {
+ NumToShift = Math.floor(Frac);
+ Frac -= NumToShift;
+
+ if( NumToShift < this._buffer.length)
+ {
+ // normal case
+ this._previousValue = x3dom.fields.Quaternion.copy(this._buffer[this._buffer.length - NumToShift]);
+
+ for (C=this._buffer.length - 1; C>=NumToShift; C--) {
+ this._buffer[C] = x3dom.fields.Quaternion.copy(this._buffer[C - NumToShift]);
+ }
+
+ for (C=0; C<NumToShift; C++)
+ {
+ // Hmm, we have a destination value, but don't know how it has
+ // reached the current state.
+ // Therefore we do a linear interpolation from the latest value in the buffer to destination.
+ Alpha = C / NumToShift;
+
+ this._buffer[C] = this._vf.destination.slerp(this._buffer[NumToShift], Alpha);
+ }
+ }
+ else
+ {
+ // degenerated case:
+ //
+ // We have a _VERY_ low frame rate...
+ // we can only guess how we should fill the array.
+ // Maybe we could write part of a linear interpolation
+ // from this._buffer[0] to destination, that goes from this._bufferEndTime to now
+ // (possibly only the end of the interpolation is to be written),
+ // but if we reach here we are in a very degenerate case...
+ // Thus we just write destination to the buffer.
+
+ this._previousValue = x3dom.fields.Quaternion.copy((NumToShift == this._buffer.length) ?
+ this._buffer[0] : this._vf.destination);
+
+ for (C= 0; C<this._buffer.length; C++) {
+ this._buffer[C] = x3dom.fields.Quaternion.copy(this._vf.destination);
+ }
+ }
+
+ this._bufferEndTime += NumToShift * this._stepTime;
+ }
+
+ return Frac;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### OrientationDamper ### */
+x3dom.registerNodeType(
+ "OrientationDamper",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DDamperNode,
+
+ /**
+ * Constructor for OrientationDamper
+ * @constructs x3dom.nodeTypes.OrientationDamper
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDamperNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The OrientationDamper animates transitions of orientations. If its value is routed to an
+ * orientation field of a Transform node that contains an object, then, whenever the destination field receives
+ * an orientation, the OrientationDamper node rotates the object from its current orientation to the newly set
+ * orientation. It creates a transition that approaches the newly set orientation asymptotically during a time
+ * period of approximately three to four times the value of the field tau depending on the desired accuracy and
+ * the value of order. Through this asymptotic approach of the destination orientation, a very smooth
+ * transition is created.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.OrientationDamper.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain orientation is to be created right after the scene is loaded or right after the
+ * OrientationDamper node is created dynamically.
+ * @var {x3dom.fields.SFRotation} initialDestination
+ * @memberof x3dom.nodeTypes.OrientationDamper
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'initialDestination', 0, 1, 0, 0);
+
+ /**
+ * The field initialValue can be used to set the initial orientation of the object.
+ * @var {x3dom.fields.SFRotation} initialValue
+ * @memberof x3dom.nodeTypes.OrientationDamper
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'initialValue', 0, 1, 0, 0);
+
+
+ /**
+ * The current orientation value.
+ * @var {x3dom.fields.SFRotation} value
+ * @memberof x3dom.nodeTypes.OrientationDamper
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'value', 0, 1, 0, 0);
+
+ /**
+ * The target orientation value
+ * @var {x3dom.fields.SFRotation} destination
+ * @memberof x3dom.nodeTypes.OrientationDamper
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'destination', 0, 1, 0, 0);
+
+ this._value0 = new x3dom.fields.Quaternion(0, 1, 0, 0);
+ this._value1 = new x3dom.fields.Quaternion(0, 1, 0, 0);
+ this._value2 = new x3dom.fields.Quaternion(0, 1, 0, 0);
+ this._value3 = new x3dom.fields.Quaternion(0, 1, 0, 0);
+ this._value4 = new x3dom.fields.Quaternion(0, 1, 0, 0);
+ this._value5 = new x3dom.fields.Quaternion(0, 1, 0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName === "tolerance")
+ {
+ this._eps = this._vf.tolerance < 0 ? 0.001 : this._vf.tolerance;
+ }
+ else if (fieldName.indexOf("destination") >= 0)
+ {
+ if ( !this._value0.equals(this._vf.destination, this._eps) ) {
+ this._value0 = this._vf.destination;
+
+ if (!this._vf.isActive) {
+ //this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this._value1.setValues(this._vf.value);
+ this._value2.setValues(this._vf.value);
+ this._value3.setValues(this._vf.value);
+ this._value4.setValues(this._vf.value);
+ this._value5.setValues(this._vf.value);
+ this._lastTick = 0;
+
+ this.postMessage('value', this._value5);
+
+ if (!this._vf.isActive) {
+ this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ initialize: function()
+ {
+ this._value0.setValues(this._vf.initialDestination);
+ this._value1.setValues(this._vf.initialValue);
+ this._value2.setValues(this._vf.initialValue);
+ this._value3.setValues(this._vf.initialValue);
+ this._value4.setValues(this._vf.initialValue);
+ this._value5.setValues(this._vf.initialValue);
+ this._lastTick = 0;
+
+ var active = !this._value0.equals(this._value1, this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ },
+
+ tick: function(now)
+ {
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._lastTick)
+ {
+ this._lastTick = now;
+ return false;
+ }
+
+ var delta = now - this._lastTick;
+
+ var alpha = Math.exp(-delta / this._vf.tau);
+
+ this._value1 = this._vf.order > 0 && this._vf.tau ?
+ this._value0.slerp(this._value1, alpha) :
+ new x3dom.fields.Quaternion(this._value0.x, this._value0.y, this._value0.z, this._value0.w);
+
+ this._value2 = this._vf.order > 1 && this._vf.tau ?
+ this._value1.slerp(this._value2, alpha) :
+ new x3dom.fields.Quaternion(this._value1.x, this._value1.y, this._value1.z, this._value1.w);
+
+ this._value3 = this._vf.order > 2 && this._vf.tau ?
+ this._value2.slerp(this._value3, alpha) :
+ new x3dom.fields.Quaternion(this._value2.x, this._value2.y, this._value2.z, this._value2.w);
+
+ this._value4 = this._vf.order > 3 && this._vf.tau ?
+ this._value3.slerp(this._value4, alpha) :
+ new x3dom.fields.Quaternion(this._value3.x, this._value3.y, this._value3.z, this._value3.w);
+
+ this._value5 = this._vf.order > 4 && this._vf.tau ?
+ this._value4.slerp(this._value5, alpha) :
+ new x3dom.fields.Quaternion(this._value4.x, this._value4.y, this._value4.z, this._value4.w);
+
+ var dist = Math.abs(this._value1.inverse().multiply(this._value0).angle());
+
+ if(this._vf.order > 1)
+ {
+ var dist2 = Math.abs(this._value2.inverse().multiply(this._value1).angle());
+ if (dist2 > dist) { dist = dist2; }
+ }
+ if(this._vf.order > 2)
+ {
+ var dist3 = Math.abs(this._value3.inverse().multiply(this._value2).angle());
+ if (dist3 > dist) { dist = dist3; }
+ }
+ if(this._vf.order > 3)
+ {
+ var dist4 = Math.abs(this._value4.inverse().multiply(this._value3).angle());
+ if (dist4 > dist) { dist = dist4; }
+ }
+ if(this._vf.order > 4)
+ {
+ var dist5 = Math.abs(this._value5.inverse().multiply(this._value4).angle());
+ if (dist5 > dist) { dist = dist5; }
+ }
+
+ if (dist <= this._eps)
+ {
+ this._value1.setValues(this._value0);
+ this._value2.setValues(this._value0);
+ this._value3.setValues(this._value0);
+ this._value4.setValues(this._value0);
+ this._value5.setValues(this._value0);
+
+ this.postMessage('value', this._value0);
+ this.postMessage('isActive', false);
+
+ this._lastTick = 0;
+
+ return false;
+ }
+
+ this.postMessage('value', this._value5);
+
+ this._lastTick = now;
+
+ return true;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PositionChaser ### */
+x3dom.registerNodeType(
+ "PositionChaser",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DChaserNode,
+
+ /**
+ * Constructor for PositionChaser
+ * @constructs x3dom.nodeTypes.PositionChaser
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChaserNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PositionChaser animates transitions for 3D vectors. If its value field is routed to a
+ * translation field of a Transform node that contains an object, then, whenever the destination field
+ * receives a 3D position, the PositionChaser node moves the object from its current position to the newly set
+ * position. It creates a smooth transition that ends duration seconds after the last position has been
+ * received.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PositionChaser.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain position is to be created right after the scene is loaded or right after the PositionChaser node
+ * is created dynamically.
+ * @var {x3dom.fields.SFVec3f} initialDestination
+ * @memberof x3dom.nodeTypes.PositionChaser
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'initialDestination', 0, 0, 0);
+
+ /**
+ * The field initialValue can be used to set the initial position of the object.
+ * @var {x3dom.fields.SFVec3f} initialValue
+ * @memberof x3dom.nodeTypes.PositionChaser
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'initialValue', 0, 0, 0);
+
+
+ /**
+ * The current orientation value.
+ * @var {x3dom.fields.SFVec3f} value
+ * @memberof x3dom.nodeTypes.PositionChaser
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'value', 0, 0, 0);
+
+ /**
+ * The target orientation value.
+ * @var {x3dom.fields.SFVec3f} destination
+ * @memberof x3dom.nodeTypes.PositionChaser
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'destination', 0, 0, 0);
+
+ this._buffer = new x3dom.fields.MFVec3f();
+ this._previousValue = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._value = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName.indexOf("destination") >= 0)
+ {
+ this.initialize();
+ this.updateBuffer(this._currTime);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this.initialize();
+
+ this._previousValue.setValues(this._vf.value);
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C].setValues(this._vf.value);
+ }
+
+ this.postMessage('value', this._vf.value);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ /** The following handler code was basically taken from
+ * http://www.hersto.com/X3D/Followers
+ */
+ initialize: function()
+ {
+ if (!this._initDone)
+ {
+ this._initDone = true;
+
+ this._vf.destination = x3dom.fields.SFVec3f.copy(this._vf.initialDestination);
+
+ this._buffer.length = this._numSupports;
+
+ this._buffer[0] = x3dom.fields.SFVec3f.copy(this._vf.initialDestination);
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C] = x3dom.fields.SFVec3f.copy(this._vf.initialValue);
+ }
+
+ this._previousValue = x3dom.fields.SFVec3f.copy(this._vf.initialValue);
+
+ this._stepTime = this._vf.duration / this._numSupports;
+
+ var active = !this._buffer[0].equals(this._buffer[1], this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ }
+ },
+
+ tick: function(now)
+ {
+ this.initialize();
+ this._currTime = now;
+
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._bufferEndTime)
+ {
+ this._bufferEndTime = now; // first event we received, so we are in the initialization phase.
+
+ this._value = x3dom.fields.SFVec3f.copy(this._vf.initialValue);
+
+ this.postMessage('value', this._value);
+
+ return true;
+ }
+
+ var Frac = this.updateBuffer(now);
+ // Frac is a value in 0 <= Frac < 1.
+
+ // now we can calculate the output.
+ // This means we calculate the delta between each entry in _buffer and its previous
+ // entries, calculate the step response of each such step and add it to form the output.
+
+ // The oldest value _buffer[_buffer.length - 1] needs some extra thought, because it has
+ // no previous value. More exactly, we haven't stored a previous value anymore.
+ // However, the step response of that missing previous value has already reached its
+ // destination, so we can - would we have that previous value - use this as a start point
+ // for adding the step responses.
+ // Actually updateBuffer(.) maintains this value in
+
+ var Output = x3dom.fields.SFVec3f.copy(this._previousValue);
+
+ var DeltaIn = this._buffer[this._buffer.length - 1].subtract(this._previousValue);
+
+ var DeltaOut = DeltaIn.multiply(this.stepResponse((this._buffer.length - 1 + Frac) * this._stepTime));
+
+ Output = Output.add(DeltaOut);
+
+ for (var C=this._buffer.length - 2; C>=0; C--)
+ {
+ DeltaIn = this._buffer[C].subtract(this._buffer[C + 1]);
+
+ DeltaOut = DeltaIn.multiply(this.stepResponse((C + Frac) * this._stepTime));
+
+ Output = Output.add(DeltaOut);
+ }
+
+ if ( !Output.equals(this._value, this._eps) ) {
+ this._value.setValues(Output);
+
+ this.postMessage('value', this._value);
+ }
+ else {
+ this.postMessage('isActive', false);
+ }
+
+ return this._vf.isActive;
+ },
+
+ updateBuffer: function(now)
+ {
+ var Frac = (now - this._bufferEndTime) / this._stepTime;
+ var C;
+ var NumToShift;
+ var Alpha;
+ // is normally < 1. When it has grown to be larger than 1, we have to shift the array because the step response
+ // of the oldest entry has already reached its destination, and it's time for a newer entry.
+ // In the case of a very low frame rate, or a very short _stepTime we may need to shift by more than one entry.
+
+ if (Frac >= 1)
+ {
+ NumToShift = Math.floor(Frac);
+ Frac -= NumToShift;
+
+ if( NumToShift < this._buffer.length)
+ {
+ // normal case
+ this._previousValue = x3dom.fields.SFVec3f.copy(this._buffer[this._buffer.length - NumToShift]);
+
+ for (C=this._buffer.length - 1; C>=NumToShift; C--) {
+ this._buffer[C] = x3dom.fields.SFVec3f.copy(this._buffer[C - NumToShift]);
+ }
+
+ for (C=0; C<NumToShift; C++)
+ {
+ // Hmm, we have a destination value, but don't know how it has
+ // reached the current state.
+ // Therefore we do a linear interpolation from the latest value in the buffer to destination.
+ Alpha = C / NumToShift;
+
+ this._buffer[C] = this._buffer[NumToShift].multiply(Alpha).add(this._vf.destination.multiply((1 - Alpha)));
+ }
+ }
+ else
+ {
+ // degenerated case:
+ //
+ // We have a _VERY_ low frame rate...
+ // we can only guess how we should fill the array.
+ // Maybe we could write part of a linear interpolation
+ // from this._buffer[0] to destination, that goes from this._bufferEndTime to now
+ // (possibly only the end of the interpolation is to be written),
+ // but if we reach here we are in a very degenerate case...
+ // Thus we just write destination to the buffer.
+
+ this._previousValue = x3dom.fields.SFVec3f.copy((NumToShift == this._buffer.length) ?
+ this._buffer[0] : this._vf.destination);
+
+ for (C= 0; C<this._buffer.length; C++) {
+ this._buffer[C] = x3dom.fields.SFVec3f.copy(this._vf.destination);
+ }
+ }
+
+ this._bufferEndTime += NumToShift * this._stepTime;
+ }
+
+ return Frac;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PositionChaser2D ### */
+x3dom.registerNodeType(
+ "PositionChaser2D",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DChaserNode,
+
+ /**
+ * Constructor for PositionChaser2D
+ * @constructs x3dom.nodeTypes.PositionChaser2D
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChaserNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PositionChaser2D animates transitions for 2D vectors. Whenever its destination field receives
+ * a 2D vector it creates a transition from its current 2D vector value to the newly set value. It creates a
+ * smooth transition that ends duration seconds after the last 2D vector has been received.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PositionChaser2D.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain 2D vector value is to be created right after the scene is loaded or right after the
+ * PositionChaser2D node is created dynamically.
+ * @var {x3dom.fields.SFVec2f} initialDestination
+ * @memberof x3dom.nodeTypes.PositionChaser2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'initialDestination', 0, 0);
+
+ /**
+ * The field initialValue can be used to set the initial initial value.
+ * @var {x3dom.fields.SFVec2f} initialValue
+ * @memberof x3dom.nodeTypes.PositionChaser2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'initialValue', 0, 0);
+
+
+ /**
+ * The current 2D position.
+ * @var {x3dom.fields.SFVec2f} value
+ * @memberof x3dom.nodeTypes.PositionChaser2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'value', 0, 0);
+
+ /**
+ * The target 2D position.
+ * @var {x3dom.fields.SFVec2f} destination
+ * @memberof x3dom.nodeTypes.PositionChaser2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'destination', 0, 0);
+
+ this._buffer = new x3dom.fields.MFVec2f();
+ this._previousValue = new x3dom.fields.SFVec2f(0, 0);
+ this._value = new x3dom.fields.SFVec2f(0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName.indexOf("destination") >= 0)
+ {
+ this.initialize();
+ this.updateBuffer(this._currTime);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this.initialize();
+
+ this._previousValue.setValues(this._vf.value);
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C].setValues(this._vf.value);
+ }
+
+ this.postMessage('value', this._vf.value);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ /** The following handler code is copy & paste from PositionChaser
+ */
+ initialize: function()
+ {
+ if (!this._initDone)
+ {
+ this._initDone = true;
+
+ this._vf.destination = x3dom.fields.SFVec2f.copy(this._vf.initialDestination);
+
+ this._buffer.length = this._numSupports;
+
+ this._buffer[0] = x3dom.fields.SFVec2f.copy(this._vf.initialDestination);
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C] = x3dom.fields.SFVec2f.copy(this._vf.initialValue);
+ }
+
+ this._previousValue = x3dom.fields.SFVec2f.copy(this._vf.initialValue);
+
+ this._stepTime = this._vf.duration / this._numSupports;
+
+ var active = !this._buffer[0].equals(this._buffer[1], this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ }
+ },
+
+ tick: function(now)
+ {
+ this.initialize();
+ this._currTime = now;
+
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._bufferEndTime)
+ {
+ this._bufferEndTime = now;
+
+ this._value = x3dom.fields.SFVec2f.copy(this._vf.initialValue);
+
+ this.postMessage('value', this._value);
+
+ return true;
+ }
+
+ var Frac = this.updateBuffer(now);
+
+ var Output = x3dom.fields.SFVec2f.copy(this._previousValue);
+
+ var DeltaIn = this._buffer[this._buffer.length - 1].subtract(this._previousValue);
+
+ var DeltaOut = DeltaIn.multiply(this.stepResponse((this._buffer.length - 1 + Frac) * this._stepTime));
+
+ Output = Output.add(DeltaOut);
+
+ for (var C=this._buffer.length - 2; C>=0; C--)
+ {
+ DeltaIn = this._buffer[C].subtract(this._buffer[C + 1]);
+
+ DeltaOut = DeltaIn.multiply(this.stepResponse((C + Frac) * this._stepTime));
+
+ Output = Output.add(DeltaOut);
+ }
+
+ if ( !Output.equals(this._value, this._eps) ) {
+ this._value.setValues(Output);
+
+ this.postMessage('value', this._value);
+ }
+ else {
+ this.postMessage('isActive', false);
+ }
+
+ return this._vf.isActive;
+ },
+
+ updateBuffer: function(now)
+ {
+ var Frac = (now - this._bufferEndTime) / this._stepTime;
+ var C;
+ var NumToShift;
+ var Alpha;
+
+ if (Frac >= 1)
+ {
+ NumToShift = Math.floor(Frac);
+ Frac -= NumToShift;
+
+ if( NumToShift < this._buffer.length)
+ {
+ this._previousValue = x3dom.fields.SFVec2f.copy(this._buffer[this._buffer.length - NumToShift]);
+
+ for (C=this._buffer.length - 1; C>=NumToShift; C--) {
+ this._buffer[C]= x3dom.fields.SFVec2f.copy(this._buffer[C - NumToShift]);
+ }
+
+ for (C=0; C<NumToShift; C++)
+ {
+ Alpha = C / NumToShift;
+
+ this._buffer[C] = this._buffer[NumToShift].multiply(Alpha).add(this._vf.destination.multiply((1 - Alpha)));
+ }
+ }
+ else
+ {
+ this._previousValue = x3dom.fields.SFVec2f.copy((NumToShift == this._buffer.length) ?
+ this._buffer[0] : this._vf.destination);
+
+ for (C= 0; C<this._buffer.length; C++) {
+ this._buffer[C] = x3dom.fields.SFVec2f.copy(this._vf.destination);
+ }
+ }
+
+ this._bufferEndTime += NumToShift * this._stepTime;
+ }
+
+ return Frac;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PositionDamper ### */
+x3dom.registerNodeType(
+ "PositionDamper",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DDamperNode,
+
+ /**
+ * Constructor for PositionDamper
+ * @constructs x3dom.nodeTypes.PositionDamper
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDamperNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PositionDamper animates transitions for 3D vectors. If its value field is routed to a
+ * translation field of a Transform node that contains an object, then, whenever the destination field receives
+ * a 3D position, the PositionDamper node moves the object from its current position to the newly set position.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PositionDamper.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialvalue unless a transition to a
+ * certain position is to be created right after the scene is loaded or right after the PositionDamper node
+ * is created dynamically.
+ * @var {x3dom.fields.SFVec3f} initialDestination
+ * @memberof x3dom.nodeTypes.PositionDamper
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'initialDestination', 0, 0, 0);
+
+ /**
+ * The field initialValue can be used to set the initial position of the object.
+ * @var {x3dom.fields.SFVec3f} initialValue
+ * @memberof x3dom.nodeTypes.PositionDamper
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'initialValue', 0, 0, 0);
+
+
+ /**
+ * The current position value.
+ * @var {x3dom.fields.SFVec3f} value
+ * @memberof x3dom.nodeTypes.PositionDamper
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'value', 0, 0, 0);
+
+ /**
+ * The target position value.
+ * @var {x3dom.fields.SFVec3f} destination
+ * @memberof x3dom.nodeTypes.PositionDamper
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'destination', 0, 0, 0);
+
+ this._value0 = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._value1 = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._value2 = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._value3 = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._value4 = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._value5 = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName === "tolerance")
+ {
+ this._eps = this._vf.tolerance < 0 ? 0.001 : this._vf.tolerance;
+ }
+ else if (fieldName.indexOf("destination") >= 0)
+ {
+ if ( !this._value0.equals(this._vf.destination, this._eps) ) {
+ this._value0 = this._vf.destination;
+
+ if (!this._vf.isActive) {
+ //this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this._value1.setValues(this._vf.value);
+ this._value2.setValues(this._vf.value);
+ this._value3.setValues(this._vf.value);
+ this._value4.setValues(this._vf.value);
+ this._value5.setValues(this._vf.value);
+ this._lastTick = 0;
+
+ this.postMessage('value', this._value5);
+
+ if (!this._vf.isActive) {
+ this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ initialize: function()
+ {
+ this._value0.setValues(this._vf.initialDestination);
+ this._value1.setValues(this._vf.initialValue);
+ this._value2.setValues(this._vf.initialValue);
+ this._value3.setValues(this._vf.initialValue);
+ this._value4.setValues(this._vf.initialValue);
+ this._value5.setValues(this._vf.initialValue);
+ this._lastTick = 0;
+
+ var active = !this._value0.equals(this._value1, this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ },
+
+ tick: function(now)
+ {
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._lastTick)
+ {
+ this._lastTick = now;
+ return false;
+ }
+
+ var delta = now - this._lastTick;
+
+ var alpha = Math.exp(-delta / this._vf.tau);
+
+ this._value1 = this._vf.order > 0 && this._vf.tau ?
+ this._value0.add(this._value1.subtract(this._value0).multiply(alpha)) :
+ new x3dom.fields.SFVec3f(this._value0.x, this._value0.y, this._value0.z);
+
+ this._value2 = this._vf.order > 1 && this._vf.tau ?
+ this._value1.add(this._value2.subtract(this._value1).multiply(alpha)) :
+ new x3dom.fields.SFVec3f(this._value1.x, this._value1.y, this._value1.z);
+
+ this._value3 = this._vf.order > 2 && this._vf.tau ?
+ this._value2.add(this._value3.subtract(this._value2).multiply(alpha)) :
+ new x3dom.fields.SFVec3f(this._value2.x, this._value2.y, this._value2.z);
+
+ this._value4 = this._vf.order > 3 && this._vf.tau ?
+ this._value3.add(this._value4.subtract(this._value3).multiply(alpha)) :
+ new x3dom.fields.SFVec3f(this._value3.x, this._value3.y, this._value3.z);
+
+ this._value5 = this._vf.order > 4 && this._vf.tau ?
+ this._value4.add(this._value5.subtract(this._value4).multiply(alpha)) :
+ new x3dom.fields.SFVec3f(this._value4.x, this._value4.y, this._value4.z);
+
+ var dist = this._value1.subtract(this._value0).length();
+
+ if (this._vf.order > 1)
+ {
+ var dist2 = this._value2.subtract(this._value1).length();
+ if (dist2 > dist) {dist = dist2;}
+ }
+ if (this._vf.order > 2)
+ {
+ var dist3 = this._value3.subtract(this._value2).length();
+ if (dist3 > dist) {dist = dist3;}
+ }
+ if (this._vf.order > 3)
+ {
+ var dist4 = this._value4.subtract(this._value3).length();
+ if (dist4 > dist) {dist = dist4;}
+ }
+ if (this._vf.order > 4)
+ {
+ var dist5 = this._value5.subtract(this._value4).length();
+ if (dist5 > dist) {dist = dist5;}
+ }
+
+ if (dist <= this._eps)
+ {
+ this._value1.setValues(this._value0);
+ this._value2.setValues(this._value0);
+ this._value3.setValues(this._value0);
+ this._value4.setValues(this._value0);
+ this._value5.setValues(this._value0);
+
+ this.postMessage('value', this._value0);
+ this.postMessage('isActive', false);
+
+ this._lastTick = 0;
+
+ return false;
+ }
+
+ this.postMessage('value', this._value5);
+
+ this._lastTick = now;
+
+ return true;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PositionDamper2D ### */
+x3dom.registerNodeType(
+ "PositionDamper2D",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DDamperNode,
+
+ /**
+ * Constructor for PositionDamper2D
+ * @constructs x3dom.nodeTypes.PositionDamper2D
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDamperNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PositionDamper2D animates transitions for 2D vectors. Whenever the destination field receives
+ * a 2D vector, it creates a transition from its current 2D vector value to the newly set value.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PositionDamper2D.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain 2D vector value is to be created right after the scene is loaded or right after the
+ * PositinChaser2D node is created dynamically.
+ * @var {x3dom.fields.SFVec2f} initialDestination
+ * @memberof x3dom.nodeTypes.PositionDamper2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'initialDestination', 0, 0);
+
+ /**
+ * The field initialValue can be used to set the initial initial value.
+ * @var {x3dom.fields.SFVec2f} initialValue
+ * @memberof x3dom.nodeTypes.PositionDamper2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'initialValue', 0, 0);
+
+
+ /**
+ * The current 2D position value.
+ * @var {x3dom.fields.SFVec2f} value
+ * @memberof x3dom.nodeTypes.PositionDamper2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'value', 0, 0);
+
+ /**
+ * The target 2D position value.
+ * @var {x3dom.fields.SFVec2f} destination
+ * @memberof x3dom.nodeTypes.PositionDamper2D
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'destination', 0, 0);
+
+ this._value0 = new x3dom.fields.SFVec2f(0, 0);
+ this._value1 = new x3dom.fields.SFVec2f(0, 0);
+ this._value2 = new x3dom.fields.SFVec2f(0, 0);
+ this._value3 = new x3dom.fields.SFVec2f(0, 0);
+ this._value4 = new x3dom.fields.SFVec2f(0, 0);
+ this._value5 = new x3dom.fields.SFVec2f(0, 0);
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName === "tolerance")
+ {
+ this._eps = this._vf.tolerance < 0 ? 0.001 : this._vf.tolerance;
+ }
+ else if (fieldName.indexOf("destination") >= 0)
+ {
+ if ( !this._value0.equals(this._vf.destination, this._eps) ) {
+ this._value0 = this._vf.destination;
+
+ if (!this._vf.isActive) {
+ //this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this._value1.setValues(this._vf.value);
+ this._value2.setValues(this._vf.value);
+ this._value3.setValues(this._vf.value);
+ this._value4.setValues(this._vf.value);
+ this._value5.setValues(this._vf.value);
+ this._lastTick = 0;
+
+ this.postMessage('value', this._value5);
+
+ if (!this._vf.isActive) {
+ this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ initialize: function()
+ {
+ this._value0.setValues(this._vf.initialDestination);
+ this._value1.setValues(this._vf.initialValue);
+ this._value2.setValues(this._vf.initialValue);
+ this._value3.setValues(this._vf.initialValue);
+ this._value4.setValues(this._vf.initialValue);
+ this._value5.setValues(this._vf.initialValue);
+ this._lastTick = 0;
+
+ var active = !this._value0.equals(this._value1, this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ },
+
+ tick: function(now)
+ {
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._lastTick)
+ {
+ this._lastTick = now;
+ return false;
+ }
+
+ var delta = now - this._lastTick;
+
+ var alpha = Math.exp(-delta / this._vf.tau);
+
+ this._value1 = this._vf.order > 0 && this._vf.tau ?
+ this._value0.add(this._value1.subtract(this._value0).multiply(alpha)) :
+ new x3dom.fields.SFVec2f(this._value0.x, this._value0.y, this._value0.z);
+
+ this._value2 = this._vf.order > 1 && this._vf.tau ?
+ this._value1.add(this._value2.subtract(this._value1).multiply(alpha)) :
+ new x3dom.fields.SFVec2f(this._value1.x, this._value1.y, this._value1.z);
+
+ this._value3 = this._vf.order > 2 && this._vf.tau ?
+ this._value2.add(this._value3.subtract(this._value2).multiply(alpha)) :
+ new x3dom.fields.SFVec2f(this._value2.x, this._value2.y, this._value2.z);
+
+ this._value4 = this._vf.order > 3 && this._vf.tau ?
+ this._value3.add(this._value4.subtract(this._value3).multiply(alpha)) :
+ new x3dom.fields.SFVec2f(this._value3.x, this._value3.y, this._value3.z);
+
+ this._value5 = this._vf.order > 4 && this._vf.tau ?
+ this._value4.add(this._value5.subtract(this._value4).multiply(alpha)) :
+ new x3dom.fields.SFVec2f(this._value4.x, this._value4.y, this._value4.z);
+
+ var dist = this._value1.subtract(this._value0).length();
+
+ if (this._vf.order > 1)
+ {
+ var dist2 = this._value2.subtract(this._value1).length();
+ if (dist2 > dist) {dist = dist2;}
+ }
+ if (this._vf.order > 2)
+ {
+ var dist3 = this._value3.subtract(this._value2).length();
+ if (dist3 > dist) {dist = dist3;}
+ }
+ if (this._vf.order > 3)
+ {
+ var dist4 = this._value4.subtract(this._value3).length();
+ if (dist4 > dist) {dist = dist4;}
+ }
+ if (this._vf.order > 4)
+ {
+ var dist5 = this._value5.subtract(this._value4).length();
+ if (dist5 > dist) {dist = dist5;}
+ }
+
+ if (dist <= this._eps)
+ {
+ this._value1.setValues(this._value0);
+ this._value2.setValues(this._value0);
+ this._value3.setValues(this._value0);
+ this._value4.setValues(this._value0);
+ this._value5.setValues(this._value0);
+
+ this.postMessage('value', this._value0);
+ this.postMessage('isActive', false);
+
+ this._lastTick = 0;
+
+ return false;
+ }
+
+ this.postMessage('value', this._value5);
+
+ this._lastTick = now;
+
+ return true;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ScalarChaser ### */
+x3dom.registerNodeType(
+ "ScalarChaser",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DChaserNode,
+
+ /**
+ * Constructor for ScalarChaser
+ * @constructs x3dom.nodeTypes.ScalarChaser
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChaserNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ScalarChaser animates transitions for single float values. Whenever the destination field
+ * receives a floating point number, it creates a transition from its current value to the newly set number.
+ * It creates a smooth transition that ends duration seconds after the last number has been received.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ScalarChaser.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain value is to be created right after the scene is loaded or right after the ScalarChaser node is
+ * created dynamically.
+ * @var {x3dom.fields.SFFloat} initialDestination
+ * @memberof x3dom.nodeTypes.ScalarChaser
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'initialDestination', 0);
+
+ /**
+ * The field initialValue can be used to set the initial initial value.
+ * @var {x3dom.fields.SFFloat} initialValue
+ * @memberof x3dom.nodeTypes.ScalarChaser
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'initialValue', 0);
+
+
+ /**
+ * The current value.
+ * @var {x3dom.fields.SFFloat} value
+ * @memberof x3dom.nodeTypes.ScalarChaser
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'value', 0);
+
+ /**
+ * The target value.
+ * @var {x3dom.fields.SFFloat} destination
+ * @memberof x3dom.nodeTypes.ScalarChaser
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'destination', 0);
+
+ this._buffer = [];
+ this._previousValue = 0;
+ this._value = 0;
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName.indexOf("destination") >= 0)
+ {
+ this.initialize();
+ this.updateBuffer(this._currTime);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this.initialize();
+
+ this._previousValue = this._vf.value;
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C] = this._vf.value;
+ }
+
+ this.postMessage('value', this._vf.value);
+
+ if (!this._vf.isActive) {
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ initialize: function()
+ {
+ if (!this._initDone)
+ {
+ this._initDone = true;
+
+ this._vf.destination = this._vf.initialDestination;
+
+ this._buffer.length = this._numSupports;
+
+ this._buffer[0] = this._vf.initialDestination;
+ for (var C=1; C<this._buffer.length; C++) {
+ this._buffer[C] = this._vf.initialValue;
+ }
+
+ this._previousValue = this._vf.initialValue;
+
+ this._stepTime = this._vf.duration / this._numSupports;
+
+ var active = (Math.abs(this._buffer[0] - this._buffer[1]) > this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ }
+ },
+
+ tick: function(now)
+ {
+ this.initialize();
+ this._currTime = now;
+
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._bufferEndTime)
+ {
+ this._bufferEndTime = now;
+
+ this._value = this._vf.initialValue;
+
+ this.postMessage('value', this._value);
+
+ return true;
+ }
+
+ var Frac = this.updateBuffer(now);
+
+ var Output = this._previousValue;
+
+ var DeltaIn = this._buffer[this._buffer.length - 1] - this._previousValue;
+
+ var DeltaOut = DeltaIn * (this.stepResponse((this._buffer.length - 1 + Frac) * this._stepTime));
+
+ Output = Output + DeltaOut;
+
+ for (var C=this._buffer.length - 2; C>=0; C--)
+ {
+ DeltaIn = this._buffer[C] - this._buffer[C + 1];
+
+ DeltaOut = DeltaIn * (this.stepResponse((C + Frac) * this._stepTime));
+
+ Output = Output + DeltaOut;
+ }
+
+ if (Math.abs(Output - this._value) > this._eps) {
+ this._value = Output;
+
+ this.postMessage('value', this._value);
+ }
+ else {
+ this.postMessage('isActive', false);
+ }
+
+ return this._vf.isActive;
+ },
+
+ updateBuffer: function(now)
+ {
+ var Frac = (now - this._bufferEndTime) / this._stepTime;
+ var C;
+ var NumToShift;
+ var Alpha;
+
+ if (Frac >= 1)
+ {
+ NumToShift = Math.floor(Frac);
+ Frac -= NumToShift;
+
+ if (NumToShift < this._buffer.length)
+ {
+ this._previousValue = this._buffer[this._buffer.length - NumToShift];
+
+ for (C=this._buffer.length - 1; C>=NumToShift; C--) {
+ this._buffer[C] = this._buffer[C - NumToShift];
+ }
+
+ for (C=0; C<NumToShift; C++)
+ {
+ Alpha = C / NumToShift;
+
+ this._buffer[C] = this._buffer[NumToShift] * Alpha + this._vf.destination * (1 - Alpha);
+ }
+ }
+ else
+ {
+ this._previousValue = (NumToShift == this._buffer.length) ? this._buffer[0] : this._vf.destination;
+
+ for (C = 0; C<this._buffer.length; C++) {
+ this._buffer[C] = this._vf.destination;
+ }
+ }
+
+ this._bufferEndTime += NumToShift * this._stepTime;
+ }
+
+ return Frac;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ScalarDamper ### */
+x3dom.registerNodeType(
+ "ScalarDamper",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DDamperNode,
+
+ /**
+ * Constructor for ScalarDamper
+ * @constructs x3dom.nodeTypes.ScalarDamper
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDamperNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ScalarDamper animates transitions for single float values. If the value field is routed to a
+ * transparency field of a Material node, then, whenever the destination field receives a single float value,
+ * the ScalarDamper node creates a transition from its current value to the newly set value.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ScalarDamper.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain value is to be created right after the scene is loaded or right after the ScalarDamper node is
+ * created dynamically.
+ * @var {x3dom.fields.SFFloat} initialDestination
+ * @memberof x3dom.nodeTypes.ScalarDamper
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'initialDestination', 0);
+
+ /**
+ * The field initialValue can be used to set the initial value of the node.
+ * @var {x3dom.fields.SFFloat} initialValue
+ * @memberof x3dom.nodeTypes.ScalarDamper
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'initialValue', 0);
+
+
+ /**
+ * The current value.
+ * @var {x3dom.fields.SFFloat} value
+ * @memberof x3dom.nodeTypes.ScalarDamper
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'value', 0);
+
+ /**
+ * The target value.
+ * @var {x3dom.fields.SFFloat} destination
+ * @memberof x3dom.nodeTypes.ScalarDamper
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'destination', 0);
+
+ this._value0 = 0;
+ this._value1 = 0;
+ this._value2 = 0;
+ this._value3 = 0;
+ this._value4 = 0;
+ this._value5 = 0;
+
+ this.initialize();
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName === "tolerance")
+ {
+ this._eps = this._vf.tolerance < 0 ? 0.001 : this._vf.tolerance;
+ }
+ else if (fieldName.indexOf("destination") >= 0)
+ {
+ if (Math.abs(this._value0 - this._vf.destination) > this._eps) {
+ this._value0 = this._vf.destination;
+
+ if (!this._vf.isActive) {
+ //this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ }
+ else if (fieldName.indexOf("value") >= 0)
+ {
+ this._value1 = this._vf.value;
+ this._value2 = this._vf.value;
+ this._value3 = this._vf.value;
+ this._value4 = this._vf.value;
+ this._value5 = this._vf.value;
+ this._lastTick = 0;
+
+ this.postMessage('value', this._value5);
+
+ if (!this._vf.isActive) {
+ this._lastTick = 0;
+ this.postMessage('isActive', true);
+ }
+ }
+ },
+
+ initialize: function()
+ {
+ this._value0 = this._vf.initialDestination;
+ this._value1 = this._vf.initialValue;
+ this._value2 = this._vf.initialValue;
+ this._value3 = this._vf.initialValue;
+ this._value4 = this._vf.initialValue;
+ this._value5 = this._vf.initialValue;
+ this._lastTick = 0;
+
+ var active = (Math.abs(this._value0 - this._value1) > this._eps);
+ if (this._vf.isActive !== active) {
+ this.postMessage('isActive', active);
+ }
+ },
+
+ tick: function(now)
+ {
+ //if (!this._vf.isActive)
+ // return false;
+
+ if (!this._lastTick)
+ {
+ this._lastTick = now;
+ return false;
+ }
+
+ var delta = now - this._lastTick;
+
+ var alpha = Math.exp(-delta / this._vf.tau);
+
+ this._value1 = this._vf.order > 0 && this._vf.tau ?
+ this._value0 + alpha * (this._value1 - this._value0) : this._value0;
+
+ this._value2 = this._vf.order > 1 && this._vf.tau ?
+ this._value1 + alpha * (this._value2 - this._value1) : this._value1;
+
+ this._value3 = this._vf.order > 2 && this._vf.tau ?
+ this._value2 + alpha * (this._value3 - this._value2) : this._value2;
+
+ this._value4 = this._vf.order > 3 && this._vf.tau ?
+ this._value3 + alpha * (this._value4 - this._value3) : this._value3;
+
+ this._value5 = this._vf.order > 4 && this._vf.tau ?
+ this._value4 + alpha * (this._value5 - this._value4) : this._value4;
+
+ var dist = Math.abs(this._value1 - this._value0);
+
+ if (this._vf.order > 1)
+ {
+ var dist2 = Math.abs(this._value2 - this._value1);
+ if (dist2 > dist) {dist = dist2;}
+ }
+ if (this._vf.order > 2)
+ {
+ var dist3 = Math.abs(this._value3 - this._value2);
+ if (dist3 > dist) {dist = dist3;}
+ }
+ if (this._vf.order > 3)
+ {
+ var dist4 = Math.abs(this._value4 - this._value3);
+ if (dist4 > dist) {dist = dist4;}
+ }
+ if (this._vf.order > 4)
+ {
+ var dist5 = Math.abs(this._value5 - this._value4);
+ if (dist5 > dist) {dist = dist5;}
+ }
+
+ if (dist <= this._eps)
+ {
+ this._value1 = this._value0;
+ this._value2 = this._value0;
+ this._value3 = this._value0;
+ this._value4 = this._value0;
+ this._value5 = this._value0;
+
+ this.postMessage('value', this._value0);
+ this.postMessage('isActive', false);
+
+ this._lastTick = 0;
+
+ return false;
+ }
+
+ this.postMessage('value', this._value5);
+
+ this._lastTick = now;
+
+ return true;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### CoordinateDamper ### */
+x3dom.registerNodeType(
+ "CoordinateDamper",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DDamperNode,
+
+ /**
+ * Constructor for CoordinateDamper
+ * @constructs x3dom.nodeTypes.CoordinateDamper
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDamperNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The CoordinateChaser animates transitions for array of 3D vectors (e.g., the coordinates of a
+ * mesh). Whenever it receives an array of 3D vectors, the value_changed creates a transition from its
+ * current value to the newly set number. It creates a smooth transition that ends duration seconds after the
+ * last number has been received.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.CoordinateDamper.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain value is to be created right after the scene is loaded or right after the CoordinateChaser node
+ * is created dynamically.
+ * @var {x3dom.fields.MFVec3f} initialDestination
+ * @memberof x3dom.nodeTypes.CoordinateDamper
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'initialDestination', []);
+
+ /**
+ * The field initialValue can be used to set the initial value.
+ * @var {x3dom.fields.MFVec3f} initialValue
+ * @memberof x3dom.nodeTypes.CoordinateDamper
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'initialValue', []);
+
+
+ /**
+ * The current coordinate value
+ * @var {x3dom.fields.MFVec3f} value
+ * @memberof x3dom.nodeTypes.CoordinateDamper
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'value', []);
+
+ /**
+ * The target coordinate value
+ * @var {x3dom.fields.MFVec3f} destination
+ * @memberof x3dom.nodeTypes.CoordinateDamper
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'destination', []);
+
+ x3dom.debug.logWarning("CoordinateDamper NYI");
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TexCoordDamper2D ### */
+x3dom.registerNodeType(
+ "TexCoordDamper2D",
+ "Followers",
+ defineClass(x3dom.nodeTypes.X3DDamperNode,
+
+ /**
+ * Constructor for TexCoordDamper2D
+ * @constructs x3dom.nodeTypes.TexCoordDamper2D
+ * @x3d 3.3
+ * @component Followers
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDamperNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The TexCoordDamper2D node animates transitions for an array of 2D vectors (e.g., the texture
+ * coordinates of a mesh). Whenever the destination field receives an array of 2D vectors, value begins
+ * sending an array of the same length, where each element moves from its current value towards the value at
+ * the same position in the array received.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TexCoordDamper2D.superClass.call(this, ctx);
+
+
+ /**
+ * The field initialDestination should be set to the same value than initialValue unless a transition to a
+ * certain 2D vector value is to be created right after the scene is loaded or right after the
+ * CoordinateDamper node is created dynamically.
+ * @var {x3dom.fields.MFVec2f} initialDestination
+ * @memberof x3dom.nodeTypes.TexCoordDamper2D
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec2f(ctx, 'initialDestination', []);
+
+ /**
+ * The field initialValue can be used to set the initial value of value_changed.
+ * @var {x3dom.fields.MFVec2f} initialValue
+ * @memberof x3dom.nodeTypes.TexCoordDamper2D
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec2f(ctx, 'initialValue', []);
+
+
+ /**
+ * The current value.
+ * @var {x3dom.fields.MFVec2f} value
+ * @memberof x3dom.nodeTypes.TexCoordDamper2D
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec2f(ctx, 'value', []);
+
+ /**
+ * The target value.
+ * @var {x3dom.fields.MFVec2f} destination
+ * @memberof x3dom.nodeTypes.TexCoordDamper2D
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec2f(ctx, 'destination', []);
+
+ x3dom.debug.logWarning("TexCoordDamper2D NYI");
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### X3DInterpolatorNode ###
+x3dom.registerNodeType(
+ "X3DInterpolatorNode",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DInterpolatorNode
+ * @constructs x3dom.nodeTypes.X3DInterpolatorNode
+ * @x3d 3.3
+ * @component Interpolation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The abstract node X3DInterpolatorNode forms the basis for all types of interpolators.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DInterpolatorNode.superClass.call(this, ctx);
+
+
+ /**
+ * The key field contains the list of key times, the keyValue field contains values for the target field, one complete set of values for each key.
+ * Interpolator nodes containing no keys in the key field shall not produce any events.
+ * However, an input event that replaces an empty key field with one that contains keys will cause the interpolator node to produce events the next time that a set_fraction event is received.
+ * @var {x3dom.fields.MFFloat} key
+ * @memberof x3dom.nodeTypes.X3DInterpolatorNode
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'key', []);
+
+ /**
+ * The set_fraction inputOnly field receives an SFFloat event and causes the interpolator node function to evaluate, resulting in a value_changed output event of the specified type with the same timestamp as the set_fraction event.
+ * @var {x3dom.fields.SFFloat} set_fraction
+ * @memberof x3dom.nodeTypes.X3DInterpolatorNode
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'set_fraction', 0);
+
+ },
+ {
+ linearInterp: function (time, interp) {
+ if (time <= this._vf.key[0])
+ return this._vf.keyValue[0];
+
+ else if (time >= this._vf.key[this._vf.key.length-1])
+ return this._vf.keyValue[this._vf.key.length-1];
+
+ for (var i = 0; i < this._vf.key.length-1; ++i) {
+ if ((this._vf.key[i] < time) && (time <= this._vf.key[i+1]))
+ return interp( this._vf.keyValue[i], this._vf.keyValue[i+1],
+ (time - this._vf.key[i]) / (this._vf.key[i+1] - this._vf.key[i]) );
+ }
+ return this._vf.keyValue[0];
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### OrientationInterpolator ###
+x3dom.registerNodeType(
+ "OrientationInterpolator",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DInterpolatorNode,
+
+ /**
+ * Constructor for OrientationInterpolator
+ * @constructs x3dom.nodeTypes.OrientationInterpolator
+ * @x3d 3.3
+ * @component Interpolation
+ * @status full
+ * @extends x3dom.nodeTypes.X3DInterpolatorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The OrientationInterpolator node interpolates among a list of rotation values specified in the keyValue field to produce an SFRotation value_changed event.
+ * These rotations are absolute in object space and therefore are not cumulative.
+ * The keyValue field shall contain exactly as many rotations as there are key frames in the key field.
+ * An orientation represents the final position of an object after a rotation has been applied.
+ * An OrientationInterpolator interpolates between two orientations by computing the shortest path on the unit sphere between the two orientations.
+ * The interpolation is linear in arc length along this path. The results are undefined if the two orientations are diagonally opposite.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.OrientationInterpolator.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the set of data points, that are used for interpolation.
+ * If two consecutive keyValue values exist such that the arc length between them is greater than π, the interpolation will take place on the arc complement.
+ * For example, the interpolation between the orientations (0, 1, 0, 0) and (0, 1, 0, 5.0) is equivalent to the rotation between the orientations (0, 1, 0, 2Ï€) and (0, 1, 0, 5.0).
+ * @var {x3dom.fields.MFRotation} keyValue
+ * @memberof x3dom.nodeTypes.OrientationInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFRotation(ctx, 'keyValue', []);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if(fieldName === "set_fraction")
+ {
+ var value = this.linearInterp(this._vf.set_fraction, function (a, b, t) {
+ return a.slerp(b, t);
+ });
+ this.postMessage('value_changed', value);
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### PositionInterpolator ###
+x3dom.registerNodeType(
+ "PositionInterpolator",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DInterpolatorNode,
+
+ /**
+ * Constructor for PositionInterpolator
+ * @constructs x3dom.nodeTypes.PositionInterpolator
+ * @x3d 3.3
+ * @component Interpolation
+ * @status full
+ * @extends x3dom.nodeTypes.X3DInterpolatorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PositionInterpolator node linearly interpolates among a list of 3D vectors to produce an SFVec3f value_changed event. The keyValue field shall contain exactly as many values as in the key field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PositionInterpolator.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the set of data points, that are used for interpolation.
+ * @var {x3dom.fields.MFVec3f} keyValue
+ * @memberof x3dom.nodeTypes.PositionInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'keyValue', []);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if(fieldName === "set_fraction")
+ {
+ var value = this.linearInterp(this._vf.set_fraction, function (a, b, t) {
+ return a.multiply(1.0-t).add(b.multiply(t));
+ });
+
+ this.postMessage('value_changed', value);
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### NormalInterpolator ###
+x3dom.registerNodeType(
+ "NormalInterpolator",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DInterpolatorNode,
+
+ /**
+ * Constructor for NormalInterpolator
+ * @constructs x3dom.nodeTypes.NormalInterpolator
+ * @x3d 3.3
+ * @component Interpolation
+ * @status full
+ * @extends x3dom.nodeTypes.X3DInterpolatorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The NormalInterpolator node interpolates among a list of normal vector sets specified by the keyValue field to produce an MFVec3f value_changed event.
+ * The output vector, value_changed, shall be a set of normalized vectors.
+ * Values in the keyValue field shall be of unit length.
+ * The number of normals in the keyValue field shall be an integer multiple of the number of key frames in the key field.
+ * That integer multiple defines how many normals will be contained in the value_changed events.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.NormalInterpolator.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the set of data points, that are used for interpolation.
+ * Values in the keyValue field shall be of unit length.
+ * @var {x3dom.fields.MFVec3f} keyValue
+ * @memberof x3dom.nodeTypes.NormalInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'keyValue', []);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if(fieldName === "set_fraction")
+ {
+ var value = this.linearInterp(this._vf.set_fraction, function (a, b, t) {
+ return a.multiply(1.0-t).add(b.multiply(t)).normalize();
+ });
+
+ this.postMessage('value_changed', value);
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### ColorInterpolator ###
+x3dom.registerNodeType(
+ "ColorInterpolator",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DInterpolatorNode,
+
+ /**
+ * Constructor for ColorInterpolator
+ * @constructs x3dom.nodeTypes.ColorInterpolator
+ * @x3d 3.3
+ * @component Interpolation
+ * @status full
+ * @extends x3dom.nodeTypes.X3DInterpolatorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ColorInterpolator node interpolates among a list of MFColor key values to produce an SFColor (RGB) value_changed event.
+ * The number of colours in the keyValue field shall be equal to the number of key frames in the key field.
+ * A linear interpolation using the value of set_fraction as input is performed in HSV space.
+ * The results are undefined when interpolating between two consecutive keys with complementary hues.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ColorInterpolator.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the set of data points, that are used for interpolation.
+ * @var {x3dom.fields.MFColor} keyValue
+ * @memberof x3dom.nodeTypes.ColorInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFColor(ctx, 'keyValue', []);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if(fieldName === "set_fraction")
+ {
+ // FIXME; perform color interpolation in HSV space
+ var value = this.linearInterp(this._vf.set_fraction, function (a, b, t) {
+ return a.multiply(1.0-t).add(b.multiply(t));
+ });
+
+ this.postMessage('value_changed', value);
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### ScalarInterpolator ###
+x3dom.registerNodeType(
+ "ScalarInterpolator",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DInterpolatorNode,
+
+ /**
+ * Constructor for ScalarInterpolator
+ * @constructs x3dom.nodeTypes.ScalarInterpolator
+ * @x3d 3.3
+ * @component Interpolation
+ * @status full
+ * @extends x3dom.nodeTypes.X3DInterpolatorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ScalarInterpolator node linearly interpolates among a list of SFFloat values to produce an SFFloat value_changed event.
+ * This interpolator is appropriate for any parameter defined using a single floating point value.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ScalarInterpolator.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the set of data points, that are used for interpolation.
+ * @var {x3dom.fields.MFFloat} keyValue
+ * @memberof x3dom.nodeTypes.ScalarInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'keyValue', []);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if(fieldName === "set_fraction")
+ {
+ var value = this.linearInterp(this._vf.set_fraction, function (a, b, t) {
+ return (1.0-t)*a + t*b;
+ });
+
+ this.postMessage('value_changed', value);
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### CoordinateInterpolator ###
+x3dom.registerNodeType(
+ "CoordinateInterpolator",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DInterpolatorNode,
+
+ /**
+ * Constructor for CoordinateInterpolator
+ * @constructs x3dom.nodeTypes.CoordinateInterpolator
+ * @x3d 3.3
+ * @component Interpolation
+ * @status full
+ * @extends x3dom.nodeTypes.X3DInterpolatorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The CoordinateInterpolator node linearly interpolates among a list of MFVec3f values to produce an MFVec3f value_changed event.
+ * The number of coordinates in the keyValue field shall be an integer multiple of the number of key frames in the key field.
+ * That integer multiple defines how many coordinates will be contained in the value_changed events.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.CoordinateInterpolator.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the set of data points, that are used for interpolation.
+ * @var {x3dom.fields.MFVec3f} keyValue
+ * @memberof x3dom.nodeTypes.CoordinateInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'keyValue', []);
+
+ if (ctx && ctx.xmlNode.hasAttribute('keyValue')) {
+ this._vf.keyValue = []; // FIXME!!!
+
+ var arr = x3dom.fields.MFVec3f.parse(ctx.xmlNode.getAttribute('keyValue'));
+ var key = this._vf.key.length > 0 ? this._vf.key.length : 1;
+ var len = arr.length / key;
+ for (var i=0; i<key; i++) {
+ var val = new x3dom.fields.MFVec3f();
+ for (var j=0; j<len; j++) {
+ val.push( arr[i*len+j] );
+ }
+ this._vf.keyValue.push(val);
+ }
+ }
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if(fieldName === "set_fraction")
+ {
+ var value = this.linearInterp(this._vf.set_fraction, function (a, b, t) {
+ var val = new x3dom.fields.MFVec3f();
+ for (var i=0; i<a.length; i++)
+ val.push(a[i].multiply(1.0-t).add(b[i].multiply(t)));
+
+ return val;
+ });
+
+ this.postMessage('value_changed', value);
+ }
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * Based on code originally provided by
+ * http://www.x3dom.org
+ *
+ * (C)2014 Toshiba Corporation, Japan.
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### SplinePositionInterpolator ###
+x3dom.registerNodeType(
+ "SplinePositionInterpolator",
+ "Interpolation",
+ defineClass(x3dom.nodeTypes.X3DInterpolatorNode,
+
+ /**
+ * Constructor for SplinePositionInterpolator
+ * @constructs x3dom.nodeTypes.SplinePositionInterpolator
+ * @x3d 3.3
+ * @component Interpolation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DInterpolatorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The SplinePositionInterpolator node non-linearly interpolates among a list of 3D vectors to produce an SFVec3f value_changed event. The keyValue, keyVelocity, and key fields shall each have the same number of values.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.SplinePositionInterpolator.superClass.call(this, ctx);
+
+ /**
+ * Defines the set of data points, that are used for interpolation.
+ * @var {x3dom.fields.MFVec3f} keyValue
+ * @memberof x3dom.nodeTypes.SplinePositionInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'keyValue', []);
+
+ /**
+ * Defines the set of velocity vectors, that are used for interpolation.
+ * @var {x3dom.fields.MFVec3f} keyVelocity
+ * @memberof x3dom.nodeTypes.SplinePositionInterpolator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'keyVelocity', []);
+
+ /**
+ * Specifies whether the interpolator should provide a closed loop, with continuous velocity vectors as the interpolator transitions from the last key to the first key.
+ * @var {x3dom.fields.SFBool} closed
+ * @memberof x3dom.nodeTypes.SplinePositionInterpolator
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'closed', false);
+
+ /**
+ * Specifies whether the velocity vectors are to be transformed into normalized tangency vectors.
+ * @var {x3dom.fields.SFBool} normalizeVelocity
+ * @memberof x3dom.nodeTypes.SplinePositionInterpolator
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'normalizeVelocity', false);
+
+ /******** Private variables and functions ***********/
+
+ /* dtot is the sum of the distance between all adjacent keys.
+ * dtot = SUM{i=0, i < n-1}(|vi - vi+1|)
+ */
+ this.dtot = 0.0;
+
+ /* Non-uniform interval adjusted velocity vectors
+ */
+ this.T0 = [];
+ this.T1 = [];
+
+ /* Checks sanity. Node is sane if (|key| == |key_value|) and (|key| == |key_velocity| or |key_velocity| == 0 or (|key_velocity| == 2 and |key| >= 2))
+ */
+ this.checkSanity = function() {
+ var sane = (this._vf.key.length == this._vf.keyValue.length) &&
+ ((this._vf.key.length == this._vf.keyVelocity.length) || (this._vf.keyVelocity.length == 2 && this._vf.key.length >= 2) || (this._vf.keyVelocity.length == 0));
+ if(!sane)
+ x3dom.debug.logWarning("SplinePositionInterpolator Node: 'key' , 'keyValue' and/or 'keyVelocity' fields have inappropriate sizes");
+ };
+
+ /* Calculate dtot (sum of distances between all adjacent keys)
+ */
+ this.calcDtot = function()
+ {
+ this.dtot = 0.0;
+ for(var i = 0; i < this._vf.key.length-1; i++)
+ {
+ this.dtot += Math.abs(this._vf.key[i] - this._vf.key[i+1]);
+ }
+ };
+
+ /* Calculate non-uniform interval adjusted velocity vectors
+ */
+ this.calcAdjustedKeyVelocity = function()
+ {
+ var i, Ti, F_plus_i, F_minus_i;
+ var N = this._vf.key.length;
+
+ // If velocities are defined at all the control points, ignore 'closed' field
+ if(this._vf.keyVelocity.length == N)
+ {
+ for(i = 0; i < N; i++)
+ {
+ Ti = this._vf.keyVelocity[i];
+
+ if(this._vf.normalizeVelocity)
+ Ti = Ti.multiply(this.dtot / Ti.length());
+
+ F_plus_i = (i == 0 || i == N-1) ? 1.0 : 2.0 * (this._vf.key[i] - this._vf.key[i-1]) / (this._vf.key[i+1] - this._vf.key[i-1]);
+ F_minus_i= (i == 0 || i == N-1) ? 1.0 : 2.0 * (this._vf.key[i+1] - this._vf.key[i]) / (this._vf.key[i+1] - this._vf.key[i-1]);
+
+ this.T0[i] = Ti.multiply(F_plus_i);
+ this.T1[i] = Ti.multiply(F_minus_i);
+ }
+ }
+ // if only first and last velocities are specified, ignore 'closed' field
+ else if(this._vf.keyVelocity.length == 2 && N > 2)
+ {
+ for(i = 0; i < N; i++)
+ {
+ if(i == 0)
+ Ti = this._vf.keyVelocity[0];
+ else if(i == N-1)
+ Ti = this._vf.keyVelocity[1];
+ else
+ Ti = this._vf.keyValue[i+1].subtract(this._vf.keyValue[i-1]).multiply(0.5);
+
+ if(this._vf.normalizeVelocity)
+ Ti = Ti.multiply(this.dtot / Ti.length());
+
+ F_plus_i = (i == 0 || i == N-1) ? 1.0 : 2.0 * (this._vf.key[i] - this._vf.key[i-1]) / (this._vf.key[i+1] - this._vf.key[i-1]);
+ F_minus_i= (i == 0 || i == N-1) ? 1.0 : 2.0 * (this._vf.key[i+1] - this._vf.key[i]) / (this._vf.key[i+1] - this._vf.key[i-1]);
+
+ this.T0[i] = Ti.multiply(F_plus_i);
+ this.T1[i] = Ti.multiply(F_minus_i);
+ }
+ }
+ // velocities are unspecified
+ else
+ {
+ // ignore closed if first and last keyValues are not equal
+ var closed = this._vf.closed && this._vf.keyValue[0].equals(this._vf.keyValue[N-1], 0.00001);
+
+ for(i = 0; i < N; i++)
+ {
+ if((i == 0 || i == N-1) && !closed)
+ {
+ this.T0[i] = new x3dom.fields.SFVec3f(0, 0, 0);
+ this.T1[i] = new x3dom.fields.SFVec3f(0, 0, 0);
+ continue;
+ }
+ else if((i == 0 || i == N-1) && closed)
+ {
+ Ti = this._vf.keyValue[1].subtract(this._vf.keyValue[N-2]).multiply(0.5);
+ if(i == 0) {
+ F_plus_i = 2.0 * (this._vf.key[0] - this._vf.key[N-2]) / (this._vf.key[1] - this._vf.key[N-2]);
+ F_minus_i= 2.0 * (this._vf.key[1] - this._vf.key[0]) / (this._vf.key[1] - this._vf.key[N-2]);
+ }
+ else {
+ F_plus_i = 2.0 * (this._vf.key[N-1] - this._vf.key[N-2]) / (this._vf.key[1] - this._vf.key[N-2]);
+ F_minus_i= 2.0 * (this._vf.key[1] - this._vf.key[N-1]) / (this._vf.key[1] - this._vf.key[N-2]);
+ }
+ F_plus_i = 2.0 * (this._vf.key[N-1] - this._vf.key[N-2]) / (this._vf.key[N-2] - this._vf.key[1]);
+ F_minus_i= 2.0 * (this._vf.key[1] - this._vf.key[0]) / (this._vf.key[N-2] - this._vf.key[1]);
+ }
+ else
+ {
+ Ti = this._vf.keyValue[i+1].subtract(this._vf.keyValue[i-1]).multiply(0.5);
+ F_plus_i = 2.0 * (this._vf.key[i] - this._vf.key[i-1]) / (this._vf.key[i+1] - this._vf.key[i-1]);
+ F_minus_i= 2.0 * (this._vf.key[i+1] - this._vf.key[i]) / (this._vf.key[i+1] - this._vf.key[i-1]);
+ }
+
+ this.T0[i] = Ti.multiply(F_plus_i);
+ this.T1[i] = Ti.multiply(F_minus_i);
+ }
+ }
+ };
+
+ this.checkSanity();
+ this.calcDtot();
+ this.calcAdjustedKeyVelocity();
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ switch(fieldName)
+ {
+ case 'key':
+ case 'keyValue':
+ case 'keyVelocity':
+ {
+ this.checkSanity();
+ this.calcDtot();
+ this.calcAdjustedKeyVelocity();
+ break;
+ }
+ case 'closed':
+ case 'normalizeVelocity':
+ {
+ this.calcAdjustedKeyVelocity();
+ break;
+ }
+ case 'set_fraction':
+ {
+ var value;
+
+ if(this._vf.key.length > 0.0) {
+ if (this._vf.set_fraction <= this._vf.key[0])
+ value = x3dom.fields.SFVec3f.copy(this._vf.keyValue[0]);
+
+ else if (this._vf.set_fraction >= this._vf.key[this._vf.key.length-1])
+ value = x3dom.fields.SFVec3f.copy(this._vf.keyValue[this._vf.key.length-1]);
+ }
+
+ for(var i = 0; i < this._vf.key.length-1; i++) {
+ if ((this._vf.key[i] < this._vf.set_fraction) && (this._vf.set_fraction <= this._vf.key[i+1])) {
+ var s = (this._vf.set_fraction - this._vf.key[i]) / (this._vf.key[i+1]-this._vf.key[i]);
+
+ var S_H = new x3dom.fields.SFVec4f(2.0*s*s*s - 3.0*s*s + 1.0, -2.0*s*s*s + 3.0*s*s, s*s*s - 2.0*s*s + s, s*s*s - s*s);
+ value = new x3dom.fields.SFVec3f(S_H.x * this._vf.keyValue[i].x + S_H.y * this._vf.keyValue[i+1].x + S_H.z * this.T0[i].x + S_H.w * this.T1[i+1].x,
+ S_H.x * this._vf.keyValue[i].y + S_H.y * this._vf.keyValue[i+1].y + S_H.z * this.T0[i].y + S_H.w * this.T1[i+1].y,
+ S_H.x * this._vf.keyValue[i].z + S_H.y * this._vf.keyValue[i+1].z + S_H.z * this.T0[i].z + S_H.w * this.T1[i+1].z);
+ break;
+ }
+ }
+
+ if(value !== undefined)
+ this.postMessage('value_changed', value);
+ else
+ x3dom.debug.logWarning("SplinePositionInterpolator Node: value_changed is undefined!");
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### TimeSensor ###
+x3dom.registerNodeType(
+ "TimeSensor",
+ "Time",
+ defineClass(x3dom.nodeTypes.X3DSensorNode,
+
+ /**
+ * Constructor for TimeSensor
+ * @constructs x3dom.nodeTypes.TimeSensor
+ * @x3d 3.3
+ * @component Time
+ * @status full
+ * @extends x3dom.nodeTypes.X3DSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc TimeSensor nodes generate events as time passes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TimeSensor.superClass.call(this, ctx);
+
+ if (ctx)
+ ctx.doc._nodeBag.timer.push(this);
+ else
+ x3dom.debug.logWarning("TimeSensor: No runtime context found!");
+
+
+ /**
+ * The "cycle" of a TimeSensor node lasts for cycleInterval seconds. The value of cycleInterval shall be greater than zero.
+ * @var {x3dom.fields.SFTime} cycleInterval
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'cycleInterval', 1);
+
+
+ /**
+ * Specifies whether the timer cycle loops.
+ * @var {x3dom.fields.SFBool} loop
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'loop', false);
+
+ /**
+ * Sets the startTime for the cycle.
+ * @var {x3dom.fields.SFTime} startTime
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'startTime', 0);
+
+ /**
+ * Sets a time for the timer to stop.
+ * @var {x3dom.fields.SFTime} stopTime
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'stopTime', 0);
+
+ /**
+ * Sets a time for the timer to pause.
+ * @var {x3dom.fields.SFTime} pauseTime
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'pauseTime', 0);
+
+ /**
+ * Sets a time for the timer to resume from pause.
+ * @var {x3dom.fields.SFTime} resumeTime
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'resumeTime', 0);
+
+
+ /**
+ * A cycleTime outputOnly field can be used for synchronization purposes such as sound with animation.
+ * The value of a cycleTime event will be equal to the time at the beginning of the current cycle. A cycleTime event is generated at the beginning of every cycle, including the cycle starting at startTime.
+ * The first cycleTime event for a TimeSensor node can be used as an alarm (single pulse at a specified time).
+ * @var {x3dom.fields.SFTime} cycleTime
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'cycleTime', 0);
+
+ /**
+ * The elapsedTime outputOnly field delivers the current elapsed time since the TimeSensor was activated and running, cumulative in seconds and not counting any time while in a paused state.
+ * @var {x3dom.fields.SFTime} elapsedTime
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'elapsedTime', 0);
+
+ /**
+ * fraction_changed events output a floating point value in the closed interval [0, 1]. At startTime the value of fraction_changed is 0. After startTime, the value of fraction_changed in any cycle will progress through the range (0.0, 1.0].
+ * @var {x3dom.fields.SFFloat} fraction_changed
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'fraction_changed', 0);
+
+ /**
+ * Outputs whether the timer is active.
+ * @var {x3dom.fields.SFBool} isActive
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'isActive', false);
+
+ /**
+ * Outputs whether the timer is paused.
+ * @var {x3dom.fields.SFBool} isPaused
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'isPaused', false);
+
+ /**
+ * The time event sends the absolute time for a given tick of the TimeSensor node.
+ * @var {x3dom.fields.SFTime} time
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'time', 0);
+
+
+ /**
+ *
+ * @var {x3dom.fields.SFBool} first
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx,'first', true);
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} firstCycle
+ * @memberof x3dom.nodeTypes.TimeSensor
+ * @initvalue 0.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx,'firstCycle', 0.0);
+
+ this._prevCycle = -1;
+ this._lastTime = 0;
+ this._cycleStopTime = 0;
+ this._activatedTime = 0;
+
+ if (this._vf.startTime > 0) {
+ this._updateCycleStopTime();
+ }
+
+ this._backupStartTime = this._vf.startTime;
+ this._backupStopTime = this._vf.stopTime;
+ this._backupCycleInterval = this._vf.cycleInterval;
+
+ },
+ {
+ tick: function (time)
+ {
+ if (!this._vf.enabled) {
+ this._lastTime = time;
+ return false;
+ }
+
+ var isActive = ( this._vf.cycleInterval > 0 &&
+ time >= this._vf.startTime &&
+ (time < this._vf.stopTime || this._vf.stopTime <= this._vf.startTime) &&
+ (this._vf.loop == true || (this._vf.loop == false && time < this._cycleStopTime)) );
+
+ if (isActive && !this._vf.isActive) {
+ this.postMessage('isActive', true);
+ this._activatedTime = time;
+ }
+
+ // Checking for this._vf.isActive allows the dispatch of 'final events' (before deactivation)
+ if (isActive || this._vf.isActive) {
+ this.postMessage('elapsedTime', time - this._activatedTime);
+
+ var isPaused = ( time >= this._vf.pauseTime && this._vf.pauseTime > this._vf.resumeTime );
+
+ if (isPaused && !this._vf.isPaused) {
+ this.postMessage('isPaused', true);
+ this.postMessage('pauseTime', time);
+ } else if (!isPaused && this._vf.isPaused) {
+ this.postMessage('isPaused', false);
+ this.postMessage('resumeTime', time);
+ }
+
+ if (!isPaused) {
+ var cycleFrac = this._getCycleAt(time);
+ var cycle = Math.floor(cycleFrac);
+
+ var cycleTime = this._vf.startTime + cycle*this._vf.cycleInterval;
+ var adjustTime = 0;
+
+ if (this._vf.stopTime > this._vf.startTime &&
+ this._lastTime < this._vf.stopTime && time >= this._vf.stopTime)
+ adjustTime = this._vf.stopTime;
+ else if (this._lastTime < cycleTime && time >= cycleTime)
+ adjustTime = cycleTime;
+
+ if( adjustTime > 0 ) {
+ time = adjustTime;
+ cycleFrac = this._getCycleAt(time);
+ cycle = Math.floor(cycleFrac);
+ }
+
+ var fraction = cycleFrac - cycle;
+
+ if (fraction < x3dom.fields.Eps) {
+ fraction = ( this._lastTime < this._vf.startTime ? 0.0 : 1.0 );
+ this.postMessage('cycleTime', time);
+ }
+
+ this.postMessage('fraction_changed', fraction);
+
+ this.postMessage('time', time);
+ }
+ }
+
+ if (!isActive && this._vf.isActive)
+ this.postMessage('isActive', false);
+
+ this._lastTime = time;
+
+ return true;
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName == "enabled") {
+ // TODO; eval other relevant outputs
+ if (!this._vf.enabled && this._vf.isActive) {
+ this.postMessage('isActive', false);
+ }
+ }
+ else if (fieldName == "startTime") {
+ // Spec: Should be ignored when active. (Restore old value)
+ if (this._vf.isActive) {
+ this._vf.startTime = this._backupStartTime;
+ return;
+ }
+
+ this._backupStartTime = this._vf.startTime;
+ this._updateCycleStopTime();
+ }
+ else if (fieldName == "stopTime") {
+ // Spec: Should be ignored when active and less than startTime. (Restore old value)
+ if (this._vf.isActive && this._vf.stopTime <= this._vf.startTime) {
+ this._vf.stopTime = this._backupStopTime;
+ return;
+ }
+
+ this._backupStopTime = this._vf.stopTime;
+ }
+ else if (fieldName == "cycleInterval") {
+ // Spec: Should be ignored when active. (Restore old value)
+ if (this._vf.isActive) {
+ this._vf.cycleInterval = this._backupCycleInterval;
+ return;
+ }
+
+ this._backupCycleInterval = this._vf.cycleInterval;
+ }
+ else if (fieldName == "loop") {
+ this._updateCycleStopTime();
+ }
+ },
+
+ parentRemoved: function(parent)
+ {
+ if (this._parentNodes.length === 0) {
+ var doc = this.findX3DDoc();
+
+ for (var i=0, n=doc._nodeBag.timer.length; i<n; i++) {
+ if (doc._nodeBag.timer[i] === this) {
+ doc._nodeBag.timer.splice(i, 1);
+ }
+ }
+ }
+ },
+
+ _getCycleAt: function(time)
+ {
+ return Math.max( 0.0, time - this._vf.startTime ) / this._vf.cycleInterval;
+ },
+
+ _updateCycleStopTime: function()
+ {
+ if (this._vf.loop == false) {
+ var now = new Date().getTime() / 1000;
+ var cycleToStop = Math.floor(this._getCycleAt(now)) + 1;
+
+ this._cycleStopTime = this._vf.startTime + cycleToStop*this._vf.cycleInterval;
+ }
+ else {
+ this._cycleStopTime = 0;
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DTimeDependentNode ### */
+x3dom.registerNodeType(
+ "X3DTimeDependentNode",
+ "Time",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DTimeDependentNode
+ * @constructs x3dom.nodeTypes.X3DTimeDependentNode
+ * @x3d 3.3
+ * @component Time
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base node type from which all time-dependent nodes are derived.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DTimeDependentNode.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies whether the timer cycle loops.
+ * @var {x3dom.fields.SFBool} loop
+ * @memberof x3dom.nodeTypes.X3DTimeDependentNode
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'loop', false);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### Anchor ###
+x3dom.registerNodeType(
+ "Anchor",
+ "Networking",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Anchor
+ * @constructs x3dom.nodeTypes.Anchor
+ * @x3d 3.3
+ * @component Networking
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Anchor is a Grouping node that can contain most nodes. Clicking Anchored geometry loads content specified by the url field.
+ * Loaded content completely replaces current content, if parameter is same window.
+ * Hint: insert a Shape node before adding geometry or Appearance.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Anchor.superClass.call(this, ctx);
+
+
+ /**
+ * Address of replacement world, activated by clicking Anchor geometry. Hint: jump to a world's internal viewpoint by appending viewpoint name (e.g. #ViewpointName, someOtherCoolWorld.wrl#GrandTour). Hint: jump to a local viewpoint by only using viewpoint name (e.g. #GrandTour). Hint: Strings can have multiple values, so separate each string by quote marks [ 'http://www.url1.org' 'http://www.url2.org' 'etc.' ]. Hint: XML encoding for ' is ampersandquot; (a character entity). Warning: strictly match directory and filename capitalization for http links! Hint: can replace embedded blank(s) in url queries with %20 for each blank character.
+ * @var {x3dom.fields.MFString} url
+ * @memberof x3dom.nodeTypes.Anchor
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'url', []);
+
+ /**
+ * Passed parameter that signals web browser how to redirect url loading. Each string shall consist of "keyword=value" pairs. Hint: set parameter to target=_blank or target=_extern to load target url with a system-specific application. target=_self or target=_intern will open url in current x3d-browser window. Hint: set parameter to target=frame_name to load target url into another frame. Hint: Strings can have multiple values, so separate each string by quote marks. [ 'http://www.url1.org' 'http://www.url2.org' 'etc.' ]. Interchange profile hint: this field may be ignored.
+ * @var {x3dom.fields.MFString} parameter
+ * @memberof x3dom.nodeTypes.Anchor
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'parameter', []);
+
+ /**
+ * The description field in the Anchor node specifies a textual description of the Anchor node.
+ * This may be used by browser-specific user interfaces that wish to present users with more detailed information about the Anchor.
+ * @var {x3dom.fields.SFString} description
+ * @memberof x3dom.nodeTypes.Anchor
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'description', "");
+
+ },
+ {
+ doIntersect: function(line) {
+ var isect = false;
+ for (var i=0; i<this._childNodes.length; i++) {
+ if (this._childNodes[i]) {
+ isect = this._childNodes[i].doIntersect(line) || isect;
+ }
+ }
+ return isect;
+ },
+
+ handleTouch: function() {
+ var url = this._vf.url.length ? this._vf.url[0] : "";
+ var aPos = url.search("#");
+ var anchor = "";
+ if (aPos >= 0)
+ anchor = url.slice(aPos+1);
+
+ var param = this._vf.parameter.length ? this._vf.parameter[0] : "";
+ var tPos = param.search("target=");
+ var target = "";
+ if (tPos >= 0)
+ target = param.slice(tPos+7);
+
+ // TODO: implement #Viewpoint bind
+ // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/components/networking.html#Anchor
+ x3dom.debug.logInfo("Anchor url=" + url + ", target=" + target + ", #viewpoint=" + anchor);
+
+ if(target.length !=0 || target != "_self") {
+ window.open(this._nameSpace.getURL(url), target);
+ }
+ else {
+ window.location = this._nameSpace.getURL(url);
+ }
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### Inline ###
+x3dom.registerNodeType(
+ "Inline",
+ "Networking",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Inline
+ * @constructs x3dom.nodeTypes.Inline
+ * @x3d 3.3
+ * @component Networking
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Inline is a Grouping node that can load nodes from another X3D scene via url.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Inline.superClass.call(this, ctx);
+
+
+ /**
+ * Each specified URL shall refer to a valid X3D file that contains a list of children nodes, prototypes and routes at the top level. Hint: Strings can have multiple values, so separate each string by quote marks. Warning: strictly match directory and filename capitalization for http links!
+ * @var {x3dom.fields.MFString} url
+ * @memberof x3dom.nodeTypes.Inline
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'url', []);
+
+ /**
+ * Specifies whether the X3D file specified by the url field is loaded. Hint: use LoadSensor to detect when loading is complete. TRUE: load immediately (it's also possible to load the URL at a later time by sending a TRUE event to the load field); FALSE: no action is taken (by sending a FALSE event to the load field of a previously loaded Inline, the contents of the Inline will be unloaded from the scene graph)
+ * @var {x3dom.fields.SFBool} load
+ * @memberof x3dom.nodeTypes.Inline
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'load', true);
+
+ /**
+ * Specifies the namespace of the Inline node.
+ * @var {x3dom.fields.MFString} nameSpaceName
+ * @memberof x3dom.nodeTypes.Inline
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'nameSpaceName', []);
+
+ /**
+ * Specifies whether the DEF value is used as id when no other id is set.
+ * @var {x3dom.fields.SFBool} mapDEFToID
+ * @memberof x3dom.nodeTypes.Inline
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'mapDEFToID', false);
+
+ this.initDone = false;
+ this.count = 0;
+ this.numRetries = x3dom.nodeTypes.Inline.MaximumRetries;
+
+ },
+ {
+ fieldChanged: function (fieldName)
+ {
+ if (fieldName == "url") {
+ if (this._vf.nameSpaceName.length != 0) {
+ var node = this._xmlNode;
+ if (node && node.hasChildNodes())
+ {
+ while ( node.childNodes.length >= 1 )
+ {
+ node.removeChild( node.firstChild );
+ }
+ }
+ }
+ this.loadInline();
+ }
+ else if (fieldName == "render") {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ },
+
+ nodeChanged: function ()
+ {
+ if (!this.initDone) {
+ this.initDone = true;
+ this.loadInline();
+ }
+ },
+
+ fireEvents: function(eventType)
+ {
+ if ( this._xmlNode &&
+ (this._xmlNode['on'+eventType] ||
+ this._xmlNode.hasAttribute('on'+eventType) ||
+ this._listeners[eventType]) )
+ {
+ var event = {
+ target: this._xmlNode,
+ type: eventType,
+ error: (eventType == "error") ? "XMLHttpRequest Error" : "",
+ cancelBubble: false,
+ stopPropagation: function() { this.cancelBubble = true; }
+ };
+
+ try {
+ var attrib = this._xmlNode["on" + eventType];
+
+ if (typeof(attrib) === "function") {
+ attrib.call(this._xmlNode, event);
+ }
+ else {
+ var funcStr = this._xmlNode.getAttribute("on" + eventType);
+ var func = new Function('event', funcStr);
+ func.call(this._xmlNode, event);
+ }
+
+ var list = this._listeners[eventType];
+ if (list) {
+ for (var i = 0; i < list.length; i++) {
+ list[i].call(this._xmlNode, event);
+ }
+ }
+ }
+ catch(ex) {
+ x3dom.debug.logException(ex);
+ }
+ }
+ },
+
+ loadInline: function ()
+ {
+ var that = this;
+
+ var xhr = new window.XMLHttpRequest();
+ if (xhr.overrideMimeType)
+ xhr.overrideMimeType('text/xml'); //application/xhtml+xml
+
+ xhr.onreadystatechange = function ()
+ {
+ if (xhr.readyState != 4) {
+ // still loading
+ //x3dom.debug.logInfo('Loading inlined data... (readyState: ' + xhr.readyState + ')');
+ return xhr;
+ }
+
+ if (xhr.status === x3dom.nodeTypes.Inline.AwaitTranscoding) {
+ if (that.count < that.numRetries)
+ {
+ that.count++;
+ var refreshTime = +xhr.getResponseHeader("Refresh") || 5;
+ x3dom.debug.logInfo('XHR status: ' + xhr.status + ' - Await Transcoding (' + that.count + '/' + that.numRetries + '): ' +
+ 'Next request in ' + refreshTime + ' seconds');
+
+ window.setTimeout(function() {
+ that._nameSpace.doc.downloadCount -= 1;
+ that.loadInline();
+ }, refreshTime * 1000);
+ return xhr;
+ }
+ else
+ {
+ x3dom.debug.logError('XHR status: ' + xhr.status + ' - Await Transcoding (' + that.count + '/' + that.numRetries + '): ' +
+ 'No Retries left');
+ that._nameSpace.doc.downloadCount -= 1;
+ that.count = 0;
+ return xhr;
+ }
+ }
+ else if ((xhr.status !== 200) && (xhr.status !== 0)) {
+ that.fireEvents("error");
+ x3dom.debug.logError('XHR status: ' + xhr.status + ' - XMLHttpRequest requires web server running!');
+
+ that._nameSpace.doc.downloadCount -= 1;
+ that.count = 0;
+ return xhr;
+ }
+ else if ((xhr.status == 200) || (xhr.status == 0)) {
+ that.count = 0;
+ }
+
+ x3dom.debug.logInfo('Inline: downloading '+that._vf.url[0]+' done.');
+
+ var inlScene = null, newScene = null, nameSpace = null, xml = null;
+
+ if (navigator.appName != "Microsoft Internet Explorer")
+ xml = xhr.responseXML;
+ else
+ xml = new DOMParser().parseFromString(xhr.responseText, "text/xml");
+
+ //TODO; check if exists and FIXME: it's not necessarily the first scene in the doc!
+ if (xml !== undefined && xml !== null)
+ {
+ inlScene = xml.getElementsByTagName('Scene')[0] ||
+ xml.getElementsByTagName('scene')[0];
+ }
+ else {
+ that.fireEvents("error");
+ }
+
+ if (inlScene)
+ {
+ var nsName = (that._vf.nameSpaceName.length != 0) ?
+ that._vf.nameSpaceName.toString().replace(' ','') : "";
+ nameSpace = new x3dom.NodeNameSpace(nsName, that._nameSpace.doc);
+
+ var url = that._vf.url.length ? that._vf.url[0] : "";
+ if ((url[0] === '/') || (url.indexOf(":") >= 0))
+ nameSpace.setBaseURL(url);
+ else
+ nameSpace.setBaseURL(that._nameSpace.baseURL + url);
+
+ newScene = nameSpace.setupTree(inlScene);
+ that._nameSpace.addSpace(nameSpace);
+
+ if(that._vf.nameSpaceName.length != 0)
+ {
+ Array.forEach ( inlScene.childNodes, function (childDomNode)
+ {
+ if(childDomNode instanceof Element)
+ {
+ setNamespace(that._vf.nameSpaceName, childDomNode, that._vf.mapDEFToID);
+ that._xmlNode.appendChild(childDomNode);
+ }
+ } );
+ }
+ }
+ else {
+ if (xml && xml.localName)
+ x3dom.debug.logError('No Scene in ' + xml.localName);
+ else
+ x3dom.debug.logError('No Scene in resource');
+ }
+
+ // trick to free memory, assigning a property to global object, then deleting it
+ var global = x3dom.getGlobal();
+
+ if (that._childNodes.length > 0 && that._childNodes[0] && that._childNodes[0]._nameSpace)
+ that._nameSpace.removeSpace(that._childNodes[0]._nameSpace);
+
+ while (that._childNodes.length !== 0)
+ global['_remover'] = that.removeChild(that._childNodes[0]);
+
+ delete global['_remover'];
+
+ if (newScene)
+ {
+ that.addChild(newScene);
+
+ that.invalidateVolume();
+ //that.invalidateCache();
+
+ that._nameSpace.doc.downloadCount -= 1;
+ that._nameSpace.doc.needRender = true;
+ x3dom.debug.logInfo('Inline: added ' + that._vf.url[0] + ' to scene.');
+
+ // recalc changed scene bounding box twice
+ var theScene = that._nameSpace.doc._scene;
+
+ if (theScene) {
+ theScene.invalidateVolume();
+ //theScene.invalidateCache();
+
+ window.setTimeout( function() {
+ that.invalidateVolume();
+ //that.invalidateCache();
+
+ theScene.updateVolume();
+ that._nameSpace.doc.needRender = true;
+ }, 1000 );
+ }
+
+ that.fireEvents("load");
+ }
+
+ newScene = null;
+ nameSpace = null;
+ inlScene = null;
+ xml = null;
+
+ return xhr;
+ };
+
+ if (this._vf.url.length && this._vf.url[0].length)
+ {
+ var xhrURI = this._nameSpace.getURL(this._vf.url[0]);
+
+ xhr.open('GET', xhrURI, true);
+
+ this._nameSpace.doc.downloadCount += 1;
+
+ try {
+ xhr.send(null);
+ }
+ catch(ex) {
+ this.fireEvents("error");
+ x3dom.debug.logError(this._vf.url[0] + ": " + ex);
+ }
+ }
+ }
+ }
+ )
+);
+
+x3dom.nodeTypes.Inline.AwaitTranscoding = 202; // Parameterizable retry state for Transcoder
+x3dom.nodeTypes.Inline.MaximumRetries = 15; // Parameterizable maximum number of retries
+
+function setNamespace(prefix, childDomNode, mapDEFToID)
+{
+ if(childDomNode instanceof Element && childDomNode.__setAttribute !== undefined) {
+
+ if(childDomNode.hasAttribute('id') ) {
+ childDomNode.__setAttribute('id', prefix.toString().replace(' ','') +'__'+ childDomNode.getAttribute('id'));
+ } else if (childDomNode.hasAttribute('DEF') && mapDEFToID){
+ childDomNode.__setAttribute('id', prefix.toString().replace(' ','') +'__'+ childDomNode.getAttribute('DEF'));
+ // workaround for Safari
+ if (!childDomNode.id)
+ childDomNode.id = childDomNode.__getAttribute('id');
+ }
+ }
+
+ if(childDomNode.hasChildNodes()){
+ Array.forEach ( childDomNode.childNodes, function (children) {
+ setNamespace(prefix, children, mapDEFToID);
+ } );
+ }
+}
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### MultiPart ###
+x3dom.registerNodeType(
+ "MultiPart",
+ "Networking",
+ defineClass(x3dom.nodeTypes.Inline,
+
+ /**
+ * Constructor for MultiPart
+ * @constructs x3dom.nodeTypes.MultiPart
+ * @x3d x.x
+ * @component Networking
+ * @extends x3dom.nodeTypes.Inline
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Multipart node
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MultiPart.superClass.call(this, ctx);
+
+ /**
+ * Specifies the url to the IDMap.
+ * @var {x3dom.fields.MFString} urlIDMap
+ * @memberof x3dom.nodeTypes.MultiPart
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'urlIDMap', []);
+
+ /**
+ * Defines whether the shape is pickable.
+ * @var {x3dom.fields.SFBool} isPickable
+ * @memberof x3dom.nodeTypes.MultiPart
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'isPickable', true);
+
+ /**
+ * Defines the shape type for sorting.
+ * @var {x3dom.fields.SFString} sortType
+ * @range [auto, transparent, opaque]
+ * @memberof x3dom.nodeTypes.MultiPart
+ * @initvalue 'auto'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'sortType', 'auto');
+
+ /**
+ * Specifies whether backface-culling is used. If solid is TRUE only front-faces are drawn.
+ * @var {x3dom.fields.SFBool} solid
+ * @memberof x3dom.nodeTypes.MultiPart
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'solid', false);
+
+ /**
+ * Change render order manually.
+ * @var {x3dom.fields.SFInt32} sortKey
+ * @memberof x3dom.nodeTypes.MultiPart
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'sortKey', 0);
+
+ /**
+ * Set the initial visibility.
+ * @var {x3dom.fields.SFInt32} initialVisibility
+ * @range [auto, visible, invisible]
+ * @memberof x3dom.nodeTypes.MultiPart
+ * @initvalue 'auto'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'initialVisibility', 'auto');
+
+ this._idMap = null;
+ this._inlineNamespace = null;
+ this._highlightedParts = [];
+ this._minId = 0;
+ this._maxId = 0;
+ this._lastId = -1;
+ this._lastClickedId = -1;
+ this._lastButton = 0;
+ this._identifierToPartId = [];
+ this._identifierToAppId = [];
+ this._visiblePartsPerShape = [];
+ this._partVolume = [];
+ this._partVisibility = [];
+ this._originalColor = [];
+ this._materials = [];
+
+ },
+ {
+ fieldChanged: function (fieldName)
+ {
+ if (fieldName == "url") {
+ if (this._vf.nameSpaceName.length != 0) {
+ var node = this._xmlNode;
+ if (node && node.hasChildNodes())
+ {
+ while ( node.childNodes.length >= 1 )
+ {
+ node.removeChild( node.firstChild );
+ }
+ }
+ }
+ this.loadInline();
+ }
+ else if (fieldName == "render") {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ },
+
+ nodeChanged: function ()
+ {
+ if (!this.initDone) {
+ this.initDone = true;
+ this.loadIDMap();
+ }
+ },
+
+ getVolume: function ()
+ {
+ var vol = this._graph.volume;
+
+ if (!this.volumeValid() && this._vf.render)
+ {
+ for (var i=0; i<this._partVisibility.length; i++)
+ {
+ if (!this._partVisibility[i])
+ continue;
+
+ var childVol = this._partVolume[i];
+
+ if (childVol && childVol.isValid())
+ vol.extendBounds(childVol.min, childVol.max);
+ }
+ }
+
+ return vol;
+ },
+
+ handleEvents: function(e)
+ {
+ if( this._inlineNamespace ) {
+ var colorMap = this._inlineNamespace.defMap["MultiMaterial_ColorMap"];
+ var emissiveMap = this._inlineNamespace.defMap["MultiMaterial_EmissiveMap"];
+ var specularMap = this._inlineNamespace.defMap["MultiMaterial_SpecularMap"];
+ var visibilityMap = this._inlineNamespace.defMap["MultiMaterial_VisibilityMap"];
+
+ //Check for Background press and release
+ if (e.pickedId == -1 && e.button != 0) {
+ this._lastClickedId = -1;
+ this._lastButton = e.button;
+ } else if (e.pickedId == -1 && e.button == 0) {
+ this._lastClickedId = -1;
+ this._lastButton = 0;
+ }
+
+ if (e.pickedId != -1) {
+ e.part = new x3dom.Parts(this, [e.pickedId - this._minId], colorMap, emissiveMap, specularMap, visibilityMap);
+ e.partID = this._idMap.mapping[e.pickedId - this._minId].name;
+
+ //fire mousemove event
+ e.type = "mousemove";
+ this.callEvtHandler("onmousemove", e);
+
+ //fire mouseover event
+ e.type = "mouseover";
+ this.callEvtHandler("onmouseover", e);
+
+ //if some mouse button is down fire mousedown event
+ if (!e.mouseup && e.button && e.button != this._lastButton) {
+ e.type = "mousedown";
+ this._lastButton = e.button;
+ if ( this._lastClickedId == -1 ) {
+ this._lastClickedId = e.pickedId;
+ }
+ this.callEvtHandler("onmousedown", e);
+ }
+
+ //if some mouse button is up fire mouseup event
+ if (e.mouseup || (this._lastButton != 0 && e.button == 0)) {
+ e.type = "mouseup";
+ this.callEvtHandler("onmouseup", e);
+ this._lastButton = 0;
+
+ if ( e.pickedId == this._lastClickedId ) {
+ this._lastClickedId = -1;
+ e.type = "click";
+ this.callEvtHandler("onclick", e);
+ }
+
+ this._lastClickedId = -1;
+ }
+
+ //If the picked id has changed we enter+leave a part
+ if (e.pickedId != this._lastId) {
+ if (this._lastId != -1) {
+ e.part = new x3dom.Parts(this, [this._lastId - this._minId], colorMap, emissiveMap, specularMap, visibilityMap);
+ e.partID = this._idMap.mapping[this._lastId - this._minId].name;
+ e.type = "mouseleave";
+ this.callEvtHandler("onmouseleave", e);
+ }
+
+ e.part = new x3dom.Parts(this, [e.pickedId - this._minId], colorMap, emissiveMap, specularMap, visibilityMap);
+ e.partID = this._idMap.mapping[e.pickedId - this._minId].name;
+ e.type = "mouseenter";
+ this.callEvtHandler("onmouseenter", e);
+ this._lastId = e.pickedId;
+ }
+
+ this._lastId = e.pickedId;
+ }
+ else if (this._lastId != -1) {
+ e.part = new x3dom.Parts(this, [this._lastId - this._minId], colorMap, emissiveMap, specularMap, visibilityMap);
+ e.partID = this._idMap.mapping[this._lastId - this._minId].name;
+ e.type = "mouseout";
+ this.callEvtHandler("onmouseout", e);
+ e.type = "mouseleave";
+ this.callEvtHandler("onmouseleave", e);
+ this._lastId = -1;
+ }
+ }
+
+ },
+
+ loadIDMap: function ()
+ {
+ if (this._vf.urlIDMap.length && this._vf.urlIDMap[0].length)
+ {
+ var i;
+
+ var that = this;
+
+ var idMapURI = this._nameSpace.getURL(this._vf.urlIDMap[0]);
+
+ var xhr = new XMLHttpRequest();
+
+ xhr.open("GET", idMapURI, true);
+
+ xhr.onload = function()
+ {
+ that._idMap = JSON.parse(this.responseText);
+
+ //Check if the MultiPart map already initialized
+ if (that._nameSpace.doc._scene._multiPartMap == null) {
+ that._nameSpace.doc._scene._multiPartMap = {numberOfIds: 0, multiParts: []};
+ }
+
+ //Set the ID range this MultiPart is holding
+ that._minId = that._nameSpace.doc._scene._multiPartMap.numberOfIds;
+ that._maxId = that._minId + that._idMap.numberOfIDs - 1;
+
+ //Update the MultiPart map
+ that._nameSpace.doc._scene._multiPartMap.numberOfIds += that._idMap.numberOfIDs;
+ that._nameSpace.doc._scene._multiPartMap.multiParts.push(that);
+
+ //prepare internal shape map
+ for (i=0; i<that._idMap.mapping.length; i++)
+ {
+ if (!that._identifierToPartId[that._idMap.mapping[i].name]) {
+ that._identifierToPartId[that._idMap.mapping[i].name] = [];
+ }
+
+ if (!that._identifierToPartId[that._idMap.mapping[i].appearance]) {
+ that._identifierToPartId[that._idMap.mapping[i].appearance] = [];
+ }
+
+ that._identifierToPartId[that._idMap.mapping[i].name].push(i);
+ that._identifierToPartId[that._idMap.mapping[i].appearance].push(i);
+
+ if (!that._partVolume[i]) {
+ var min = x3dom.fields.SFVec3f.parse(that._idMap.mapping[i].min);
+ var max = x3dom.fields.SFVec3f.parse(that._idMap.mapping[i].max);
+
+ that._partVolume[i] = new x3dom.fields.BoxVolume(min, max);
+ }
+
+ }
+
+ //prepare internal appearance map
+ for (i=0; i<that._idMap.appearance.length; i++)
+ {
+ that._identifierToAppId[that._idMap.appearance[i].name] = i;
+ }
+
+ that.loadInline();
+ };
+
+ xhr.send(null);
+ }
+ },
+
+ createMaterialData: function ()
+ {
+ var diffuseColor, transparency, specularColor, shininess, emissiveColor, ambientIntensity;
+ var backDiffuseColor, backTransparency, backSpecularColor, backShininess, backEmissiveColor, backAmbientIntensity;
+ var rgba_DT = "", rgba_SS = "", rgba_EA = "";
+ var rgba_DT_B = "", rgba_SS_B = "", rgba_EA_B = "";
+
+ var size = Math.ceil(Math.sqrt(this._idMap.numberOfIDs));
+
+ //scale image data array size to the next highest power of two
+ size = x3dom.Utils.nextHighestPowerOfTwo(size);
+ var sizeTwo = size * 2.0;
+
+ var diffuseTransparencyData = size + " " + sizeTwo + " 4";
+ var specularShininessData = size + " " + sizeTwo + " 4";
+ var emissiveAmbientIntensityData = size + " " + sizeTwo + " 4";
+
+ for (var i=0; i<size*size; i++)
+ {
+ if (i < this._idMap.mapping.length)
+ {
+ var appName = this._idMap.mapping[i].appearance;
+ var appID = this._identifierToAppId[appName];
+
+ //AmbientIntensity
+ if (this._idMap.appearance[appID].material.ambientIntensity) {
+ ambientIntensity = this._idMap.appearance[appID].material.ambientIntensity
+ } else {
+ ambientIntensity = "0.2";
+ }
+
+ //BackAmbientIntensity
+ if (this._idMap.appearance[appID].material.backAmbientIntensity) {
+ backAmbientIntensity = this._idMap.appearance[appID].material.backAmbientIntensity
+ } else {
+ backAmbientIntensity = ambientIntensity;
+ }
+
+ //DiffuseColor
+ if (this._idMap.appearance[appID].material.diffuseColor) {
+ diffuseColor = this._idMap.appearance[appID].material.diffuseColor
+ } else {
+ diffuseColor = "0.8 0.8 0.8";
+ }
+
+ //BackDiffuseColor
+ if (this._idMap.appearance[appID].material.backDiffuseColor) {
+ backDiffuseColor = this._idMap.appearance[appID].material.backDiffuseColor
+ } else {
+ backDiffuseColor = diffuseColor;
+ }
+
+ //EmissiveColor
+ if (this._idMap.appearance[appID].material.emissiveColor) {
+ emissiveColor = this._idMap.appearance[appID].material.emissiveColor
+ } else {
+ emissiveColor = "0.0 0.0 0.0";
+ }
+
+ //BackEmissiveColor
+ if (this._idMap.appearance[appID].material.backEmissiveColor) {
+ backEmissiveColor = this._idMap.appearance[appID].material.backEmissiveColor
+ } else {
+ backEmissiveColor = emissiveColor;
+ }
+
+ //Shininess
+ if (this._idMap.appearance[appID].material.shininess) {
+ shininess = this._idMap.appearance[appID].material.shininess;
+ } else {
+ shininess = "0.2";
+ }
+
+ //BackShininess
+ if (this._idMap.appearance[appID].material.backShininess) {
+ backShininess = this._idMap.appearance[appID].material.backShininess;
+ } else {
+ backShininess = shininess;
+ }
+
+ //SpecularColor
+ if (this._idMap.appearance[appID].material.specularColor) {
+ specularColor = this._idMap.appearance[appID].material.specularColor;
+ } else {
+ specularColor = "0 0 0";
+ }
+
+ //BackSpecularColor
+ if (this._idMap.appearance[appID].material.backSpecularColor) {
+ backSpecularColor = this._idMap.appearance[appID].material.backSpecularColor;
+ } else {
+ backSpecularColor = specularColor;
+ }
+
+ //Transparency
+ if (this._idMap.appearance[appID].material.transparency) {
+ transparency = this._idMap.appearance[appID].material.transparency;
+ } else {
+ transparency = "0.0";
+ }
+
+ //BackTransparency
+ if (this._idMap.appearance[appID].material.backTransparency) {
+ backTransparency = this._idMap.appearance[appID].material.backTransparency;
+ } else {
+ backTransparency = transparency;
+ }
+
+ rgba_DT += " " + x3dom.fields.SFColorRGBA.parse(diffuseColor + " " + transparency).toUint();
+ rgba_SS += " " + x3dom.fields.SFColorRGBA.parse(specularColor + " " + shininess).toUint();
+ rgba_EA += " " + x3dom.fields.SFColorRGBA.parse(emissiveColor + " " + ambientIntensity).toUint();
+
+ rgba_DT_B += " " + x3dom.fields.SFColorRGBA.parse(backDiffuseColor + " " + backTransparency).toUint();
+ rgba_SS_B += " " + x3dom.fields.SFColorRGBA.parse(backSpecularColor + " " + backShininess).toUint();
+ rgba_EA_B += " " + x3dom.fields.SFColorRGBA.parse(backEmissiveColor + " " + backAmbientIntensity).toUint();
+
+ this._originalColor[i] = rgba_DT;
+
+ this._materials[i] = new x3dom.MultiMaterial({
+ "ambientIntensity": ambientIntensity,
+ "diffuseColor": x3dom.fields.SFColor.parse(diffuseColor),
+ "emissiveColor": x3dom.fields.SFColor.parse(emissiveColor),
+ "shininess": shininess,
+ "specularColor": x3dom.fields.SFColor.parse(specularColor),
+ "transparency": 1.0 - transparency,
+ "backAmbientIntensity": backAmbientIntensity,
+ "backDiffuseColor": x3dom.fields.SFColor.parse(backDiffuseColor),
+ "backEmissiveColor": x3dom.fields.SFColor.parse(backEmissiveColor),
+ "backShininess": backShininess,
+ "backSpecularColor": x3dom.fields.SFColor.parse(backSpecularColor),
+ "backTransparency": 1.0 - backTransparency
+ });
+ }
+ else
+ {
+ rgba_DT += " 255";
+ rgba_SS += " 255";
+ rgba_EA += " 255";
+
+ rgba_DT_B += " 255";
+ rgba_SS_B += " 255";
+ rgba_EA_B += " 255";
+ }
+ }
+
+ //Combine Front and Back Data
+ diffuseTransparencyData += rgba_DT + rgba_DT_B;
+ specularShininessData += rgba_SS + rgba_SS_B;
+ emissiveAmbientIntensityData += rgba_EA + rgba_EA_B;
+
+ return {
+ "diffuseTransparency": diffuseTransparencyData,
+ "specularShininess": specularShininessData,
+ "emissiveAmbientIntensity": emissiveAmbientIntensityData
+ };
+ },
+
+ createVisibilityData: function ()
+ {
+ var i, j;
+ var size = Math.ceil(Math.sqrt(this._idMap.numberOfIDs));
+
+ //scale image data array size to the next highest power of two
+ size = x3dom.Utils.nextHighestPowerOfTwo(size);
+
+ var visibilityData = size + " " + size + " 1";
+
+ for (i=0; i<size*size; i++)
+ {
+ if (i < this._idMap.mapping.length)
+ {
+ if (this._vf.initialVisibility == 'auto')
+ {
+ //TODO get the Data from JSON
+ visibilityData += " 255";
+
+ if (!this._partVisibility[i]) {
+ this._partVisibility[i] = true;
+ }
+
+ for (j=0; j<this._idMap.mapping[i].usage.length; j++)
+ {
+ if (!this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]]) {
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]] = {val:0, max:0};
+ }
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]].val++;
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]].max++;
+ }
+ }
+ else if (this._vf.initialVisibility == 'visible')
+ {
+ visibilityData += " 255";
+
+ if (!this._partVisibility[i]) {
+ this._partVisibility[i] = true;
+ }
+
+ for (j=0; j<this._idMap.mapping[i].usage.length; j++)
+ {
+ if (!this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]]) {
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]] = {val:0, max:0};
+ }
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]].val++;
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]].max++;
+ }
+ }
+ else if (this._vf.initialVisibility == 'invisible')
+ {
+ visibilityData += " 0";
+
+ if (!this._partVisibility[i]) {
+ this._partVisibility[i] = false;
+ }
+
+ for (j=0; j<this._idMap.mapping[i].usage.length; j++)
+ {
+ if (!this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]]) {
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]] = {val:0, max:0};
+ }
+ this._visiblePartsPerShape[this._idMap.mapping[i].usage[j]].max++;
+ }
+ }
+
+ }
+ else
+ {
+ visibilityData += " 0";
+ }
+ }
+ return visibilityData;
+ },
+
+ replaceMaterials: function (inlScene)
+ {
+ var css, shapeDEF, materialData, visibilityData, appearance;
+ var firstMat = true;
+ if (inlScene && inlScene.hasChildNodes())
+ {
+ materialData = this.createMaterialData();
+ visibilityData = this.createVisibilityData();
+
+ var shapes = inlScene.getElementsByTagName("Shape");
+
+ for (var s=0; s<shapes.length; s++)
+ {
+ shapeDEF = shapes[s].getAttribute("DEF") ||
+ shapes[s].getAttribute("def");
+
+ if(shapeDEF && this._visiblePartsPerShape[shapeDEF] &&
+ this._visiblePartsPerShape[shapeDEF].val == 0)
+ {
+ shapes[s].setAttribute("render", "false");
+ }
+
+ shapes[s].setAttribute("idOffset", this._minId);
+ shapes[s].setAttribute("isPickable", this._vf.isPickable);
+
+ var geometries = shapes[s].getElementsByTagName("BinaryGeometry");
+
+ if (geometries && geometries.length) {
+ for (var g = 0; g < geometries.length; g++) {
+ geometries[g].setAttribute("solid", this._vf.solid);
+ }
+ }
+
+ var appearances = shapes[s].getElementsByTagName("Appearance");
+
+ if (appearances.length)
+ {
+ for (var a = 0; a < appearances.length; a++)
+ {
+ //Remove DEF/USE
+ appearances[a].removeAttribute("DEF");
+ appearances[a].removeAttribute("USE");
+
+ appearances[a].setAttribute("sortType", this._vf.sortType);
+ appearances[a].setAttribute("sortKey", this._vf.sortKey);
+
+ var materials = appearances[a].getElementsByTagName("Material");
+
+ if (materials.length)
+ {
+ //Replace Material
+ if (firstMat) {
+ firstMat = false;
+ css = document.createElement("CommonSurfaceShader");
+ css.setAttribute("DEF", "MultiMaterial");
+
+ var ptDA = document.createElement("PixelTexture");
+ ptDA.setAttribute("containerField", "multiDiffuseAlphaTexture");
+ ptDA.setAttribute("id", "MultiMaterial_ColorMap");
+ ptDA.setAttribute("image", materialData.diffuseTransparency);
+
+ var ptEA = document.createElement("PixelTexture");
+ ptEA.setAttribute("containerField", "multiEmissiveAmbientTexture");
+ ptEA.setAttribute("id", "MultiMaterial_EmissiveMap");
+ ptEA.setAttribute("image", materialData.emissiveAmbientIntensity);
+
+ var ptSS = document.createElement("PixelTexture");
+ ptSS.setAttribute("containerField", "multiSpecularShininessTexture");
+ ptSS.setAttribute("id", "MultiMaterial_SpecularMap");
+ ptSS.setAttribute("image", materialData.specularShininess);
+
+ var ptV = document.createElement("PixelTexture");
+ ptV.setAttribute("containerField", "multiVisibilityTexture");
+ ptV.setAttribute("id", "MultiMaterial_VisibilityMap");
+ ptV.setAttribute("image", visibilityData);
+
+ css.appendChild(ptDA);
+ css.appendChild(ptEA);
+ css.appendChild(ptSS);
+ css.appendChild(ptV);
+ }
+ else
+ {
+ css = document.createElement("CommonSurfaceShader");
+ css.setAttribute("USE", "MultiMaterial");
+ }
+ appearances[a].replaceChild(css, materials[0]);
+ }
+ else
+ {
+ //Add Material
+ if (firstMat) {
+ firstMat = false;
+ css = document.createElement("CommonSurfaceShader");
+ css.setAttribute("DEF", "MultiMaterial");
+
+ var ptDA = document.createElement("PixelTexture");
+ ptDA.setAttribute("containerField", "multiDiffuseAlphaTexture");
+ ptDA.setAttribute("id", "MultiMaterial_ColorMap");
+ ptDA.setAttribute("image", materialData.diffuseTransparency);
+
+ var ptEA = document.createElement("PixelTexture");
+ ptEA.setAttribute("containerField", "multiEmissiveAmbientTexture");
+ ptEA.setAttribute("id", "MultiMaterial_EmissiveMap");
+ ptEA.setAttribute("image", materialData.emissiveAmbientIntensity);
+
+ var ptSS = document.createElement("PixelTexture");
+ ptSS.setAttribute("containerField", "multiSpecularShininessTexture");
+ ptSS.setAttribute("id", "MultiMaterial_SpecularMap");
+ ptSS.setAttribute("image", materialData.specularShininess);
+
+ var ptV = document.createElement("PixelTexture");
+ ptV.setAttribute("containerField", "multiVisibilityTexture");
+ ptV.setAttribute("id", "MultiMaterial_VisibilityMap");
+ ptV.setAttribute("image", visibilityData);
+
+ css.appendChild(ptDA);
+ css.appendChild(ptEA);
+ css.appendChild(ptSS);
+ css.appendChild(ptV);
+ }
+ else
+ {
+ css = document.createElement("CommonSurfaceShader");
+ css.setAttribute("USE", "MultiMaterial");
+ }
+
+ appearances[a].appendChild(css);
+ }
+ }
+ }
+ else
+ {
+ //Add Appearance
+ appearance = document.createElement("Appearance");
+
+ //Add Material
+ if (firstMat) {
+ firstMat = false;
+ css = document.createElement("CommonSurfaceShader");
+ css.setAttribute("DEF", "MultiMaterial");
+
+ var ptDA = document.createElement("PixelTexture");
+ ptDA.setAttribute("containerField", "multiDiffuseAlphaTexture");
+ ptDA.setAttribute("id", "MultiMaterial_ColorMap");
+ ptDA.setAttribute("image", materialData.diffuseTransparency);
+
+ var ptEA = document.createElement("PixelTexture");
+ ptEA.setAttribute("containerField", "multiEmissiveAmbientTexture");
+ ptEA.setAttribute("id", "MultiMaterial_EmissiveMap");
+ ptEA.setAttribute("image", materialData.emissiveAmbientIntensity);
+
+ var ptSS = document.createElement("PixelTexture");
+ ptSS.setAttribute("containerField", "multiSpecularShininessTexture");
+ ptSS.setAttribute("id", "MultiMaterial_SpecularMap");
+ ptSS.setAttribute("image", materialData.specularShininess);
+
+ var ptV = document.createElement("PixelTexture");
+ ptV.setAttribute("containerField", "multiVisibilityTexture");
+ ptV.setAttribute("id", "MultiMaterial_VisibilityMap");
+ ptV.setAttribute("image", visibilityData);
+
+ css.appendChild(ptDA);
+ css.appendChild(ptEA);
+ css.appendChild(ptSS);
+ css.appendChild(ptV);
+ }
+ else
+ {
+ css = document.createElement("CommonSurfaceShader");
+ css.setAttribute("USE", "MultiMaterial");
+ }
+
+ appearance.appendChild(css);
+ geometries[g].appendChild(appearance);
+ }
+ }
+ }
+ },
+
+ appendAPI: function ()
+ {
+ var multiPart = this;
+
+ this._xmlNode.getIdList = function ()
+ {
+ var i, ids = [];
+
+ for (i=0; i<multiPart._idMap.mapping.length; i++) {
+ ids.push( multiPart._idMap.mapping[i].name );
+ }
+
+ return ids;
+ };
+
+ this._xmlNode.getAppearanceIdList = function ()
+ {
+ var i, ids = [];
+
+ for (i=0; i<multiPart._idMap.appearance.length; i++) {
+ ids.push( multiPart._idMap.appearance[i].name );
+ }
+
+ return ids;
+ };
+
+ this._xmlNode.getParts = function (selector)
+ {
+ var i, m;
+ var selection = [];
+
+ if (selector == undefined) {
+ for (m=0; m<multiPart._idMap.mapping.length; m++) {
+ selection.push(m);
+ }
+ } else {
+ for (i=0; i<selector.length; i++) {
+ if (multiPart._identifierToPartId[selector[i]]) {
+ selection = selection.concat(multiPart._identifierToPartId[selector[i]]);
+ }
+ }
+ }
+
+ var colorMap = multiPart._inlineNamespace.defMap["MultiMaterial_ColorMap"];
+ var emissiveMap = multiPart._inlineNamespace.defMap["MultiMaterial_EmissiveMap"];
+ var specularMap = multiPart._inlineNamespace.defMap["MultiMaterial_SpecularMap"];
+ var visibilityMap = multiPart._inlineNamespace.defMap["MultiMaterial_VisibilityMap"];
+
+ if ( selection.length == 0) {
+ return null;
+ } else {
+ return new x3dom.Parts(multiPart, selection, colorMap, emissiveMap, specularMap, visibilityMap);
+ }
+ };
+ },
+
+ loadInline: function ()
+ {
+ var that = this;
+ var xhr = new window.XMLHttpRequest();
+ if (xhr.overrideMimeType)
+ xhr.overrideMimeType('text/xml'); //application/xhtml+xml
+
+ xhr.onreadystatechange = function ()
+ {
+ if (xhr.readyState != 4) {
+ // still loading
+ //x3dom.debug.logInfo('Loading inlined data... (readyState: ' + xhr.readyState + ')');
+ return xhr;
+ }
+
+ if (xhr.status === x3dom.nodeTypes.Inline.AwaitTranscoding) {
+ if (that.count < that.numRetries)
+ {
+ that.count++;
+ var refreshTime = +xhr.getResponseHeader("Refresh") || 5;
+ x3dom.debug.logInfo('XHR status: ' + xhr.status + ' - Await Transcoding (' + that.count + '/' + that.numRetries + '): ' +
+ 'Next request in ' + refreshTime + ' seconds');
+
+ window.setTimeout(function() {
+ that._nameSpace.doc.downloadCount -= 1;
+ that.loadInline();
+ }, refreshTime * 1000);
+ return xhr;
+ }
+ else
+ {
+ x3dom.debug.logError('XHR status: ' + xhr.status + ' - Await Transcoding (' + that.count + '/' + that.numRetries + '): ' +
+ 'No Retries left');
+ that._nameSpace.doc.downloadCount -= 1;
+ that.count = 0;
+ return xhr;
+ }
+ }
+ else if ((xhr.status !== 200) && (xhr.status !== 0)) {
+ that.fireEvents("error");
+ x3dom.debug.logError('XHR status: ' + xhr.status + ' - XMLHttpRequest requires web server running!');
+
+ that._nameSpace.doc.downloadCount -= 1;
+ that.count = 0;
+ return xhr;
+ }
+ else if ((xhr.status == 200) || (xhr.status == 0)) {
+ that.count = 0;
+ }
+
+ x3dom.debug.logInfo('Inline: downloading '+that._vf.url[0]+' done.');
+
+ var inlScene = null, newScene = null, nameSpace = null, xml = null;
+
+ if (navigator.appName != "Microsoft Internet Explorer")
+ xml = xhr.responseXML;
+ else
+ xml = new DOMParser().parseFromString(xhr.responseText, "text/xml");
+
+ //TODO; check if exists and FIXME: it's not necessarily the first scene in the doc!
+ if (xml !== undefined && xml !== null)
+ {
+ inlScene = xml.getElementsByTagName('Scene')[0] ||
+ xml.getElementsByTagName('scene')[0];
+ }
+ else {
+ that.fireEvents("error");
+ }
+
+ if (inlScene)
+ {
+ var nsDefault = "ns" + that._nameSpace.childSpaces.length;
+
+ var nsName = (that._vf.nameSpaceName.length != 0) ?
+ that._vf.nameSpaceName.toString().replace(' ','') : nsDefault;
+
+ that._inlineNamespace = new x3dom.NodeNameSpace(nsName, that._nameSpace.doc);
+
+ var url = that._vf.url.length ? that._vf.url[0] : "";
+
+ if ((url[0] === '/') || (url.indexOf(":") >= 0))
+ {
+ that._inlineNamespace.setBaseURL(url);
+ }
+ else
+ {
+ that._inlineNamespace.setBaseURL(that._nameSpace.baseURL + url);
+ }
+
+ //Replace Material before setupTree()
+ that.replaceMaterials(inlScene);
+
+ newScene = that._inlineNamespace.setupTree(inlScene);
+
+ that._nameSpace.addSpace(that._inlineNamespace);
+
+ if(that._vf.nameSpaceName.length != 0)
+ {
+ Array.forEach ( inlScene.childNodes, function (childDomNode)
+ {
+ if(childDomNode instanceof Element)
+ {
+ setNamespace(that._vf.nameSpaceName, childDomNode, that._vf.mapDEFToID);
+ that._xmlNode.appendChild(childDomNode);
+ }
+ } );
+ }
+ }
+ else {
+ if (xml && xml.localName) {
+ x3dom.debug.logError('No Scene in ' + xml.localName);
+ } else {
+ x3dom.debug.logError('No Scene in resource');
+ }
+ }
+
+ // trick to free memory, assigning a property to global object, then deleting it
+ var global = x3dom.getGlobal();
+
+ if (that._childNodes.length > 0 && that._childNodes[0] && that._childNodes[0]._nameSpace) {
+ that._nameSpace.removeSpace(that._childNodes[0]._nameSpace);
+ }
+
+ while (that._childNodes.length !== 0) {
+ global['_remover'] = that.removeChild(that._childNodes[0]);
+ }
+
+ delete global['_remover'];
+
+ if (newScene)
+ {
+ that.addChild(newScene);
+
+ that.invalidateVolume();
+ //that.invalidateCache();
+
+ that._nameSpace.doc.downloadCount -= 1;
+ that._nameSpace.doc.needRender = true;
+ x3dom.debug.logInfo('Inline: added ' + that._vf.url[0] + ' to scene.');
+
+ // recalc changed scene bounding box twice
+ var theScene = that._nameSpace.doc._scene;
+
+ if (theScene) {
+ theScene.invalidateVolume();
+ //theScene.invalidateCache();
+
+ window.setTimeout( function() {
+ that.invalidateVolume();
+ //that.invalidateCache();
+
+ theScene.updateVolume();
+ that._nameSpace.doc.needRender = true;
+ }, 1000 );
+ }
+
+ that.appendAPI();
+ that.fireEvents("load");
+ }
+
+ newScene = null;
+ //nameSpace = null;
+ inlScene = null;
+ xml = null;
+
+ return xhr;
+ };
+
+ if (this._vf.url.length && this._vf.url[0].length)
+ {
+ var xhrURI = this._nameSpace.getURL(this._vf.url[0]);
+
+ xhr.open('GET', xhrURI, true);
+
+ this._nameSpace.doc.downloadCount += 1;
+
+ try {
+ xhr.send(null);
+ }
+ catch(ex) {
+ this.fireEvents("error");
+ x3dom.debug.logError(this._vf.url[0] + ": " + ex);
+ }
+ }
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+x3dom.registerNodeType(
+ "X3DBackgroundNode",
+ "EnvironmentalEffects",
+ defineClass(x3dom.nodeTypes.X3DBindableNode,
+
+ /**
+ * Constructor for X3DBackgroundNode
+ * @constructs x3dom.nodeTypes.X3DBackgroundNode
+ * @x3d 3.3
+ * @component EnvironmentalEffects
+ * @status full
+ * @extends x3dom.nodeTypes.X3DBindableNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc X3DBackgroundNode is the abstract type from which all backgrounds inherit. X3DBackgroundNode is a
+ * bindable node that, when bound, defines the panoramic background for the scene.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DBackgroundNode.superClass.call(this, ctx);
+
+ var trans = (ctx && ctx.autoGen) ? 1 : 0;
+
+ /**
+ * Cross Origin Mode
+ * @var {x3dom.fields.SFString} crossOrigin
+ * @memberof x3dom.nodeTypes.X3DBackgroundNode
+ * @initvalue ""
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'crossOrigin', '');
+
+ /**
+ * Color of the ground
+ * @var {x3dom.fields.MFColor} groundColor
+ * @memberof x3dom.nodeTypes.X3DBackgroundNode
+ * @initvalue (0,0,0)
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFColor(ctx, 'groundColor', []);
+
+ /**
+ * Angle of the ground
+ * @var {x3dom.fields.MFFloat} groundAngle
+ * @memberof x3dom.nodeTypes.X3DBackgroundNode
+ * @initvalue []
+ * @range [0, pi]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'groundAngle', []);
+
+ /**
+ * Color of the sky
+ * @var {x3dom.fields.MFColor} skyColor
+ * @memberof x3dom.nodeTypes.X3DBackgroundNode
+ * @initvalue (0,0,0)
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFColor(ctx, 'skyColor', [new x3dom.fields.SFColor(0,0,0)]);
+
+ /**
+ * Angle of the sky
+ * @var {x3dom.fields.MFFloat} skyAngle
+ * @memberof x3dom.nodeTypes.X3DBackgroundNode
+ * @initvalue []
+ * @range [0, pi]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'skyAngle', []);
+
+ /**
+ * Transparency of the background
+ * @var {x3dom.fields.SFFloat} transparency
+ * @memberof x3dom.nodeTypes.X3DBackgroundNode
+ * @initvalue 0/1
+ * @range [0,1]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'transparency', trans);
+
+ this._dirty = true;
+
+ },
+ {
+ getSkyColor: function() {
+ return new x3dom.fields.SFColor(0,0,0);
+ },
+ getTransparency: function() {
+ return 0;
+ },
+ getTexUrl: function() {
+ return [];
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DFogNode ### */
+x3dom.registerNodeType(
+ "X3DFogNode",
+ "EnvironmentalEffects",
+ defineClass(x3dom.nodeTypes.X3DBindableNode,
+
+ /**
+ * Constructor for X3DFogNode
+ * @constructs x3dom.nodeTypes.X3DFogNode
+ * @x3d 3.3
+ * @component EnvironmentalEffects
+ * @status full
+ * @extends x3dom.nodeTypes.X3DBindableNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc X3DFogObject is the abstract type that describes a node that influences the lighting equation
+ * through the use of fog semantics.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DFogNode.superClass.call(this, ctx);
+
+ /**
+ * Objects located outside the visibilityRange from the viewer are drawn with a constant colour of color.
+ * Objects very close to the viewer are blended very little with the fog color.
+ * @var {x3dom.fields.SFColor} color
+ * @memberof x3dom.nodeTypes.X3DFogNode
+ * @initvalue (1,1,1)
+ * @range [0,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColor(ctx, 'color', 1, 1, 1);
+
+ /**
+ * The fogType field controls how much of the fog colour is blended with the object as a function of
+ * distance. If fogType is "LINEAR", the amount of blending is a linear function of the distance, resulting
+ * in a depth cueing effect. If fogType is "EXPONENTIAL," an exponential increase in blending is used,
+ * resulting in a more natural fog appearance.
+ * @var {x3dom.fields.SFString} fogType
+ * @memberof x3dom.nodeTypes.X3DFogNode
+ * @initvalue "LINEAR"
+ * @range {"LINEAR","EXPONENTIAL"}
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'fogType', "LINEAR");
+
+ /**
+ * The visibilityRange specifies the distance in length base units (in the local coordinate system) at
+ * which objects are totally obscured by the fog. A visibilityRange of 0.0 disables the Fog node.
+ * The visibilityRange is affected by the scaling transformations of the Fog node's parents; translations
+ * and rotations have no affect on visibilityRange.
+ * @var {x3dom.fields.SFFloat} visibilityRange
+ * @memberof x3dom.nodeTypes.X3DFogNode
+ * @initvalue 0
+ * @range [0, -inf]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'visibilityRange', 0);
+
+ },
+ {
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Fog ### */
+x3dom.registerNodeType(
+ "Fog",
+ "EnvironmentalEffects",
+ defineClass(x3dom.nodeTypes.X3DFogNode,
+
+ /**
+ * Constructor for Fog
+ * @constructs x3dom.nodeTypes.Fog
+ * @x3d 3.3
+ * @component EnvironmentalEffects
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DFogNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Fog node provides a way to simulate atmospheric effects by blending objects with the colour
+ * specified by the color field based on the distances of the various objects from the viewer. The distances
+ * are calculated in the coordinate space of the Fog node.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Fog.superClass.call(this, ctx);
+
+ },
+ {
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Background ### */
+x3dom.registerNodeType(
+ "Background",
+ "EnvironmentalEffects",
+ defineClass(x3dom.nodeTypes.X3DBackgroundNode,
+
+ /**
+ * Constructor for Background
+ * @constructs x3dom.nodeTypes.Background
+ * @x3d 3.3
+ * @component EnvironmentalEffects
+ * @status full
+ * @extends x3dom.nodeTypes.X3DBackgroundNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc A background node that uses six static images to compose the backdrop. For the backUrl,
+ * bottomUrl, frontUrl, leftUrl, rightUrl, topUrl fields, browsers shall support the JPEG and PNG
+ * (see ISO/IEC 15948) image file formats.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Background.superClass.call(this, ctx);
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} backUrl
+ * @memberof x3dom.nodeTypes.Background
+ * @initvalue []
+ * @range [URI]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'backUrl', []);
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} bottomUrl
+ * @memberof x3dom.nodeTypes.Background
+ * @initvalue []
+ * @range [URI]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'bottomUrl', []);
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} frontUrl
+ * @memberof x3dom.nodeTypes.Background
+ * @initvalue []
+ * @range [URI]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'frontUrl', []);
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} leftUrl
+ * @memberof x3dom.nodeTypes.Background
+ * @initvalue []
+ * @range [URI]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'leftUrl', []);
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} rightUrl
+ * @memberof x3dom.nodeTypes.Background
+ * @initvalue []
+ * @range [URI]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'rightUrl', []);
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} topUrl
+ * @memberof x3dom.nodeTypes.Background
+ * @initvalue []
+ * @range [URI]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'topUrl', []);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName.indexOf("Url") > 0 || fieldName == "transparency" ||
+ fieldName.search("sky") >= 0 || fieldName.search("ground") >= 0) {
+ this._dirty = true;
+ }
+ else if (fieldName.indexOf("bind") >= 0) {
+ this.bind(this._vf.bind);
+ }
+ },
+
+ getSkyColor: function() {
+ return this._vf.skyColor;
+ },
+
+ getGroundColor: function() {
+ return this._vf.groundColor;
+ },
+
+ getTransparency: function() {
+ return this._vf.transparency;
+ },
+
+ getTexUrl: function() {
+ return [
+ this._nameSpace.getURL(this._vf.backUrl[0]),
+ this._nameSpace.getURL(this._vf.frontUrl[0]),
+ this._nameSpace.getURL(this._vf.bottomUrl[0]),
+ this._nameSpace.getURL(this._vf.topUrl[0]),
+ this._nameSpace.getURL(this._vf.leftUrl[0]),
+ this._nameSpace.getURL(this._vf.rightUrl[0])
+ ];
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DEnvironmentNode ### */
+x3dom.registerNodeType(
+ "X3DEnvironmentNode",
+ "EnvironmentalEffects",
+ defineClass(x3dom.nodeTypes.X3DBindableNode,
+
+ /**
+ * Constructor for X3DEnvironmentNode
+ * @constructs x3dom.nodeTypes.X3DEnvironmentNode
+ * @x3d x.x
+ * @component EnvironmentalEffects
+ * @status full
+ * @extends x3dom.nodeTypes.X3DBindableNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Base class for environment nodes
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DEnvironmentNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Environment ### */
+x3dom.registerNodeType(
+ "Environment",
+ "EnvironmentalEffects",
+ defineClass(x3dom.nodeTypes.X3DEnvironmentNode,
+
+ /**
+ * Constructor for Environment
+ * @constructs x3dom.nodeTypes.Environment
+ * @x3d x.x
+ * @component EnvironmentalEffects
+ * @status full
+ * @extends x3dom.nodeTypes.X3DEnvironmentNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Bindable node to setup rendering and culling parameters
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Environment.superClass.call(this, ctx);
+
+ /**
+ * If TRUE, transparent objects are sorted from back to front (allows explicitly disabling sorting)
+ * @var {x3dom.fields.SFBool} sortTrans
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'sortTrans', true);
+
+ /**
+ * Transparent objects like glass do not throw much shadow, enable this IR convenience flag with TRUE
+ * @var {x3dom.fields.SFBool} shadowExcludeTransparentObjects
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'shadowExcludeTransparentObjects', false);
+
+ /**
+ * The gamma correction to apply by default, see lighting and gamma tutorial
+ * @var {x3dom.fields.SFString} gammaCorrectionDefault
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue "none"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'gammaCorrectionDefault', "linear");
+
+ // boolean flags for feature (de)activation
+
+ /**
+ * If TRUE, objects outside the viewing frustum are ignored
+ * @var {x3dom.fields.SFBool} frustumCulling
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'frustumCulling', true);
+
+ /**
+ * If TRUE, objects smaller than the threshold below are ignored
+ * @var {x3dom.fields.SFBool} smallFeatureCulling
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'smallFeatureCulling', false);
+
+ /**
+ * Objects smaller than the threshold below are ignored
+ * @var {x3dom.fields.SFFloat} smallFeatureThreshold
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue 1.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'smallFeatureThreshold', 1.0);
+
+ // defaults can be >0 since only used upon activation
+
+ /**
+ * If TRUE and occlusion culling supported, objects occluding less than the threshold below are ignored
+ * @var {x3dom.fields.SFBool} occlusionCulling
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'occlusionCulling', false);
+
+ /**
+ * Objects occluding less than the threshold below are ignored
+ * @var {x3dom.fields.SFFloat} occlusionVisibilityThreshold
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue 0.0
+ * @range [0,1]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'occlusionVisibilityThreshold', 0.0);
+
+ // previously was scaleRenderedIdsOnMove; percentage of objects to be rendered, in [0,1]
+
+ /**
+ * If TRUE and occlusion culling supported, only threshold fraction of objects, sorted by their screen
+ * space coverage, are rendered
+ * @var {x3dom.fields.SFBool} lowPriorityCulling
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'lowPriorityCulling', false);
+
+ /**
+ * Only threshold fraction of objects, sorted by their screen space coverage, are rendered
+ * @var {x3dom.fields.SFFloat} lowPriorityThreshold
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue 1.0
+ * @range [0,1]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'lowPriorityThreshold', 1.0); // 1.0 means everything is rendered
+
+ // shape tesselation is lowered as long as resulting error is lower than threshold
+
+ /**
+ * If TRUE, shape tesselation is lowered as long as resulting error is lower than threshold
+ * @var {x3dom.fields.SFBool} tessellationDetailCulling
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'tessellationDetailCulling', false);
+
+ /**
+ * Shape tesselation is lowered as long as resulting error is lower than threshold
+ * @var {x3dom.fields.SFFloat} tessellationErrorThreshold
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue 0.0
+ * @range [0,1]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'tessellationErrorThreshold', 0.0);
+
+ /**
+ * Experimental: If true ARC adjusts rendering parameters
+ * @var {x3dom.fields.SFBool} enableARC
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'enableARC', false);
+
+ /**
+ * Experimental: Define minimal target frame-rate for static moments and quality-speed trade-off
+ * @var {x3dom.fields.SFFloat} minFrameRate
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue 1.0
+ * @range [1,inf]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'minFrameRate', 1.0);
+
+ /**
+ * Experimental: Define maximal target frame-rate for dynamic moments and quality-speed trade-off
+ * @var {x3dom.fields.SFFloat} maxFrameRate
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue 62.5
+ * @range [1,inf]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'maxFrameRate', 62.5);
+
+ // 4 exp. factors for controlling speed-performance trade-off
+ // factors could be in [0, 1] (and not evaluated if -1)
+
+ /**
+ * Experimenal: Factor of user data for controlling speed-performance trade-off
+ * @var {x3dom.fields.SFFloat} userDataFactor
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue -1
+ * @range [0,1] or -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'userDataFactor', -1);
+
+ /**
+ * Experimenal: Factor of small feature culling for controlling speed-performance trade-off
+ * @var {x3dom.fields.SFFloat} smallFeatureFactor
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue -1
+ * @range [0,1] or -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'smallFeatureFactor', -1);
+
+ /**
+ * Experimenal: Factor of occlusion culling for controlling speed-performance trade-off
+ * @var {x3dom.fields.SFFloat} occlusionVisibilityFactor
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue -1
+ * @range [0,1] or -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'occlusionVisibilityFactor', -1);
+
+ /**
+ * Experimenal: Factor of low priority culling for controlling speed-performance trade-off
+ * @var {x3dom.fields.SFFloat} lowPriorityFactor
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue -1
+ * @range [0,1] or -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'lowPriorityFactor', -1);
+
+ /**
+ * Experimenal: Factor of tesselation error for controlling speed-performance trade-off
+ * @var {x3dom.fields.SFFloat} tessellationErrorFactor
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue -1
+ * @range [0,1] or -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'tessellationErrorFactor', -1);
+
+ /**
+ * Flag to enable Screen Space Ambient Occlusion
+ * @var {x3dom.fields.SFBool} SSAO
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue "false"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'SSAO', false);
+
+ /**
+ * Value that determines the radius in which the SSAO is sampled in world space
+ * @var {x3dom.fields.SFFloat} SSAOradius
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue "4"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'SSAOradius',0.7);
+
+ /**
+ * Value that determines the amount of contribution of SSAO (from 0 to 1)
+ * @var {x3dom.fields.SFFloat} SSAOamount
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue "1.0"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'SSAOamount',0.3);
+
+ /**
+ * Value that determines the size of the random texture used for sparse sampling of SSAO
+ * @var {x3dom.fields.SFFloat} SSAOrandomTextureSize
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue "4"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'SSAOrandomTextureSize',4);
+
+ /**
+ * Value that determines the maximum depth difference for the SSAO blurring pass.
+ * Pixels with higher depth difference to the filer kernel center are not incorporated into the average.
+ * @var {x3dom.fields.SFFloat} SSAOblurDepthTreshold
+ * @memberof x3dom.nodeTypes.Environment
+ * @initvalue "5"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'SSAOblurDepthTreshold',1);
+
+ this._validGammaCorrectionTypes = [
+ "none", "fastlinear", "linear"
+ ];
+
+ // init internal stuff (but should be called each frame)
+ this.checkSanity();
+
+ },
+ {
+ checkSanity: function()
+ {
+ var checkParam = function(flag, value, defaultOn, defaultOff)
+ {
+ if(flag && (value == defaultOff))
+ return defaultOn;
+
+ if(!flag && (value != defaultOff))
+ return defaultOff;
+ return value;
+ };
+
+ this._smallFeatureThreshold = checkParam(this._vf.smallFeatureCulling,
+ this._vf.smallFeatureThreshold, 10, 0); // cull objects < 10 px
+ this._lowPriorityThreshold = checkParam(this._vf.lowPriorityCulling,
+ this._vf.lowPriorityThreshold, 0.5, 1); // 1 means 100% visible
+ this._occlusionVisibilityThreshold = checkParam(this._vf.occlusionCulling,
+ this._vf.occlusionVisibilityThreshold, 1, 0);
+ this._tessellationErrorThreshold = checkParam(this._vf.tessellationDetailCulling,
+ this._vf.tessellationErrorThreshold, 1, 0);
+
+ var checkGamma = function(field, that) {
+ field = field.toLowerCase();
+
+ if (that._validGammaCorrectionTypes.indexOf(field) > -1) {
+ return field;
+ }
+ else {
+ x3dom.debug.logWarning(field + " gammaCorrectionDefault may only be linear (default), fastLinear, or none");
+ return that._validGammaCorrectionTypes[0];
+ }
+ };
+
+ this._vf.gammaCorrectionDefault = checkGamma(this._vf.gammaCorrectionDefault, this);
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DViewpointNode ### */
+x3dom.registerNodeType(
+ "X3DViewpointNode",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DBindableNode,
+
+ /**
+ * Constructor for X3DViewpointNode
+ * @constructs x3dom.nodeTypes.X3DViewpointNode
+ * @x3d 3.3
+ * @component Navigation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DBindableNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc A node of node type X3DViewpointNode defines a specific location in the local coordinate system from which the user may view the scene.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DViewpointNode.superClass.call(this, ctx);
+
+ // attach some convenience accessor methods to dom/xml node
+ if (ctx && ctx.xmlNode) {
+ var domNode = ctx.xmlNode;
+
+ if (!domNode.resetView && !domNode.getFieldOfView &&
+ !domNode.getNear && !domNode.getFar)
+ {
+ domNode.resetView = function() {
+ var that = this._x3domNode;
+
+ that.resetView();
+ that._nameSpace.doc.needRender = true;
+ };
+
+ domNode.getFieldOfView = function() {
+ return this._x3domNode.getFieldOfView();
+ };
+
+ domNode.getNear = function() {
+ return this._x3domNode.getNear();
+ };
+
+ domNode.getFar = function() {
+ return this._x3domNode.getFar();
+ };
+ }
+ }
+
+ },
+ {
+ activate: function (prev) {
+ var viewarea = this._nameSpace.doc._viewarea;
+ if (prev) {
+ viewarea.animateTo(this, prev._autoGen ? null : prev);
+ }
+ viewarea._needNavigationMatrixUpdate = true;
+
+ x3dom.nodeTypes.X3DBindableNode.prototype.activate.call(this, prev);
+ //x3dom.debug.logInfo ('activate ViewBindable ' + this._DEF + '/' + this._vf.description);
+ },
+
+ deactivate: function (prev) {
+ x3dom.nodeTypes.X3DBindableNode.prototype.deactivate.call(this, prev);
+ //x3dom.debug.logInfo ('deactivate ViewBindable ' + this._DEF + '/' + this._vf.description);
+ },
+
+ getTransformation: function() {
+ return this.getCurrentTransform();
+ },
+
+ getCenterOfRotation: function() {
+ return new x3dom.fields.SFVec3f(0, 0, 0);
+ },
+
+ setCenterOfRotation: function(cor) {
+ this._vf.centerOfRotation.setValues(cor); // method overwritten by Viewfrustum
+ },
+
+ getFieldOfView: function() {
+ return 1.57079633;
+ },
+
+ /**
+ * Sets the (local) view matrix
+ * @param newView
+ */
+ setView: function(newView) {
+ var mat = this.getCurrentTransform();
+ this._viewMatrix = newView.mult(mat);
+ },
+
+ /**
+ * Sets an absolute view matrix in world coordinates
+ * @param newView
+ */
+ setViewAbsolute: function(newView)
+ {
+ this._viewMatrix = newView
+ },
+
+ setProjectionMatrix: function(matrix)
+ {
+
+ },
+
+ resetView: function() {
+ // see derived class
+ },
+
+ getNear: function() {
+ return 0.1;
+ },
+
+ getFar: function() {
+ return 10000;
+ },
+
+ getImgPlaneHeightAtDistOne: function() {
+ return 2.0;
+ },
+
+ getViewMatrix: function() {
+ return null;
+ },
+
+ getProjectionMatrix: function(aspect) {
+ return null;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Viewpoint ### */
+x3dom.registerNodeType(
+ "Viewpoint",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DViewpointNode,
+
+ /**
+ * Constructor for Viewpoint
+ * @constructs x3dom.nodeTypes.Viewpoint
+ * @x3d 3.3
+ * @component Navigation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DViewpointNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Viewpoint provides a specific location and direction where the user may view the scene.
+ * The principalPoint extention allows to set asymmetric frustums.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Viewpoint.superClass.call(this, ctx);
+
+
+ /**
+ * Preferred minimum viewing angle from this viewpoint in radians.
+ * Small field of view roughly corresponds to a telephoto lens, large field of view roughly corresponds to a wide-angle lens.
+ * Hint: modifying Viewpoint distance to object may be better for zooming.
+ * Warning: fieldOfView may not be correct for different window sizes and aspect ratios.
+ * Interchange profile hint: this field may be ignored.
+ * @var {x3dom.fields.SFFloat} fieldOfView
+ * @range [0, pi]
+ * @memberof x3dom.nodeTypes.Viewpoint
+ * @initvalue 0.785398
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'fieldOfView', 0.785398);
+
+ /**
+ * The position fields of the Viewpoint node specifies a relative location in the local coordinate system. Position is relative to the coordinate system's origin (0,0,0),
+ * @var {x3dom.fields.SFVec3f} position
+ * @memberof x3dom.nodeTypes.Viewpoint
+ * @initvalue 0,0,10
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'position', 0, 0, 10);
+
+ /**
+ * The orientation fields of the Viewpoint node specifies relative orientation to the default orientation.
+ * @var {x3dom.fields.SFRotation} orientation
+ * @memberof x3dom.nodeTypes.Viewpoint
+ * @initvalue 0,0,0,1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'orientation', 0, 0, 0, 1);
+
+ /**
+ * The centerOfRotation field specifies a center about which to rotate the user's eyepoint when in EXAMINE mode.
+ * @var {x3dom.fields.SFVec3f} centerOfRotation
+ * @memberof x3dom.nodeTypes.Viewpoint
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'centerOfRotation', 0, 0, 0);
+
+ /**
+ * Specifies the near plane.
+ * @var {x3dom.fields.SFFloat} zNear
+ * @range -1 or [0, inf]
+ * @memberof x3dom.nodeTypes.Viewpoint
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zNear', -1); //0.1);
+
+ /**
+ * Specifies the far plane.
+ * @var {x3dom.fields.SFFloat} zFar
+ * @range -1 or [0, inf]
+ * @memberof x3dom.nodeTypes.Viewpoint
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zFar', -1); //100000);
+
+ //this._viewMatrix = this._vf.orientation.toMatrix().transpose().
+ // mult(x3dom.fields.SFMatrix4f.translation(this._vf.position.negate()));
+ this._viewMatrix = x3dom.fields.SFMatrix4f.translation(this._vf.position).
+ mult(this._vf.orientation.toMatrix()).inverse();
+
+ this._projMatrix = null;
+ this._lastAspect = 1.0;
+
+ // z-ratio: a value around 5000 would be better...
+ this._zRatio = 10000;
+ this._zNear = this._vf.zNear;
+ this._zFar = this._vf.zFar;
+
+ // special stuff...
+ this._imgPlaneHeightAtDistOne = 2.0 * Math.tan(this._vf.fieldOfView / 2.0);
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName == "position" || fieldName == "orientation") {
+ this.resetView();
+ }
+ else if (fieldName == "fieldOfView" ||
+ fieldName == "zNear" || fieldName == "zFar") {
+ this._projMatrix = null; // only trigger refresh
+ this._zNear = this._vf.zNear;
+ this._zFar = this._vf.zFar;
+ this._imgPlaneHeightAtDistOne = 2.0 * Math.tan(this._vf.fieldOfView / 2.0);
+ }
+ else if (fieldName.indexOf("bind") >= 0) {
+ // FIXME; call parent.fieldChanged();
+ this.bind(this._vf.bind);
+ }
+ },
+
+ setProjectionMatrix: function(matrix)
+ {
+ this._projMatrix = matrix;
+ },
+
+ getCenterOfRotation: function() {
+ return this._vf.centerOfRotation;
+ },
+
+ getViewMatrix: function() {
+ return this._viewMatrix;
+ },
+
+ getFieldOfView: function() {
+ return this._vf.fieldOfView;
+ },
+
+ resetView: function() {
+ this._viewMatrix = x3dom.fields.SFMatrix4f.translation(this._vf.position).
+ mult(this._vf.orientation.toMatrix()).inverse();
+ },
+
+ getNear: function() {
+ return this._zNear;
+ },
+
+ getFar: function() {
+ return this._zFar;
+ },
+
+ getImgPlaneHeightAtDistOne: function() {
+ return this._imgPlaneHeightAtDistOne;
+ },
+
+ getProjectionMatrix: function(aspect)
+ {
+ var fovy = this._vf.fieldOfView;
+ var zfar = this._vf.zFar;
+ var znear = this._vf.zNear;
+
+ if (znear <= 0 || zfar <= 0)
+ {
+ var nearScale = 0.8, farScale = 1.2;
+ var viewarea = this._nameSpace.doc._viewarea;
+ var scene = viewarea._scene;
+
+ // Doesn't work if called e.g. from RenderedTexture with different sub-scene
+ var min = x3dom.fields.SFVec3f.copy(scene._lastMin);
+ var max = x3dom.fields.SFVec3f.copy(scene._lastMax);
+
+ var dia = max.subtract(min);
+ var sRad = dia.length() / 2;
+
+ var mat = viewarea.getViewMatrix().inverse();
+ var vp = mat.e3();
+
+ // account for scales around the viewpoint
+ var translation = new x3dom.fields.SFVec3f(0,0,0),
+ scaleFactor = new x3dom.fields.SFVec3f(1,1,1);
+ var rotation = new x3dom.fields.Quaternion(0,0,1,0),
+ scaleOrientation = new x3dom.fields.Quaternion(0,0,1,0);
+
+ // unfortunately, decompose is a rather expensive operation
+ mat.getTransform(translation, rotation, scaleFactor, scaleOrientation);
+
+ var minScal = scaleFactor.x, maxScal = scaleFactor.x;
+
+ if (maxScal < scaleFactor.y) maxScal = scaleFactor.y;
+ if (minScal > scaleFactor.y) minScal = scaleFactor.y;
+ if (maxScal < scaleFactor.z) maxScal = scaleFactor.z;
+ if (minScal > scaleFactor.z) minScal = scaleFactor.z;
+
+ if (maxScal > 1)
+ nearScale /= maxScal;
+ else if (minScal > x3dom.fields.Eps && minScal < 1)
+ farScale /= minScal;
+ // near/far scale adaption done
+
+ var sCenter = min.add(dia.multiply(0.5));
+ var vDist = (vp.subtract(sCenter)).length();
+
+ if (sRad) {
+ if (vDist > sRad)
+ znear = (vDist - sRad) * nearScale; // Camera outside scene
+ else
+ znear = 0; // Camera inside scene
+
+ zfar = (vDist + sRad) * farScale;
+ }
+ else {
+ znear = 0.1;
+ zfar = 100000;
+ }
+
+ var zNearLimit = zfar / this._zRatio;
+ znear = Math.max(znear, Math.max(x3dom.fields.Eps, zNearLimit));
+
+ if (zfar > this._vf.zNear && this._vf.zNear > 0)
+ znear = this._vf.zNear;
+ if (this._vf.zFar > znear)
+ zfar = this._vf.zFar;
+
+ if (zfar <= znear)
+ zfar = znear + 1;
+ //x3dom.debug.logInfo("near: " + znear + " -> far:" + zfar);
+ }
+
+ if (this._projMatrix == null)
+ {
+ this._projMatrix = x3dom.fields.SFMatrix4f.perspective(fovy, aspect, znear, zfar);
+ }
+ else if (this._zNear != znear || this._zFar != zfar)
+ {
+ var div = znear - zfar;
+ this._projMatrix._22 = (znear + zfar) / div;
+ this._projMatrix._23 = 2 * znear * zfar / div;
+ }
+ else if (this._lastAspect != aspect)
+ {
+ this._projMatrix._00 = (1 / Math.tan(fovy / 2)) / aspect;
+ this._lastAspect = aspect;
+ }
+
+ // also needed for being able to ask for near and far
+ this._zNear = znear;
+ this._zFar = zfar;
+
+ return this._projMatrix;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### OrthoViewpoint ### */
+x3dom.registerNodeType(
+ "OrthoViewpoint",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DViewpointNode,
+
+ /**
+ * Constructor for OrthoViewpoint
+ * @constructs x3dom.nodeTypes.OrthoViewpoint
+ * @x3d 3.3
+ * @component Navigation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DViewpointNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The OrthoViewpoint node defines a viewpoint that provides an orthographic view of the scene.
+ * An orthographic view is one in which all projectors are parallel to the projector from centerOfRotation to position.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.OrthoViewpoint.superClass.call(this, ctx);
+
+
+ /**
+ * The fieldOfView field specifies minimum and maximum extents of the view in units of the local coordinate system
+ * @var {x3dom.fields.MFFloat} fieldOfView
+ * @memberof x3dom.nodeTypes.OrthoViewpoint
+ * @initvalue [-1,-1,1,1]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'fieldOfView', [-1, -1, 1, 1]);
+
+ /**
+ * Position (x, y, z in meters) relative to local coordinate system.
+ * @var {x3dom.fields.SFVec3f} position
+ * @memberof x3dom.nodeTypes.OrthoViewpoint
+ * @initvalue 0,0,10
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'position', 0, 0, 10);
+
+ /**
+ * Rotation (axis, angle in radians) of Viewpoint, relative to default -Z axis direction in local coordinate system.
+ * Hint: this is orientation _change_ from default direction (0 0 -1).
+ * Hint: complex rotations can be accomplished axis-by-axis using parent Transforms.
+ * @var {x3dom.fields.SFRotation} orientation
+ * @range [-1, 1] or [-inf, inf]
+ * @memberof x3dom.nodeTypes.OrthoViewpoint
+ * @initvalue 0,0,0,1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'orientation', 0, 0, 0, 1);
+
+ /**
+ * centerOfRotation point relates to NavigationInfo EXAMINE mode.
+ * @var {x3dom.fields.SFVec3f} centerOfRotation
+ * @memberof x3dom.nodeTypes.OrthoViewpoint
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'centerOfRotation', 0, 0, 0);
+
+ /**
+ * z-near position; used for clipping
+ * @var {x3dom.fields.SFFloat} zNear
+ * @memberof x3dom.nodeTypes.OrthoViewpoint
+ * @initvalue 0.1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zNear', 0.1);
+
+ /**
+ * z-far position; used for clipping
+ * @var {x3dom.fields.SFFloat} zFar
+ * @memberof x3dom.nodeTypes.OrthoViewpoint
+ * @initvalue 10000
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'zFar', 10000);
+
+ this._viewMatrix = null;
+ this._projMatrix = null;
+ this._lastAspect = 1.0;
+
+ this.resetView();
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName == "position" || fieldName == "orientation") {
+ this.resetView();
+ }
+ else if (fieldName == "fieldOfView" ||
+ fieldName == "zNear" || fieldName == "zFar") {
+ this._projMatrix = null; // trigger refresh
+ this.resetView();
+ }
+ else if (fieldName.indexOf("bind") >= 0) {
+ this.bind(this._vf.bind);
+ }
+ },
+
+ getCenterOfRotation: function() {
+ return this._vf.centerOfRotation;
+ },
+
+ getViewMatrix: function() {
+ return this._viewMatrix;
+ },
+
+ resetView: function() {
+ var offset = x3dom.fields.SFMatrix4f.translation(new x3dom.fields.SFVec3f(
+ (this._vf.fieldOfView[0] + this._vf.fieldOfView[2]) / 2,
+ (this._vf.fieldOfView[1] + this._vf.fieldOfView[3]) / 2, 0));
+
+ this._viewMatrix = x3dom.fields.SFMatrix4f.translation(this._vf.position).
+ mult(this._vf.orientation.toMatrix());
+ this._viewMatrix = this._viewMatrix.mult(offset).inverse();
+ },
+
+ getNear: function() {
+ return this._vf.zNear;
+ },
+
+ getFar: function() {
+ return this._vf.zFar;
+ },
+
+ getProjectionMatrix: function(aspect)
+ {
+ if (this._projMatrix == null || this._lastAspect != aspect)
+ {
+ var near = this.getNear();
+ var far = this.getFar();
+
+ var left = this._vf.fieldOfView[0];
+ var bottom = this._vf.fieldOfView[1];
+ var right = this._vf.fieldOfView[2];
+ var top = this._vf.fieldOfView[3];
+
+ this._projMatrix = x3dom.fields.SFMatrix4f.ortho(left, right, bottom, top, near, far, aspect);
+ }
+ this._lastAspect = aspect;
+
+ return this._projMatrix;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Viewfrustum ### */
+x3dom.registerNodeType(
+ "Viewfrustum",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DViewpointNode,
+
+ /**
+ * Constructor for Viewfrustum
+ * @constructs x3dom.nodeTypes.Viewfrustum
+ * @x3d x.x
+ * @component Navigation
+ * @extends x3dom.nodeTypes.X3DViewpointNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Viewfrustum node allows to define a camera position and projection utilizing a standard OpenGL projection/modelview pair.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Viewfrustum.superClass.call(this, ctx);
+
+
+ /**
+ * Camera modelview matrix
+ * @var {x3dom.fields.SFMatrix4f} modelview
+ * @memberof x3dom.nodeTypes.Viewfrustum
+ * @initvalue 1,0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFMatrix4f(ctx, 'modelview',
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+
+ /**
+ * Camera projection matrix
+ * @var {x3dom.fields.SFMatrix4f} projection
+ * @memberof x3dom.nodeTypes.Viewfrustum
+ * @initvalue 1,0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFMatrix4f(ctx, 'projection',
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+
+ this._viewMatrix = this._vf.modelview.transpose().inverse();
+ this._projMatrix = this._vf.projection.transpose();
+
+ this._centerOfRotation = new x3dom.fields.SFVec3f(0, 0, 0);
+ // FIXME; derive near/far from current matrix, if requested!
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName == "modelview") {
+ this.resetView();
+ }
+ else if (fieldName == "projection") {
+ this._projMatrix = this._vf.projection.transpose();
+ }
+ else if (fieldName.indexOf("bind") >= 0) {
+ this.bind(this._vf.bind);
+ }
+ },
+
+ getCenterOfRotation: function() {
+ return this._centerOfRotation; // this field is only a little helper for examine mode
+ },
+
+ setCenterOfRotation: function(cor) {
+ this._centerOfRotation.setValues(cor); // update internal helper field
+ },
+
+ getViewMatrix: function() {
+ return this._viewMatrix;
+ },
+
+ getFieldOfView: function() {
+ return (2.0 * Math.atan(1.0 / this._projMatrix._11));
+ },
+
+ getImgPlaneHeightAtDistOne: function() {
+ return 2.0 / this._projMatrix._11;
+ },
+
+ resetView: function() {
+ this._viewMatrix = this._vf.modelview.transpose().inverse();
+ this._centerOfRotation = new x3dom.fields.SFVec3f(0, 0, 0); // reset helper, too
+ },
+
+ getProjectionMatrix: function(aspect) {
+ return this._projMatrix;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DNavigationInfoNode ### */
+x3dom.registerNodeType(
+ "X3DNavigationInfoNode",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DBindableNode,
+
+ /**
+ * Constructor for X3DNavigationInfoNode
+ * @constructs x3dom.nodeTypes.X3DNavigationInfoNode
+ * @x3d x.x
+ * @component Navigation
+ * @extends x3dom.nodeTypes.X3DBindableNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DNavigationInfoNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### NavigationInfo ### */
+x3dom.registerNodeType(
+ "NavigationInfo",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DNavigationInfoNode,
+
+ /**
+ * Constructor for NavigationInfo
+ * @constructs x3dom.nodeTypes.NavigationInfo
+ * @x3d 3.3
+ * @component Navigation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DNavigationInfoNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc NavigationInfo describes the viewing model and physical characteristics of the viewer's avatar.
+ * Hint: for inspection of simple objects, usability often improves with type='EXAMINE' 'ANY' Hint: NavigationInfo types ''WALK' 'FLY'' support camera-to-object collision detection.
+ * Background, Fog, NavigationInfo, TextureBackground and Viewpoint are bindable nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.NavigationInfo.superClass.call(this, ctx);
+
+
+ /**
+ * Enable/disable directional light that always points in the direction the user is looking.
+ * @var {x3dom.fields.SFBool} headlight
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'headlight', true);
+
+ /**
+ * defines the navigation type
+ * @var {x3dom.fields.MFString} type
+ * @range {"ANY","WALK","EXAMINE","FLY","LOOKAT","NONE","EXPLORE",...}
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue ["EXAMINE","ANY"]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'type', ["EXAMINE","ANY"]);
+
+ /**
+ * Specifies the view angle and height for helicopter mode and min/max rotation angle for turntable in ]0, PI[, starting from +y (0) down to -y (PI)
+ * @var {x3dom.fields.MFFloat} typeParams
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue [-0.4,60,0.05,2.8]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'typeParams', [-0.4, 60, 0.05, 2.8]);
+
+ /**
+ * allows restricting examine and turntable navigation, overrides mouse buttons (useful for special viewers)
+ * @range [all, pan, zoom, rotate, none]
+ * @var {x3dom.fields.SFString} explorationMode
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue 'all'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'explorationMode', 'all');
+ // TODO; use avatarSize + visibilityLimit for projection matrix (near/far)
+
+ /**
+ * avatarSize triplet values are:
+ * (a) collision distance between user and geometry (near culling plane of the view frustrum)
+ * (b) viewer height above terrain
+ * (c) tallest height viewer can WALK over.
+ * Hint: keep (avatarSize.CollisionDistance / visibilityLimit) less then; 10,000 to avoid aliasing artifacts (i.e. polygon 'tearing').
+ * Interchange profile hint: this field may be ignored.
+ * @var {x3dom.fields.MFFloat} avatarSize
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue [0.25,1.6,0.75]
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'avatarSize', [0.25, 1.6, 0.75]);
+
+ /**
+ * Geometry beyond the visibilityLimit may not be rendered (far culling plane of the view frustrum).
+ * visibilityLimit=0.0 indicates an infinite visibility limit.
+ * Hint: keep visibilityLimit greater than zero.
+ * Hint: keep (avatarSize.CollisionDistance / visibilityLimit) less than 10,000 to avoid aliasing artifacts (i.e. polygon 'tearing').
+ * Interchange profile hint: this field may be ignored.
+ * @var {x3dom.fields.SFFloat} visibilityLimit
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue 0.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'visibilityLimit', 0.0);
+
+ /**
+ * Default rate at which viewer travels through scene, meters/second.
+ * Warning: default 1 m/s usually seems slow for ordinary navigation.
+ * Interchange profile hint: this field may be ignored.
+ * @var {x3dom.fields.SFFloat} speed
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'speed', 1.0);
+ // for 'jumping' between viewpoints (bind transition time)
+
+ /**
+ * The transitionTime field specifies the duration of any viewpoint transition
+ * @var {x3dom.fields.SFTime} transitionTime
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'transitionTime', 1.0);
+
+ /**
+ * Specifies the transition mode.
+ * @var {x3dom.fields.MFString} transitionType
+ * @range [LINEAR, TELEPORT, ANIMATE, ...]
+ * @memberof x3dom.nodeTypes.NavigationInfo
+ * @initvalue ["LINEAR"]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'transitionType', ["LINEAR"]);
+
+ this._validTypes = [
+ "none", "examine", "turntable",
+ "fly", "freefly", "lookat", "lookaround",
+ "walk", "game", "helicopter", "any"
+ ];
+ this._heliUpdated = false;
+
+ var type = this.checkType(this.getType());
+ x3dom.debug.logInfo("NavType: " + type);
+
+ },
+ {
+ fieldChanged: function(fieldName) {
+ if (fieldName == "typeParams") {
+ this._heliUpdated = false;
+ }
+ else if (fieldName == "type") {
+ var type = this.checkType(this.getType());
+
+ switch (type) {
+ case 'game':
+ this._nameSpace.doc._viewarea.initMouseState();
+ break;
+ case 'helicopter':
+ this._heliUpdated = false;
+ break;
+ case "turntable":
+ this._nameSpace.doc._viewarea.initMouseState();
+ this._nameSpace.doc._viewarea.initTurnTable(this);
+ break;
+ default:
+ break;
+ }
+
+ this._vf.type[0] = type;
+ x3dom.debug.logInfo("Switch to " + type + " mode.");
+ }
+ },
+
+ setType: function(type, viewarea) {
+ var navType = this.checkType(type.toLowerCase());
+ var oldType = this.checkType(this.getType());
+
+ switch (navType) {
+ case 'game':
+ if (oldType !== navType) {
+ if (viewarea)
+ viewarea.initMouseState();
+ else
+ this._nameSpace.doc._viewarea.initMouseState();
+ }
+ break;
+ case 'helicopter':
+ if (oldType !== navType) {
+ this._heliUpdated = false;
+ }
+ break;
+ case "turntable":
+ if (oldType !== navType) {
+ if (viewarea) {
+ viewarea.initMouseState();
+ viewarea.initTurnTable(this);
+ }
+ else {
+ this._nameSpace.doc._viewarea.initMouseState();
+ this._nameSpace.doc._viewarea.initTurnTable(this);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ this._vf.type[0] = navType;
+ x3dom.debug.logInfo("Switch to " + navType + " mode.");
+ },
+
+ getType: function() {
+ var type = this._vf.type[0].toLowerCase();
+ // FIXME; the following if's aren't nice!
+ if (type.length <= 1)
+ type = "none";
+ else if (type == "any")
+ type = "examine";
+ return type;
+ },
+
+ getTypeParams: function() {
+ var length = this._vf.typeParams.length;
+
+ var theta = (length >= 1) ? this._vf.typeParams[0] : -0.4;
+ var height = (length >= 2) ? this._vf.typeParams[1] : 60.0;
+ var minAngle = (length >= 3) ? this._vf.typeParams[2] : x3dom.fields.Eps;
+ var maxAngle = (length >= 4) ? this._vf.typeParams[3] : Math.PI - x3dom.fields.Eps;
+
+ // experimental HACK to switch between clamp to CoR (params[4]>0) and CoR translation in turntable mode
+ var params = [theta, height, minAngle, maxAngle];
+ if (length >= 5)
+ {
+ params.push(this._vf.typeParams[4]);
+ }
+ return params;
+ },
+
+ setTypeParams: function(params) {
+ for (var i=0; i<params.length; i++) {
+ this._vf.typeParams[i] = params[i];
+ }
+ },
+
+ checkType: function(type) {
+ if (this._validTypes.indexOf(type) > -1) {
+ return type;
+ }
+ else {
+ x3dom.debug.logWarning(type + " is no valid navigation type, use one of " +
+ this._validTypes.toString());
+ return "examine";
+ }
+ },
+
+ getExplorationMode: function() {
+ switch (this._vf.explorationMode.toLowerCase()) {
+ case "all": return 7;
+ case "rotate": return 1; //left btn
+ case "zoom": return 2; //right btn
+ case "pan": return 4; //middle btn
+ case "none": return 0; //type 'none'
+ default: return 7;
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Billboard ### */
+x3dom.registerNodeType(
+ "Billboard",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Billboard
+ * @constructs x3dom.nodeTypes.Billboard
+ * @x3d 3.3
+ * @component Navigation
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Billboard is a Grouping node that can contain most nodes.
+ * Content faces the user, rotating about the specified axis. Set axisOfRotation=0 0 0 to fully face the user's camera.
+ * Hint: Put Billboard as close to the geometry as possible, nested inside Transform for local coordinate system.
+ * Hint: don't put Viewpoint inside a Billboard.
+ * Hint: insert a Shape node before adding geometry or Appearance.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Billboard.superClass.call(this, ctx);
+
+ /**
+ * axisOfRotation direction is relative to local coordinate system. Hint: axis 0 0 0 always faces viewer.
+ * @var {x3dom.fields.SFVec3f} axisOfRotation
+ * @memberof x3dom.nodeTypes.Billboard
+ * @initvalue 0,1,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'axisOfRotation', 0, 1, 0);
+
+ this._eye = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._eyeViewUp = new x3dom.fields.SFVec3f(0, 0, 0);
+ this._eyeLook = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ },
+ {
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ planeMask = drawableCollection.cull(transform, this.graphState(), singlePath, planeMask);
+ if (planeMask <= 0) {
+ return;
+ }
+
+ // no caching later on as transform changes almost every frame anyway
+ singlePath = false;
+
+ var vol = this.getVolume();
+
+ var min = x3dom.fields.SFVec3f.MAX();
+ var max = x3dom.fields.SFVec3f.MIN();
+ vol.getBounds(min, max);
+
+ var mat_view = drawableCollection.viewMatrix;
+
+ var center = new x3dom.fields.SFVec3f(0, 0, 0); // eye
+ center = mat_view.inverse().multMatrixPnt(center);
+
+ var mat_view_model = mat_view.mult(transform);
+ this._eye = transform.inverse().multMatrixPnt(center);
+ this._eyeViewUp = new x3dom.fields.SFVec3f(mat_view_model._10, mat_view_model._11, mat_view_model._12);
+ this._eyeLook = new x3dom.fields.SFVec3f(mat_view_model._20, mat_view_model._21, mat_view_model._22);
+
+ var rotMat = x3dom.fields.SFMatrix4f.identity();
+ var mid = max.add(min).multiply(0.5);
+ var billboard_to_viewer = this._eye.subtract(mid);
+
+ if(this._vf.axisOfRotation.equals(new x3dom.fields.SFVec3f(0, 0, 0), x3dom.fields.Eps)) {
+ var rot1 = x3dom.fields.Quaternion.rotateFromTo(
+ billboard_to_viewer, new x3dom.fields.SFVec3f(0, 0, 1));
+ rotMat = rot1.toMatrix().transpose();
+
+ var yAxis = rotMat.multMatrixPnt(new x3dom.fields.SFVec3f(0, 1, 0)).normalize();
+ var zAxis = rotMat.multMatrixPnt(new x3dom.fields.SFVec3f(0, 0, 1)).normalize();
+
+ if(!this._eyeViewUp.equals(new x3dom.fields.SFVec3f(0, 0, 0), x3dom.fields.Eps)) {
+ // new local z-axis aligned with camera z-axis
+ var rot2 = x3dom.fields.Quaternion.rotateFromTo(this._eyeLook, zAxis);
+ // new: local y-axis rotated by rot2
+ var rotatedyAxis = rot2.toMatrix().transpose().multMatrixVec(yAxis);
+ // new: rotated local y-axis aligned with camera y-axis
+ var rot3 = x3dom.fields.Quaternion.rotateFromTo(this._eyeViewUp, rotatedyAxis);
+
+ rotMat = rot2.toMatrix().transpose().mult(rotMat);
+ rotMat = rot3.toMatrix().transpose().mult(rotMat);
+ }
+ }
+ else {
+ var normalPlane = this._vf.axisOfRotation.cross(billboard_to_viewer).normalize();
+
+ if(this._eye.z < 0) {
+ normalPlane = normalPlane.multiply(-1);
+ }
+
+ var degreesToRotate = Math.asin(normalPlane.dot(new x3dom.fields.SFVec3f(0, 0, 1)));
+
+ if(this._eye.z < 0) {
+ degreesToRotate += Math.PI;
+ }
+
+ rotMat = x3dom.fields.SFMatrix4f.parseRotation(
+ this._vf.axisOfRotation.x + ", " + this._vf.axisOfRotation.y + ", " +
+ this._vf.axisOfRotation.z + ", " + degreesToRotate*(-1));
+ }
+
+ var childTransform = this.transformMatrix(transform.mult(rotMat));
+
+ for (var i=0, i_n=this._childNodes.length; i<i_n; i++)
+ {
+ var cnode = this._childNodes[i];
+ if (cnode) {
+ cnode.collectDrawableObjects(childTransform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### Collision ###
+x3dom.registerNodeType(
+ "Collision",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for Collision
+ * @constructs x3dom.nodeTypes.Collision
+ * @x3d 3.3
+ * @component Navigation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Collision detects camera-to-object contact using current Viewpoint and NavigationInfo avatarSize.
+ * Collision is a Grouping node that handles collision detection for its children.
+ * Collision can contain a single proxy child node for substitute collision-detection geometry.
+ * Note: proxy geometry is not rendered.
+ * Note: PointSet, IndexedLineSet, LineSet and Text do not trigger collisions.
+ * Hint: improve performance using proxy for simpler contact-calculation geometry.
+ * Hint: NavigationInfo types ''WALK' 'FLY'' support camera-to-object collision detection.
+ * Hint: insert a Shape node before adding geometry or Appearance.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Collision.superClass.call(this, ctx);
+
+
+ /**
+ * Enables/disables collision detection for children and all descendants. Hint: former name quotecollidequote in VRML 97 specification.
+ * @var {x3dom.fields.SFBool} enabled
+ * @memberof x3dom.nodeTypes.Collision
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool (ctx, "enabled", true);
+
+ /**
+ * alternate object to be checked for collision, in place of the children of this node.
+ * @var {x3dom.fields.SFNode} proxy
+ * @memberof x3dom.nodeTypes.Collision
+ * @initvalue x3dom.nodeTypes.X3DGroupingNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode ("proxy", x3dom.nodeTypes.X3DGroupingNode);
+
+
+ // TODO; add Slots: collideTime, isActive
+ /**
+ * NOT YET IMPLEMENTED. The time of collision.
+ * @var {x3dom.fields.SFTime} collideTime
+ * @memberof x3dom.nodeTypes.Collision
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime (ctx, "collideTime", 0);
+
+ /**
+ * NOT YET IMPLEMENTED. The value of the isActive field indicates the current state of the Collision node.
+ * An isActive TRUE event is generated when a collision occurs. An isActive FALSE event is generated when a collision no longer occurs.
+ * @var {x3dom.fields.SFBool} isActive
+ * @memberof x3dom.nodeTypes.Collision
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool (ctx, "isActive", true);
+ },
+ {
+ collectDrawableObjects: function (transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ planeMask = drawableCollection.cull(transform, this.graphState(), singlePath, planeMask);
+ if (planeMask <= 0) {
+ return;
+ }
+
+ var cnode, childTransform;
+
+ if (singlePath) {
+ if (!this._graph.globalMatrix) {
+ this._graph.globalMatrix = this.transformMatrix(transform);
+ }
+ childTransform = this._graph.globalMatrix;
+ }
+ else {
+ childTransform = this.transformMatrix(transform);
+ }
+
+ for (var i=0, n=this._childNodes.length; i<n; i++)
+ {
+ if ((cnode = this._childNodes[i]) && (cnode !== this._cf.proxy.node)) {
+ cnode.collectDrawableObjects(childTransform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### X3DLODNode ###
+x3dom.registerNodeType(
+ "X3DLODNode",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DGroupingNode,
+
+ /**
+ * Constructor for X3DLODNode
+ * @constructs x3dom.nodeTypes.X3DLODNode
+ * @x3d x.x
+ * @component Navigation
+ * @extends x3dom.nodeTypes.X3DGroupingNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DLODNode.superClass.call(this, ctx);
+
+
+ /**
+ * The forceTransitions field specifies whether browsers are allowed to disregard level distances in order to provide better performance.
+ * @var {x3dom.fields.SFBool} forceTransitions
+ * @memberof x3dom.nodeTypes.X3DLODNode
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool (ctx, "forceTransitions", false);
+
+ /**
+ * The center field is a translation offset in the local coordinate system that specifies the centre of the LOD node for distance calculations.
+ * @var {x3dom.fields.SFVec3f} center
+ * @memberof x3dom.nodeTypes.X3DLODNode
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, "center", 0, 0, 0);
+
+ this._eye = new x3dom.fields.SFVec3f(0, 0, 0);
+
+ },
+ {
+ collectDrawableObjects: function(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ if (singlePath && (this._parentNodes.length > 1))
+ singlePath = false;
+
+ if (singlePath && (invalidateCache = invalidateCache || this.cacheInvalid()))
+ this.invalidateCache();
+
+ planeMask = drawableCollection.cull(transform, this.graphState(), singlePath, planeMask);
+ if (planeMask <= 0) {
+ return;
+ }
+
+ // at the moment, no caching here as children may change every frame
+ singlePath = false;
+
+ this.visitChildren(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+
+ //out.LODs.push( [transform, this] );
+ },
+
+ visitChildren: function(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes) {
+ // overwritten
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### LOD ###
+x3dom.registerNodeType(
+ "LOD",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DLODNode,
+
+ /**
+ * Constructor for LOD
+ * @constructs x3dom.nodeTypes.LOD
+ * @x3d 3.3
+ * @component Navigation
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DLODNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc LOD (Level Of Detail) uses camera-to-object distance to switch among contained child levels.
+ * (Contained nodes are now called 'children' rather than 'level', for consistent naming among all GroupingNodeType nodes.)
+ * LOD range values go from near to far (as child geometry gets simpler for better performance).
+ * For n range values, you must have n+1 children levels! Only the currently selected children level is rendered, but all levels continue to send/receive events.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.LOD.superClass.call(this, ctx);
+
+
+ /**
+ * Camera-to-object distance transitions for each child level, where range values go from near to far. For n range values, you must have n+1 child levels! Hint: can add an empty Group node as nonrendering final child.
+ * @var {x3dom.fields.MFFloat} range
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.LOD
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, "range", []);
+
+ this._lastRangePos = -1;
+
+ },
+ {
+ visitChildren: function(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ var i=0, n=this._childNodes.length;
+
+ var mat_view = drawableCollection.viewMatrix;
+
+ var center = new x3dom.fields.SFVec3f(0, 0, 0); // eye
+ center = mat_view.inverse().multMatrixPnt(center);
+
+ //transform eye point to the LOD node's local coordinate system
+ this._eye = transform.inverse().multMatrixPnt(center);
+
+ var len = this._vf.center.subtract(this._eye).length();
+
+ //calculate range check for viewer distance d (with range in local coordinates)
+ //N+1 children nodes for N range values (L0, if d < R0, ... Ln-1, if d >= Rn-1)
+ while (i < this._vf.range.length && len > this._vf.range[i]) {
+ i++;
+ }
+ if (i && i >= n) {
+ i = n - 1;
+ }
+ this._lastRangePos = i;
+
+ var cnode = this._childNodes[i];
+ if (n && cnode)
+ {
+ var childTransform = this.transformMatrix(transform);
+ cnode.collectDrawableObjects(childTransform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ },
+
+ getVolume: function()
+ {
+ var vol = this._graph.volume;
+
+ if (!this.volumeValid() && this._vf.render)
+ {
+ var child, childVol;
+
+ if (this._lastRangePos >= 0) {
+ child = this._childNodes[this._lastRangePos];
+
+ childVol = (child && child._vf.render === true) ? child.getVolume() : null;
+
+ if (childVol && childVol.isValid())
+ vol.extendBounds(childVol.min, childVol.max);
+ }
+ else { // first time we're here
+ for (var i=0, n=this._childNodes.length; i<n; i++)
+ {
+ if (!(child = this._childNodes[i]) || child._vf.render !== true)
+ continue;
+
+ childVol = child.getVolume();
+
+ if (childVol && childVol.isValid())
+ vol.extendBounds(childVol.min, childVol.max);
+ }
+ }
+ }
+
+ return vol;
+ },
+
+ nodeChanged: function() {
+ //this._needReRender = true;
+ this.invalidateVolume();
+ //this.invalidateCache();
+ },
+
+ fieldChanged: function(fieldName) {
+ //this._needReRender = true;
+ if (fieldName == "render" ||
+ fieldName == "center" ||
+ fieldName == "range") {
+ this.invalidateVolume();
+ //this.invalidateCache();
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+// ### DynamicLOD ###
+x3dom.registerNodeType(
+ "DynamicLOD",
+ "Navigation",
+ defineClass(x3dom.nodeTypes.X3DLODNode,
+
+ /**
+ * Constructor for DynamicLOD
+ * @constructs x3dom.nodeTypes.DynamicLOD
+ * @x3d x.x
+ * @component Navigation
+ * @extends x3dom.nodeTypes.X3DLODNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ */
+ function (ctx) {
+ x3dom.nodeTypes.DynamicLOD.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} subScale
+ * @memberof x3dom.nodeTypes.DynamicLOD
+ * @initvalue 0.5
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'subScale', 0.5);
+
+ /**
+ *
+ * @var {x3dom.fields.SFVec2f} size
+ * @memberof x3dom.nodeTypes.DynamicLOD
+ * @initvalue 2,2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'size', 2, 2);
+
+ /**
+ *
+ * @var {x3dom.fields.SFVec2f} subdivision
+ * @memberof x3dom.nodeTypes.DynamicLOD
+ * @initvalue 1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'subdivision', 1, 1);
+
+ /**
+ *
+ * @var {x3dom.fields.SFNode} root
+ * @memberof x3dom.nodeTypes.DynamicLOD
+ * @initvalue x3dom.nodeTypes.X3DShapeNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode ('root', x3dom.nodeTypes.X3DShapeNode);
+
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} urlHead
+ * @memberof x3dom.nodeTypes.DynamicLOD
+ * @initvalue "http://r"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'urlHead', "http://r");
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} urlCenter
+ * @memberof x3dom.nodeTypes.DynamicLOD
+ * @initvalue ".ortho.tiles.virtualearth.net/tiles/h"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'urlCenter', ".ortho.tiles.virtualearth.net/tiles/h");
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} urlTail
+ * @memberof x3dom.nodeTypes.DynamicLOD
+ * @initvalue ".png?g=-1"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'urlTail', ".png?g=-1");
+
+ this.rootGeometry = new x3dom.nodeTypes.Plane(ctx);
+ this.level = 0;
+ this.quadrant = 4;
+ this.cell = "";
+
+ },
+ {
+ nodeChanged: function()
+ {
+ var root = this._cf.root.node;
+
+ if (root == null || root._cf.geometry.node != null)
+ return;
+
+ this.rootGeometry._vf.size.setValues(this._vf.size);
+ this.rootGeometry._vf.subdivision.setValues(this._vf.subdivision);
+ this.rootGeometry._vf.center.setValues(this._vf.center);
+ this.rootGeometry.fieldChanged("subdivision"); // trigger update
+
+ this._cf.root.node.addChild(this.rootGeometry); // add to shape
+ this.rootGeometry.nodeChanged();
+
+ this._cf.root.node.nodeChanged();
+
+ this._nameSpace.doc.needRender = true;
+ },
+
+ visitChildren: function(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes)
+ {
+ var root = this._cf.root.node;
+
+ if (root == null)
+ return;
+
+ var mat_view = drawableCollection.viewMatrix;
+
+ var center = new x3dom.fields.SFVec3f(0, 0, 0); // eye
+ center = mat_view.inverse().multMatrixPnt(center);
+
+ //var mat_view_model = mat_view.mult(transform);
+ this._eye = transform.inverse().multMatrixPnt(center);
+
+ var l, len = this._vf.center.subtract(this._eye).length();
+
+ //calculate range check for viewer distance d (with range in local coordinates)
+ if (len > x3dom.fields.Eps && len * this._vf.subScale <= this._vf.size.length()) {
+ /* Quadrants per level: (TODO; make parameterizable, e.g. 0 and 1 might be swapped)
+ 0 | 1
+ -----
+ 2 | 3
+ */
+ if (this._childNodes.length <= 1) {
+ var offset = new Array(
+ new x3dom.fields.SFVec3f(-0.25*this._vf.size.x, 0.25*this._vf.size.y, 0),
+ new x3dom.fields.SFVec3f( 0.25*this._vf.size.x, 0.25*this._vf.size.y, 0),
+ new x3dom.fields.SFVec3f(-0.25*this._vf.size.x, -0.25*this._vf.size.y, 0),
+ new x3dom.fields.SFVec3f( 0.25*this._vf.size.x, -0.25*this._vf.size.y, 0)
+ );
+
+ for (l=0; l<4; l++) {
+ var node = new x3dom.nodeTypes.DynamicLOD();
+
+ node._nameSpace = this._nameSpace;
+ node._eye.setValues(this._eye);
+
+ node.level = this.level + 1;
+ node.quadrant = l;
+ node.cell = this.cell + l;
+
+ node._vf.urlHead = this._vf.urlHead;
+ node._vf.urlCenter = this._vf.urlCenter;
+ node._vf.urlTail = this._vf.urlTail;
+
+ node._vf.center = this._vf.center.add(offset[l]);
+ node._vf.size = this._vf.size.multiply(0.5);
+ node._vf.subdivision.setValues(this._vf.subdivision);
+
+ var app = new x3dom.nodeTypes.Appearance();
+
+ //var mat = new x3dom.nodeTypes.Material();
+ //mat._vf.diffuseColor = new x3dom.fields.SFVec3f(Math.random(),Math.random(),Math.random());
+ //
+ //app.addChild(mat);
+ //mat.nodeChanged();
+
+ var tex = new x3dom.nodeTypes.ImageTexture();
+ tex._nameSpace = this._nameSpace;
+ tex._vf.url[0] = this._vf.urlHead + node.quadrant + this._vf.urlCenter + node.cell + this._vf.urlTail;
+ //x3dom.debug.logInfo(tex._vf.url[0]);
+
+ app.addChild(tex);
+ tex.nodeChanged();
+
+ var shape = new x3dom.nodeTypes.Shape();
+ shape._nameSpace = this._nameSpace;
+
+ shape.addChild(app);
+ app.nodeChanged();
+
+ node.addChild(shape, "root");
+ shape.nodeChanged();
+
+ this.addChild(node);
+ node.nodeChanged();
+ }
+ }
+ else {
+ for (l=1; l<this._childNodes.length; l++) {
+ this._childNodes[l].collectDrawableObjects(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ }
+ }
+ else {
+ root.collectDrawableObjects(transform, drawableCollection, singlePath, invalidateCache, planeMask, clipPlanes);
+ }
+ },
+
+ getVolume: function() {
+ var vol = this._graph.volume;
+
+ if (!vol.isValid()) {
+ vol.min.setValues(this._vf.center);
+ vol.min.x -= 0.5 * this._vf.size.x;
+ vol.min.y -= 0.5 * this._vf.size.y;
+ vol.min.z -= x3dom.fields.Eps;
+
+ vol.max.setValues(this._vf.center);
+ vol.max.x += 0.5 * this._vf.size.x;
+ vol.max.y += 0.5 * this._vf.size.y;
+ vol.max.z += x3dom.fields.Eps;
+ }
+
+ return vol;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DFontStyleNode ### */
+x3dom.registerNodeType(
+ "X3DFontStyleNode",
+ "Text",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for X3DFontStyleNode
+ * @constructs x3dom.nodeTypes.X3DFontStyleNode
+ * @x3d 3.3
+ * @component Text
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base node type for all font style nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DFontStyleNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### FontStyle ### */
+x3dom.registerNodeType(
+ "FontStyle",
+ "Text",
+ defineClass(x3dom.nodeTypes.X3DFontStyleNode,
+
+ /**
+ * Constructor for FontStyle
+ * @constructs x3dom.nodeTypes.FontStyle
+ * @x3d 3.3
+ * @component Text
+ * @status full
+ * @extends x3dom.nodeTypes.X3DFontStyleNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The FontStyle node defines the size, family, and style used for Text nodes, as well as the direction of the text strings and any language-specific rendering techniques used for non-English text.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.FontStyle.superClass.call(this, ctx);
+
+
+ /**
+ * Defines the text family.
+ * @var {x3dom.fields.MFString} family
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue ['SERIF']
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'family', ['SERIF']);
+
+ /**
+ * Specifies whether the text is shown horizontally or vertically.
+ * @var {x3dom.fields.SFBool} horizontal
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'horizontal', true);
+
+ /**
+ * Specifies where the text is anchored.
+ * @var {x3dom.fields.MFString} justify
+ * @range ["BEGIN","END","FIRST","MIDDLE",""]
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue ['BEGIN']
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'justify', ['BEGIN']);
+
+ /**
+ * The language field specifies the context of the language for the text string in the form of a language and a country in which that language is used.
+ * @var {x3dom.fields.SFString} language
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue ""
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'language', "");
+
+ /**
+ * Specifies whether the text is shown from left to right or from right to left.
+ * @var {x3dom.fields.SFBool} leftToRight
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'leftToRight', true);
+
+ /**
+ * Sets the size of the text.
+ * @var {x3dom.fields.SFFloat} size
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'size', 1.0);
+
+ /**
+ * Sets the spacing between lines of text, relative to the text size.
+ * @var {x3dom.fields.SFFloat} spacing
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'spacing', 1.0);
+
+ /**
+ * Sets the text style.
+ * @var {x3dom.fields.SFString} style
+ * @range ["PLAIN","BOLD","ITALIC","BOLDITALIC",""]
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue "PLAIN"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'style', "PLAIN");
+
+ /**
+ * Specifies whether the text flows from top to bottom or from bottom to top.
+ * @var {x3dom.fields.SFBool} topToBottom
+ * @memberof x3dom.nodeTypes.FontStyle
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'topToBottom', true);
+
+ },
+ {
+ fieldChanged: function(fieldName) {
+ if (fieldName == 'family' || fieldName == 'horizontal' || fieldName == 'justify' ||
+ fieldName == 'language' || fieldName == 'leftToRight' || fieldName == 'size' ||
+ fieldName == 'spacing' || fieldName == 'style' || fieldName == 'topToBottom') {
+ Array.forEach(this._parentNodes, function (node) {
+ node.fieldChanged(fieldName);
+ });
+ }
+ }
+ }
+ )
+);
+
+x3dom.nodeTypes.FontStyle.defaultNode = function() {
+ if (!x3dom.nodeTypes.FontStyle._defaultNode) {
+ x3dom.nodeTypes.FontStyle._defaultNode = new x3dom.nodeTypes.FontStyle();
+ x3dom.nodeTypes.FontStyle._defaultNode.nodeChanged();
+ }
+ return x3dom.nodeTypes.FontStyle._defaultNode;
+};
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Text ### */
+x3dom.registerNodeType(
+ "Text",
+ "Text",
+ defineClass(x3dom.nodeTypes.X3DGeometryNode,
+
+ /**
+ * Constructor for Text
+ * @constructs x3dom.nodeTypes.Text
+ * @x3d 3.3
+ * @component Text
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Text node specifies a two-sided, flat text string object positioned in the Z=0 plane of the local coordinate system based on values defined in the fontStyle field.
+ * Text nodes may contain multiple text strings specified using the UTF-8 encoding.
+ * The text strings are stored in the order in which the text mode characters are to be produced as defined by the parameters in the FontStyle node.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Text.superClass.call(this, ctx);
+
+
+ /**
+ * The text strings are contained in the string field.
+ * @var {x3dom.fields.MFString} string
+ * @memberof x3dom.nodeTypes.Text
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'string', []);
+
+ /**
+ * The length field contains an MFFloat value that specifies the length of each text string in the local coordinate system.
+ * The length of each line of type is measured horizontally for horizontal text (FontStyle node: horizontal=TRUE) and vertically for vertical text (FontStyle node: horizontal=FALSE).
+ * @var {x3dom.fields.MFFloat} length
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Text
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'length', []);
+
+ /**
+ * The maxExtent field limits and compresses all of the text strings if the length of the maximum string is longer than the maximum extent, as measured in the local coordinate system. If the text string with the maximum length is shorter than the maxExtent, then there is no compressing.
+ * The maximum extent is measured horizontally for horizontal text (FontStyle node: horizontal=TRUE) and vertically for vertical text (FontStyle node: horizontal=FALSE).
+ * @var {x3dom.fields.SFFloat} maxExtent
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Text
+ * @initvalue 0.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'maxExtent', 0.0);
+
+ /**
+ * The fontStyle field contains one FontStyle node that specifies the font size, font family and style, direction of the text strings, and any specific language rendering techniques used for the text.
+ * @var {x3dom.fields.SFNode} fontStyle
+ * @memberof x3dom.nodeTypes.Text
+ * @initvalue x3dom.nodeTypes.X3DFontStyleNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode ('fontStyle', x3dom.nodeTypes.X3DFontStyleNode);
+
+ this._mesh._positions[0] = [];
+ this._mesh._normals[0] = [0,0,1, 0,0,1, 0,0,1, 0,0,1];
+ this._mesh._texCoords[0] = [0,0, 1,0, 1,1, 0,1];
+ this._mesh._colors[0] = [];
+ this._mesh._indices[0] = [0,1,2, 2,3,0];
+ this._mesh._invalidate = true;
+ this._mesh._numFaces = 2;
+ this._mesh._numCoords = 4;
+
+ },
+ {
+ nodeChanged: function() {
+ if (!this._cf.fontStyle.node) {
+ this.addChild(x3dom.nodeTypes.FontStyle.defaultNode());
+ }
+ this.invalidateVolume();
+ },
+
+ fieldChanged: function(fieldName) {
+ if (fieldName == 'string' || fieldName == 'length' || fieldName == 'maxExtent') {
+ this.invalidateVolume();
+ Array.forEach(this._parentNodes, function (node) {
+ node.setAllDirty();
+ });
+ }
+ }
+ }
+ ) // defineClass
+); // registerNodeType
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DSoundNode ### */
+x3dom.registerNodeType(
+ "X3DSoundNode",
+ "Sound",
+ defineClass(x3dom.nodeTypes.X3DChildNode,
+
+ /**
+ * Constructor for X3DSoundNode
+ * @constructs x3dom.nodeTypes.X3DSoundNode
+ * @x3d 3.3
+ * @component Sound
+ * @status full
+ * @extends x3dom.nodeTypes.X3DChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @CLASSDESC This abstract node type is the base for all sound nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DSoundNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Sound ### */
+x3dom.registerNodeType(
+ "Sound",
+ "Sound",
+ defineClass(x3dom.nodeTypes.X3DSoundNode,
+
+ /**
+ * Constructor for Sound
+ * @constructs x3dom.nodeTypes.Sound
+ * @x3d 3.3
+ * @component Sound
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DSoundNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Sound node specifies the spatial presentation of a sound in a X3D scene.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Sound.superClass.call(this, ctx);
+
+
+ /**
+ * The source field specifies the sound source for the Sound node. If the source field is not specified, the Sound node will not emit audio.
+ * The source field shall specify either an AudioClip node or a MovieTexture node.
+ * If a MovieTexture node is specified as the sound source, the MovieTexture shall refer to a movie format that supports sound.
+ * @var {x3dom.fields.SFNode} source
+ * @memberof x3dom.nodeTypes.Sound
+ * @initvalue x3dom.nodeTypes.X3DSoundSourceNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('source', x3dom.nodeTypes.X3DSoundSourceNode);
+
+ },
+ {
+ nodeChanged: function()
+ {
+ if (this._cf.source.node || !this._xmlNode) {
+ return;
+ }
+
+ x3dom.debug.logInfo("No AudioClip child node given, searching for &lt;audio&gt; elements...");
+ /** USAGE e.g.:
+ <sound>
+ <audio src='sound/spita.wav' loop='loop'></audio>
+ </sound>
+ */
+ try {
+ Array.forEach( this._xmlNode.childNodes, function (childDomNode) {
+ if (childDomNode.nodeType === 1)
+ {
+ // For testing: look for <audio> element if no child
+ x3dom.debug.logInfo("### Found &lt;"+childDomNode.nodeName+"&gt; tag.");
+
+ if (childDomNode.localName.toLowerCase() === "audio")
+ {
+ var loop = childDomNode.getAttribute("loop");
+ loop = loop ? (loop.toLowerCase() === "loop") : false;
+
+ // TODO; check if crash still exists and clean-up code
+ // work around strange crash in Chrome
+ // by creating new audio element here
+
+ /*
+ var src = childDomNode.getAttribute("src");
+ var newNode = document.createElement('audio');
+ newNode.setAttribute('autobuffer', 'true');
+ newNode.setAttribute('src', src);
+ */
+ var newNode = childDomNode.cloneNode(false);
+
+ childDomNode.parentNode.removeChild(childDomNode);
+ childDomNode = null;
+
+ if(navigator.appName != "Microsoft Internet Explorer") {
+ document.body.appendChild(newNode);
+ }
+
+ var startAudio = function() {
+ newNode.play();
+ };
+
+ var audioDone = function() {
+ if (loop) {
+ newNode.play();
+ }
+ };
+
+ newNode.addEventListener("canplaythrough", startAudio, true);
+ newNode.addEventListener("ended", audioDone, true);
+ }
+ }
+ } );
+ }
+ catch(e) {
+ x3dom.debug.logException(e);
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DSoundSourceNode ### */
+x3dom.registerNodeType(
+ "X3DSoundSourceNode",
+ "Sound",
+ defineClass(x3dom.nodeTypes.X3DTimeDependentNode,
+
+ /**
+ * Constructor for X3DSoundSourceNode
+ * @constructs x3dom.nodeTypes.X3DSoundSourceNode
+ * @x3d 3.3
+ * @component Sound
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DTimeDependentNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is used to derive node types that can emit audio data.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DSoundSourceNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### AudioClip ### */
+x3dom.registerNodeType(
+ "AudioClip",
+ "Sound",
+ defineClass(x3dom.nodeTypes.X3DSoundSourceNode,
+
+ /**
+ * Constructor for AudioClip
+ * @constructs x3dom.nodeTypes.AudioClip
+ * @x3d 3.3
+ * @component Sound
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DSoundSourceNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc An AudioClip node specifies audio data that can be referenced by Sound nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.AudioClip.superClass.call(this, ctx);
+
+
+ /**
+ * The url field specifies the URL from which the sound is loaded.
+ * @var {x3dom.fields.MFString} url
+ * @memberof x3dom.nodeTypes.AudioClip
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'url', []);
+
+ /**
+ * Specifies whether the clip is enabled.
+ * @var {x3dom.fields.SFBool} enabled
+ * @memberof x3dom.nodeTypes.AudioClip
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'enabled', false);
+
+ /**
+ * Specifies whether the clip loops when finished.
+ * @var {x3dom.fields.SFBool} loop
+ * @memberof x3dom.nodeTypes.AudioClip
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'loop', false);
+
+ this._audio = document.createElement('audio');
+ //this._audio.setAttribute('preload', 'none');
+ //this._audio.setAttribute('autoplay', 'true');
+ if(navigator.appName != "Microsoft Internet Explorer") {
+ document.body.appendChild(this._audio);
+ }
+
+ this._sources = [];
+
+ },
+ {
+ nodeChanged: function()
+ {
+ this._createSources = function()
+ {
+ this._sources = [];
+ for (var i=0; i<this._vf.url.length; i++)
+ {
+ var audioUrl = this._nameSpace.getURL(this._vf.url[i]);
+ x3dom.debug.logInfo('Adding sound file: ' + audioUrl);
+ var src = document.createElement('source');
+ src.setAttribute('src', audioUrl);
+ this._sources.push(src);
+ this._audio.appendChild(src);
+ }
+ };
+
+ var that = this;
+
+ this._startAudio = function()
+ {
+ that._audio.loop = that._vf.loop ? "loop" : "";
+ if(that._vf.enabled === true)
+ {
+ that._audio.play();
+ }
+ };
+
+ this._stopAudio = function()
+ {
+ that._audio.pause();
+ };
+
+ this._audioEnded = function()
+ {
+ if (that._vf.enabled === true && that._vf.loop === true)
+ {
+ that._startAudio();
+ }
+ };
+
+ var log = function(e)
+ {
+ x3dom.debug.logWarning("MediaEvent error:"+e);
+ };
+
+ this._audio.addEventListener("canplaythrough", this._startAudio, true);
+ this._audio.addEventListener("ended", this._audioEnded, true);
+ this._audio.addEventListener("error", log, true);
+ this._audio.addEventListener("pause", this._audioEnded, true);
+
+ this._createSources();
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName === "enabled")
+ {
+ if (this._vf.enabled === true)
+ {
+ this._startAudio();
+ }
+ else
+ {
+ this._stopAudio();
+ }
+ }
+ else if (fieldName === "loop")
+ {
+ //this._audio.loop = this._vf.loop;
+ }
+ else if (fieldName === "url")
+ {
+ this._stopAudio();
+ while (this._audio.hasChildNodes())
+ {
+ this._audio.removeChild(this._audio.firstChild);
+ }
+
+ for (var i=0; i<this._vf.url.length; i++)
+ {
+ var audioUrl = this._nameSpace.getURL(this._vf.url[i]);
+ x3dom.debug.logInfo('Adding sound file: ' + audioUrl);
+ var src = document.createElement('source');
+ src.setAttribute('src', audioUrl);
+ this._audio.appendChild(src);
+ }
+ }
+ },
+
+ shutdown: function() {
+ if (this._audio) {
+ this._audio.pause();
+ while (this._audio.hasChildNodes()) {
+ this._audio.removeChild(this._audio.firstChild);
+ }
+ document.body.removeChild(this._audio);
+ this._audio = null;
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DTextureTransformNode ### */
+x3dom.registerNodeType(
+ "X3DTextureTransformNode",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for X3DTextureTransformNode
+ * @constructs x3dom.nodeTypes.X3DTextureTransformNode
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all node types which specify a transformation of texture coordinates.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DTextureTransformNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TextureTransform ### */
+x3dom.registerNodeType(
+ "TextureTransform",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureTransformNode,
+
+ /**
+ * Constructor for TextureTransform
+ * @constructs x3dom.nodeTypes.TextureTransform
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureTransformNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The TextureTransform node defines a 2D transformation that is applied to texture coordinates. This node affects the way textures coordinates are applied to the geometric surface. The transformation consists of (in order):
+ * a translation; a rotation about the centre point; a non-uniform scale about the centre point.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TextureTransform.superClass.call(this, ctx);
+
+
+ /**
+ * The center field specifies a translation offset in texture coordinate space about which the rotation and scale fields are applied.
+ * @var {x3dom.fields.SFVec2f} center
+ * @memberof x3dom.nodeTypes.TextureTransform
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'center', 0, 0);
+
+ /**
+ * The rotation field specifies a rotation in angle base units of the texture coordinates about the center point after the scale has been applied.
+ * A positive rotation value makes the texture coordinates rotate counterclockwise about the centre, thereby rotating the appearance of the texture itself clockwise.
+ * @var {x3dom.fields.SFFloat} rotation
+ * @memberof x3dom.nodeTypes.TextureTransform
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'rotation', 0);
+
+ /**
+ * The scale field specifies a scaling factor in S and T of the texture coordinates about the center point.
+ * @var {x3dom.fields.SFVec2f} scale
+ * @memberof x3dom.nodeTypes.TextureTransform
+ * @initvalue 1,1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'scale', 1, 1);
+
+ /**
+ * The translation field specifies a translation of the texture coordinates.
+ * @var {x3dom.fields.SFVec2f} translation
+ * @memberof x3dom.nodeTypes.TextureTransform
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'translation', 0, 0);
+
+ //Tc' = -C * S * R * C * T * Tc
+ var negCenter = new x3dom.fields.SFVec3f(-this._vf.center.x, -this._vf.center.y, 1);
+ var posCenter = new x3dom.fields.SFVec3f(this._vf.center.x, this._vf.center.y, 0);
+ var trans3 = new x3dom.fields.SFVec3f(this._vf.translation.x, this._vf.translation.y, 0);
+ var scale3 = new x3dom.fields.SFVec3f(this._vf.scale.x, this._vf.scale.y, 0);
+
+ this._trafo = x3dom.fields.SFMatrix4f.translation(negCenter).
+ mult(x3dom.fields.SFMatrix4f.scale(scale3)).
+ mult(x3dom.fields.SFMatrix4f.rotationZ(this._vf.rotation)).
+ mult(x3dom.fields.SFMatrix4f.translation(posCenter.add(trans3)));
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ //Tc' = -C * S * R * C * T * Tc
+ if (fieldName == 'center' || fieldName == 'rotation' ||
+ fieldName == 'scale' || fieldName == 'translation') {
+
+ var negCenter = new x3dom.fields.SFVec3f(-this._vf.center.x, -this._vf.center.y, 1);
+ var posCenter = new x3dom.fields.SFVec3f(this._vf.center.x, this._vf.center.y, 0);
+ var trans3 = new x3dom.fields.SFVec3f(this._vf.translation.x, this._vf.translation.y, 0);
+ var scale3 = new x3dom.fields.SFVec3f(this._vf.scale.x, this._vf.scale.y, 0);
+
+ this._trafo = x3dom.fields.SFMatrix4f.translation(negCenter).
+ mult(x3dom.fields.SFMatrix4f.scale(scale3)).
+ mult(x3dom.fields.SFMatrix4f.rotationZ(this._vf.rotation)).
+ mult(x3dom.fields.SFMatrix4f.translation(posCenter.add(trans3)));
+ }
+ },
+
+ texTransformMatrix: function() {
+ return this._trafo;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TextureProperties ### */
+x3dom.registerNodeType(
+ "TextureProperties",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for TextureProperties
+ * @constructs x3dom.nodeTypes.TextureProperties
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc TextureProperties allows fine control over a texture's application.
+ * This node can be used to set the texture properties for a node with a textureProperties field.
+ * A texture with a TextureProperties node will ignore the repeatS and repeatT fields on the texture.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TextureProperties.superClass.call(this, ctx);
+
+
+ /**
+ * The anisotropicDegree field describes the minimum degree of anisotropy to account for in texture filtering.
+ * A value of 1 implies no anisotropic filtering.
+ * Values above the system's maximum supported value will be clamped to the maximum allowed.
+ * @var {x3dom.fields.SFFloat} anisotropicDegree
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'anisotropicDegree', 1.0);
+
+ /**
+ * The borderColor field describes the color to use for border pixels.
+ * @var {x3dom.fields.SFColorRGBA} borderColor
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue 0,0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFColorRGBA(ctx, 'borderColor', 0, 0, 0, 0);
+
+ /**
+ * The borderWidth field describes the number of pixels to use for a texture border.
+ * @var {x3dom.fields.SFInt32} borderWidth
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'borderWidth', 0);
+
+ /**
+ * The boundaryModeS field describes the way S texture coordinate boundaries are handled.
+ * @var {x3dom.fields.SFString} boundaryModeS
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue "REPEAT"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'boundaryModeS', "REPEAT");
+
+ /**
+ * The boundaryModeS field describes the way T texture coordinate boundaries are handled.
+ * @var {x3dom.fields.SFString} boundaryModeT
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue "REPEAT"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'boundaryModeT', "REPEAT");
+
+ /**
+ * The boundaryModeS field describes the way R texture coordinate boundaries are handled.
+ * This field only applies to three dimensional textures and shall be ignored by other texture types.
+ * @var {x3dom.fields.SFString} boundaryModeR
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue "REPEAT"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'boundaryModeR', "REPEAT");
+
+ /**
+ * The magnificationFilter field describes the way textures are filtered when the image is smaller than the screen space representation.
+ * @var {x3dom.fields.SFString} magnificationFilter
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue "FASTEST"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'magnificationFilter', "FASTEST");
+
+ /**
+ * The minificationFilter field describes the way textures are filtered when the image is larger than the screen space representation.
+ * Modes with MIPMAP in the name require mipmaps. If mipmaps are not provided, the mode shall pick the corresponding non-mipmapped mode
+ * @var {x3dom.fields.SFString} minificationFilter
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue "FASTEST"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'minificationFilter', "FASTEST");
+
+ /**
+ * The textureCompression field specifies the preferred image compression method to be used during rendering.
+ * @var {x3dom.fields.SFString} textureCompression
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue "FASTEST"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'textureCompression', "FASTEST");
+
+ /**
+ * The texturePriority field describes the texture residence priority for allocating texture memory. Zero indicates the lowest priority and 1 indicates the highest priority.
+ * @var {x3dom.fields.SFFloat} texturePriority
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'texturePriority', 0);
+
+ /**
+ * The generateMipMaps field describes whether mipmaps should be generated for the texture. Mipmaps are required for filtering modes with MIPMAP in their value.
+ * @var {x3dom.fields.SFBool} generateMipMaps
+ * @memberof x3dom.nodeTypes.TextureProperties
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'generateMipMaps', false);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (this._vf.hasOwnProperty(fieldName)) {
+ Array.forEach(this._parentNodes, function (texture) {
+ Array.forEach(texture._parentNodes, function (app) {
+ Array.forEach(app._parentNodes, function (shape) {
+ shape._dirty.texture = true;
+ });
+ });
+ });
+
+ this._nameSpace.doc.needRender = true;
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DTextureNode ### */
+x3dom.registerNodeType(
+ "X3DTextureNode",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for X3DTextureNode
+ * @constructs x3dom.nodeTypes.X3DTextureNode
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all node types which specify sources for texture images.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DTextureNode.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies the channel count of the texture. 0 means the system should figure out the count automatically.
+ * @var {x3dom.fields.SFInt32} origChannelCount
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.X3DTextureNode
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'origChannelCount', 0);
+
+ /**
+ * Sets the url to a resource.
+ * @var {x3dom.fields.MFString} url
+ * @memberof x3dom.nodeTypes.X3DTextureNode
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'url', []);
+
+ /**
+ * Specifies whether the texture is repeated in s direction.
+ * @var {x3dom.fields.SFBool} repeatS
+ * @memberof x3dom.nodeTypes.X3DTextureNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'repeatS', true);
+
+ /**
+ * Specifies whether the texture is repeated in t direction.
+ * @var {x3dom.fields.SFBool} repeatT
+ * @memberof x3dom.nodeTypes.X3DTextureNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'repeatT', true);
+
+ /**
+ * Specifies whether the texture is scaled to the next highest power of two. (Needed, when texture repeat is enabled and texture size is non power of two)
+ * @var {x3dom.fields.SFBool} scale
+ * @memberof x3dom.nodeTypes.X3DTextureNode
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'scale', true);
+
+ /**
+ * Cross Origin Mode
+ * @var {x3dom.fields.SFString} crossOrigin
+ * @memberof x3dom.nodeTypes.X3DTextureNode
+ * @initvalue ""
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'crossOrigin', '');
+
+ /**
+ * Sets a TextureProperty node.
+ * @var {x3dom.fields.SFNode} textureProperties
+ * @memberof x3dom.nodeTypes.X3DTextureNode
+ * @initvalue x3dom.nodeTypes.TextureProperties
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('textureProperties', x3dom.nodeTypes.TextureProperties);
+
+ this._needPerFrameUpdate = false;
+ this._isCanvas = false;
+ this._type = "diffuseMap";
+
+ this._blending = (this._vf.origChannelCount == 1 || this._vf.origChannelCount == 2);
+
+ },
+ {
+ invalidateGLObject: function ()
+ {
+ Array.forEach(this._parentNodes, function (app) {
+ Array.forEach(app._parentNodes, function (shape) {
+ // THINKABOUTME: this is a bit ugly, cleanup more generically
+ if (x3dom.isa(shape, x3dom.nodeTypes.X3DShapeNode)) {
+ shape._dirty.texture = true;
+ }
+ else {
+ // Texture maybe in MultiTexture or CommonSurfaceShader
+ Array.forEach(shape._parentNodes, function (realShape) {
+ if (x3dom.isa(realShape, x3dom.nodeTypes.X3DShapeNode)) {
+ realShape._dirty.texture = true;
+ } else {
+ Array.forEach(realShape._parentNodes, function (realShape2) {
+ if (x3dom.isa(realShape2, x3dom.nodeTypes.X3DShapeNode)) {
+ realShape2._dirty.texture = true;
+ }
+ });
+ }
+ });
+ }
+ });
+ });
+
+ this._nameSpace.doc.needRender = true;
+ },
+
+ parentAdded: function(parent)
+ {
+ Array.forEach(parent._parentNodes, function (shape) {
+ // THINKABOUTME: this is a bit ugly, cleanup more generically
+ if (x3dom.isa(shape, x3dom.nodeTypes.Shape)) {
+ shape._dirty.texture = true;
+ }
+ else {
+ // Texture maybe in MultiTexture or CommonSurfaceShader
+ Array.forEach(shape._parentNodes, function (realShape) {
+ realShape._dirty.texture = true;
+ });
+ }
+ });
+ },
+
+ parentRemoved: function(parent)
+ {
+ Array.forEach(parent._parentNodes, function (shape) {
+ // THINKABOUTME: this is a bit ugly, cleanup more generically
+ if (x3dom.isa(shape, x3dom.nodeTypes.Shape)) {
+ shape._dirty.texture = true;
+ }
+ else {
+ // Texture maybe in MultiTexture or CommonSurfaceShader
+ Array.forEach(shape._parentNodes, function (realShape) {
+ realShape._dirty.texture = true;
+ });
+ }
+ });
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName == "url" || fieldName == "origChannelCount" ||
+ fieldName == "repeatS" || fieldName == "repeatT" ||
+ fieldName == "scale" || fieldName == "crossOrigin")
+ {
+ var that = this;
+
+ Array.forEach(this._parentNodes, function (app) {
+ if (x3dom.isa(app, x3dom.nodeTypes.X3DAppearanceNode)) {
+ app.nodeChanged();
+ Array.forEach(app._parentNodes, function (shape) {
+ shape._dirty.texture = true;
+ });
+ }
+ else if (x3dom.isa(app, x3dom.nodeTypes.MultiTexture)) {
+ Array.forEach(app._parentNodes, function (realApp) {
+ realApp.nodeChanged();
+ Array.forEach(realApp._parentNodes, function (shape) {
+ shape._dirty.texture = true;
+ });
+ });
+ }
+ else if (x3dom.isa(app, x3dom.nodeTypes.ImageGeometry)) {
+ var cf = null;
+ if (that._xmlNode && that._xmlNode.hasAttribute('containerField')) {
+ cf = that._xmlNode.getAttribute('containerField');
+ app._dirty[cf] = true;
+ }
+ }
+ else if (x3dom.nodeTypes.X3DVolumeDataNode !== undefined) {
+ if (x3dom.isa(app, x3dom.nodeTypes.X3DVolumeRenderStyleNode)) {
+ if (that._xmlNode && that._xmlNode.hasAttribute('containerField')) {
+ if(app._volumeDataParent){
+ app._volumeDataParent._dirty.texture = true;
+ }else{
+ //Texture maybe under a ComposedVolumeStyle
+ var volumeDataParent = app._parentNodes[0];
+ while(!x3dom.isa(volumeDataParent, x3dom.nodeTypes.X3DVolumeDataNode) && x3dom.isa(volumeDataParent, x3dom.nodeTypes.X3DNode)){
+ volumeDataParent = volumeDataParent._parentNodes[0];
+ }
+ if(x3dom.isa(volumeDataParent, x3dom.nodeTypes.X3DNode)){
+ volumeDataParent._dirty.texture = true;
+ }
+ }
+ }
+ } else if (x3dom.isa(app, x3dom.nodeTypes.X3DVolumeDataNode)) {
+ if (that._xmlNode && that._xmlNode.hasAttribute('containerField')) {
+ app._dirty.texture = true;
+ }
+ }
+ }
+ });
+ }
+ },
+
+ getTexture: function(pos) {
+ if (pos === 0) {
+ return this;
+ }
+ return null;
+ },
+
+ size: function() {
+ return 1;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MultiTexture ### */
+x3dom.registerNodeType(
+ "MultiTexture",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureNode,
+
+ /**
+ * Constructor for MultiTexture
+ * @constructs x3dom.nodeTypes.MultiTexture
+ * @x3d 3.3
+ * @component Texturing
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The MultiTexture node specifies the application of several individual textures to a 3D object to achieve a more complex visual effect.
+ * MultiTexture can be used as a value for the texture field in an Appearance node.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MultiTexture.superClass.call(this, ctx);
+
+
+ /**
+ * The texture field contains a list of texture nodes (e.g., ImageTexture, PixelTexture, and MovieTexture). The texture field may not contain another MultiTexture node.
+ * @var {x3dom.fields.MFNode} texture
+ * @memberof x3dom.nodeTypes.MultiTexture
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('texture', x3dom.nodeTypes.X3DTextureNode);
+
+ },
+ {
+ getTexture: function(pos) {
+ if (pos >= 0 && pos < this._cf.texture.nodes.length) {
+ return this._cf.texture.nodes[pos];
+ }
+ return null;
+ },
+
+ getTextures: function() {
+ return this._cf.texture.nodes;
+ },
+
+ size: function() {
+ return this._cf.texture.nodes.length;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Texture ### */
+// intermediate layer to avoid instantiating X3DTextureNode in web profile
+x3dom.registerNodeType(
+ "Texture", // X3DTexture2DNode
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureNode,
+
+ /**
+ * Constructor for Texture
+ * @constructs x3dom.nodeTypes.Texture
+ * @x3d x.x
+ * @component Texturing
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc (Abstract) class for 2D Textures.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Texture.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies whether the children are shown or hidden outside the texture.
+ * @var {x3dom.fields.SFBool} hideChildren
+ * @memberof x3dom.nodeTypes.Texture
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'hideChildren', true);
+
+ this._video = null;
+ this._intervalID = 0;
+ this._canvas = null;
+
+ },
+ {
+ nodeChanged: function()
+ {
+ if (this._vf.url.length || !this._xmlNode) {
+ return;
+ }
+ x3dom.debug.logInfo("No Texture URL given, searching for &lt;img&gt; elements...");
+ var that = this;
+ try {
+ Array.forEach( this._xmlNode.childNodes, function (childDomNode) {
+ if (childDomNode.nodeType === 1) {
+ var url = childDomNode.getAttribute("src");
+ // For testing: look for <img> element if url empty
+ if (url) {
+ that._vf.url.push(url);
+ x3dom.debug.logInfo(that._vf.url[that._vf.url.length-1]);
+
+ if (childDomNode.localName.toLowerCase() === "video") {
+ that._needPerFrameUpdate = true;
+ //that._video = childDomNode;
+
+ that._video = document.createElement('video');
+ that._video.setAttribute('preload', 'auto');
+ that._video.setAttribute('muted', 'muted');
+ var p = document.getElementsByTagName('body')[0];
+ p.appendChild(that._video);
+ that._video.style.display = "none";
+ that._video.style.visibility = "hidden";
+ }
+ }
+ else if (childDomNode.localName.toLowerCase() === "canvas") {
+ that._needPerFrameUpdate = true;
+ that._isCanvas = true;
+ that._canvas = childDomNode;
+ }
+
+ if (childDomNode.style && that._vf.hideChildren) {
+ childDomNode.style.display = "none";
+ childDomNode.style.visibility = "hidden";
+ }
+ x3dom.debug.logInfo("### Found &lt;"+childDomNode.nodeName+"&gt; tag.");
+ }
+ } );
+ }
+ catch(e) {
+ x3dom.debug.logException(e);
+ }
+ },
+
+ shutdown: function() {
+ if (this._video) {
+ this._video.pause();
+ while (this._video.hasChildNodes()) {
+ this._video.removeChild(this._video.firstChild);
+ }
+ document.body.removeChild(this._video);
+ this._video = null;
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### RenderedTexture ### */
+x3dom.registerNodeType(
+ "RenderedTexture",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureNode,
+
+ /**
+ * Constructor for RenderedTexture
+ * @constructs x3dom.nodeTypes.RenderedTexture
+ * @x3d x.x
+ * @component Texturing
+ * @extends x3dom.nodeTypes.X3DTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This extension provides the ability to dynamically render a partial scenegraph to an offscreen texture that can then be used on the geometry of a node.
+ * This can be used in many different ways such as creating mirror effects, inputs to shaders etc.
+ * The purpose of this component is to provide for extended visual effects, but not the complete form of offscreen rendering and buffers that would be available to lower-level rendering APIs.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.RenderedTexture.superClass.call(this, ctx);
+
+ if (ctx)
+ ctx.doc._nodeBag.renderTextures.push(this);
+ else
+ x3dom.debug.logWarning("RenderedTexture: No runtime context found!");
+
+ // Original proposal taken from: http://www.xj3d.org/extensions/render_texture.html
+ // http://doc.instantreality.org/documentation/nodetype/RenderedTexture/?filter=None
+
+
+ /**
+ * Specifies the viewpoint that is used to render the texture content.
+ * @var {x3dom.fields.SFNode} viewpoint
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue x3dom.nodeTypes.X3DViewpointNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('viewpoint', x3dom.nodeTypes.X3DViewpointNode);
+
+ /**
+ * Sets a background texture.
+ * @var {x3dom.fields.SFNode} background
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue x3dom.nodeTypes.X3DBackgroundNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('background', x3dom.nodeTypes.X3DBackgroundNode);
+
+ /**
+ * Sets a fog node.
+ * @var {x3dom.fields.SFNode} fog
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue x3dom.nodeTypes.X3DFogNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('fog', x3dom.nodeTypes.X3DFogNode); //TODO
+
+ /**
+ * Sets a separate, potentially independent, subscene. If unset, the same scene is used.
+ * @var {x3dom.fields.SFNode} scene
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue x3dom.nodeTypes.X3DNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('scene', x3dom.nodeTypes.X3DNode);
+
+ /**
+ * Defines a list of sibling nodes that should be ignored.
+ * @var {x3dom.fields.MFNode} excludeNodes
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue x3dom.nodeTypes.X3DNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFNode('excludeNodes', x3dom.nodeTypes.X3DNode);
+
+ /**
+ * Sets the width, height, color components (and number of MRTs).
+ * @var {x3dom.fields.MFInt32} dimensions
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue [128,128,4]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'dimensions', [128, 128, 4]);
+
+ /**
+ * Specifies when the texture is updated.
+ * @var {x3dom.fields.SFString} update
+ * @range ["NONE", "NEXT_FRAME_ONLY", "ALWAYS"]
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue 'NONE'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'update', 'NONE');
+
+
+ /**
+ *Specifies whether normals are shown.
+ * @var {x3dom.fields.SFBool} showNormals
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'showNormals', false);
+
+ /**
+ * Sets render information for stereo rendering.
+ * @var {x3dom.fields.SFString} stereoMode
+ * @range ["NONE","LEFT_EYE","RIGHT_EYE"]
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue 'NONE'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'stereoMode', 'NONE');
+
+ /**
+ * Sets the eye distance for stereo rendering.
+ * @var {x3dom.fields.SFFloat} interpupillaryDistance
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue 0.064
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'interpupillaryDistance', 0.064);
+
+ /**
+ * Very experimental field to change between DK1 and DK2.
+ * @var {x3dom.fields.SFFloat} oculusRiftVersion
+ * @memberof x3dom.nodeTypes.RenderedTexture
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'oculusRiftVersion', 1);
+
+ this.hScreenSize = (this._vf.oculusRiftVersion == 1) ? 0.14976 : 0.12576;
+ this.vScreenSize = (this._vf.oculusRiftVersion == 1) ? 0.09356 : 0.07074;
+ this.vScreenCenter = this.vScreenSize / 2;
+ this.eyeToScreenDistance = 0.041;
+ this.lensSeparationDistance = 0.0635;
+ this.distortionK = [1.0, 0.22, 0.24, 0.0];
+ //hRes, vRes = 1280 x 800 // DK2: 1920 x 1080
+ //this.lensCenter = 1 - 2 * this.lensSeparationDistance / this.hScreenSize;
+ this.lensCenter = 0.151976495726; // TODO: DK2 ?
+
+ x3dom.debug.assert(this._vf.dimensions.length >= 3,
+ "RenderedTexture.dimensions requires at least 3 entries.");
+ this._clearParents = true;
+ this._needRenderUpdate = true;
+
+ },
+ {
+ nodeChanged: function()
+ {
+ this._clearParents = true;
+ this._needRenderUpdate = true;
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ switch(fieldName)
+ {
+ case "excludeNodes":
+ this._clearParents = true;
+ break;
+ case "update":
+ if (this._vf.update.toUpperCase() == "NEXT_FRAME_ONLY" ||
+ this._vf.update.toUpperCase() == "ALWAYS") {
+ this._needRenderUpdate = true;
+ }
+ break;
+ default:
+ // TODO: dimensions
+ break;
+ }
+ },
+
+ getViewMatrix: function ()
+ {
+ if (this._clearParents && this._cf.excludeNodes.nodes.length) {
+ // FIXME; avoid recursions cleverer and more generic than this
+ // (Problem: nodes in excludeNodes field have this node
+ // as first parent, which leads to a recursion loop in
+ // getCurrentTransform()
+ var that = this;
+
+ Array.forEach(this._cf.excludeNodes.nodes, function(node) {
+ for (var i=0, n=node._parentNodes.length; i < n; i++) {
+ if (node._parentNodes[i] === that) {
+ node._parentNodes.splice(i, 1);
+ node.parentRemoved(that);
+ }
+ }
+ });
+
+ this._clearParents = false;
+ }
+
+ var locScene = this._cf.scene.node;
+ var scene = this._nameSpace.doc._scene;
+ var vbP = scene.getViewpoint();
+ var view = this._cf.viewpoint.node;
+ var ret_mat = null;
+
+ if (view === null || view === vbP) {
+ ret_mat = this._nameSpace.doc._viewarea.getViewMatrix();
+ }
+ else if (locScene && locScene !== scene) {
+ // in case of completely local scene do not transform local viewpoint
+ ret_mat = view.getViewMatrix()
+ }
+ else {
+ var mat_viewpoint = view.getCurrentTransform();
+ ret_mat = view.getViewMatrix().mult(mat_viewpoint.inverse());
+ }
+
+ var stereoMode = this._vf.stereoMode.toUpperCase();
+ if (stereoMode != "NONE") {
+ var d = this._vf.interpupillaryDistance / 2;
+ if (stereoMode == "RIGHT_EYE") {
+ d = -d;
+ }
+ var modifier = new x3dom.fields.SFMatrix4f(
+ 1, 0, 0, d,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ );
+ ret_mat = modifier.mult(ret_mat);
+ }
+
+ return ret_mat;
+ },
+
+ getProjectionMatrix: function()
+ {
+ var doc = this._nameSpace.doc;
+ var vbP = doc._scene.getViewpoint();
+ var view = this._cf.viewpoint.node;
+ var ret_mat = null;
+ var f, w = this._vf.dimensions[0], h = this._vf.dimensions[1];
+ var stereoMode = this._vf.stereoMode.toUpperCase();
+ var stereo = (stereoMode != "NONE");
+
+ if (view === null || view === vbP) {
+ ret_mat = x3dom.fields.SFMatrix4f.copy(doc._viewarea.getProjectionMatrix());
+ if (stereo) {
+ f = 2 * Math.atan(this.vScreenSize / (2 * this.eyeToScreenDistance));
+ f = 1 / Math.tan(f / 2);
+ }
+ else {
+ f = 1 / Math.tan(vbP._vf.fieldOfView / 2);
+ }
+ ret_mat._00 = f / (w / h);
+ ret_mat._11 = f;
+ }
+ else {
+ ret_mat = view.getProjectionMatrix(w / h);
+ }
+
+ if (stereo) {
+ var hp = this.lensCenter;
+ if (stereoMode == "RIGHT_EYE") {
+ hp = -hp;
+ }
+ var modifier = new x3dom.fields.SFMatrix4f(
+ 1, 0, 0, hp,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ );
+ ret_mat = modifier.mult(ret_mat);
+ }
+
+ return ret_mat;
+ },
+
+ getWCtoCCMatrix: function()
+ {
+ var view = this.getViewMatrix();
+ var proj = this.getProjectionMatrix();
+
+ return proj.mult(view);
+ },
+
+ parentRemoved: function(parent)
+ {
+ if (this._parentNodes.length === 0) {
+ var doc = this.findX3DDoc();
+
+ for (var i=0, n=doc._nodeBag.renderTextures.length; i<n; i++) {
+ if (doc._nodeBag.renderTextures[i] === this) {
+ doc._nodeBag.renderTextures.splice(i, 1);
+ }
+ }
+ }
+
+ if (this._cf.scene.node) {
+ this._cf.scene.node.parentRemoved(this);
+ }
+ },
+
+ requirePingPong: function()
+ {
+ return false;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### RefinementTexture ### */
+x3dom.registerNodeType(
+ "RefinementTexture",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.RenderedTexture,
+
+ /**
+ * Constructor for RefinementTexture
+ * @constructs x3dom.nodeTypes.RefinementTexture
+ * @x3d x.x
+ * @component Texturing
+ * @extends x3dom.nodeTypes.RenderedTexture
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ */
+ function (ctx) {
+ x3dom.nodeTypes.RefinementTexture.superClass.call(this, ctx);
+
+ /**
+ * Specifies the first stamp texture.
+ * @var {x3dom.fields.SFString} stamp0
+ * @memberof x3dom.nodeTypes.RefinementTexture
+ * @initvalue "gpuii/stamps/0.gif"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'stamp0', "gpuii/stamps/0.gif");
+
+ /**
+ * Specifies the second stamp texture.
+ * @var {x3dom.fields.SFString} stamp1
+ * @memberof x3dom.nodeTypes.RefinementTexture
+ * @initvalue "gpuii/stamps/1.gif"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'stamp1', "gpuii/stamps/1.gif");
+
+ /**
+ * Defines whether texture refinement should be managed by another component.
+ * @var {x3dom.fields.SFBool} autoRefinement
+ * @memberof x3dom.nodeTypes.RefinementTexture
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'autoRefinement', true);
+
+ /**
+ * Specifies the image format of the dataset.
+ * @var {x3dom.fields.SFString} format
+ * @memberof x3dom.nodeTypes.RefinementTexture
+ * @initvalue 'jpg'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'format', 'jpg');
+
+ /**
+ * Maximum level that should be loaded (if GSM is smaller than on DSL6000)
+ * @var {x3dom.fields.SFInt32} iterations
+ * @memberof x3dom.nodeTypes.RefinementTexture
+ * @initvalue 7
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'iterations', 7);
+
+ /**
+ * Maximum level that should be loaded (if GSM is smaller than on DSL6000)
+ * @var {x3dom.fields.SFInt32} maxLevel
+ * @memberof x3dom.nodeTypes.RefinementTexture
+ * @initvalue this._vf.iterations
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'maxLevel', this._vf.iterations);
+
+ if (this._vf.iterations % 2 === 0) {
+ var temp = this._vf.stamp0;
+ this._vf.stamp0 = this._vf.stamp1;
+ this._vf.stamp1 = temp;
+ }
+
+ this._vf.iterations = (this._vf.iterations > 11) ? 11 : this._vf.iterations;
+ this._vf.iterations = (this._vf.iterations < 3) ? 3 : this._vf.iterations;
+ this._vf.maxLevel = (this._vf.maxLevel > 11) ? 11 : this._vf.maxLevel;
+ this._vf.maxLevel = (this._vf.maxLevel < 3) ? 3 : this._vf.maxLevel;
+ this._vf.maxLevel = (this._vf.maxLevel > this._vf.iterations) ? this._vf.iterations : this._vf.maxLevel;
+
+ // Additional parameters to control the refinement mechanism on shader
+ // TODO: optimize
+ var repeatConfig = [
+ {x: 4, y: 8}, {x: 8, y: 8}, {x: 8, y: 16},
+ {x: 16, y: 16}, {x: 16, y: 32}, {x: 32, y: 32},
+ {x: 32, y: 64}, {x: 64, y: 64}, {x: 64, y: 128}
+ ];
+
+ // TODO: optimize
+ this._repeat = new x3dom.fields.SFVec2f(
+ this._vf.dimensions[0] / repeatConfig[this._vf.iterations - 3].x,
+ this._vf.dimensions[1] / repeatConfig[this._vf.iterations - 3].y
+ );
+ this._renderedImage = 0;
+ this._currLoadLevel = 0;
+ this._loadLevel = 1;
+
+ },
+ {
+ nextLevel: function() {
+ if (this._loadLevel < this._vf.maxLevel) {
+ this._loadLevel++;
+ this._nameSpace.doc.needRender = true;
+ }
+ },
+
+ requirePingPong: function() {
+ return (this._currLoadLevel <= this._vf.maxLevel &&
+ this._renderedImage < this._loadLevel);
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PixelTexture ### */
+x3dom.registerNodeType(
+ "PixelTexture",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureNode,
+
+ /**
+ * Constructor for PixelTexture
+ * @constructs x3dom.nodeTypes.PixelTexture
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PixelTexture node defines a 2D image-based texture map as an explicit array of pixel values (image field) and parameters controlling tiling repetition of the texture onto geometry.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PixelTexture.superClass.call(this, ctx);
+
+
+ /**
+ * The image that delivers the pixel data.
+ * @var {x3dom.fields.SFImage} image
+ * @memberof x3dom.nodeTypes.PixelTexture
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFImage(ctx, 'image', 0, 0, 0);
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName == "image") {
+ this.invalidateGLObject();
+ }
+ },
+
+ getWidth: function() {
+ return this._vf.image.width;
+ },
+
+ getHeight: function() {
+ return this._vf.image.height;
+ },
+
+ getComponents: function() {
+ return this._vf.image.comp;
+ },
+
+ setPixel: function(x, y, color, update) {
+ update = (update == undefined) ? true : update;
+
+ if (this._x3domTexture) {
+ this._x3domTexture.setPixel(x, y, [
+ color.r*255,
+ color.g*255,
+ color.b*255,
+ color.a*255 ], update );
+ this._vf.image.setPixel(x, y, color);
+ }
+ else
+ {
+ this._vf.image.setPixel(x, y, color);
+ if( update ) {
+ this.invalidateGLObject();
+ }
+ }
+
+ },
+
+ getPixel: function(x, y) {
+ return this._vf.image.getPixel(x, y);
+ },
+
+ setPixels: function(pixels, update) {
+ update = (update == undefined) ? true : update;
+
+ this._vf.image.setPixels(pixels);
+
+ if( update ) {
+ this.invalidateGLObject();
+ }
+ },
+
+ getPixels: function() {
+ return this._vf.image.getPixels();
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ImageTexture ### */
+x3dom.registerNodeType(
+ "ImageTexture",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.Texture,
+
+ /**
+ * Constructor for ImageTexture
+ * @constructs x3dom.nodeTypes.ImageTexture
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.Texture
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc ImageTexture maps a 2D-image file onto a geometric shape.
+ * Texture maps have a 2D coordinate system (s, t) horizontal and vertical, with (s, t) values in range [0.0, 1.0] for opposite corners of the image.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ImageTexture.superClass.call(this, ctx);
+
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MovieTexture ### */
+x3dom.registerNodeType(
+ "MovieTexture",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.Texture,
+
+ /**
+ * Constructor for MovieTexture
+ * @constructs x3dom.nodeTypes.MovieTexture
+ * @x3d 3.3
+ * @component Texturing
+ * @status experimental
+ * @extends x3dom.nodeTypes.Texture
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The MovieTexture node defines a time dependent texture map (contained in a movie file) and parameters for controlling the movie and the texture mapping.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MovieTexture.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies whether the playback restarts after finished.
+ * @var {x3dom.fields.SFBool} loop
+ * @memberof x3dom.nodeTypes.MovieTexture
+ * @initvalue false
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'loop', false);
+
+ /**
+ * Specifies the plaback speed.
+ * @var {x3dom.fields.SFFloat} speed
+ * @memberof x3dom.nodeTypes.MovieTexture
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'speed', 1.0);
+ // TODO; implement the following fields...
+
+ /**
+ * Sets a time to pause the video.
+ * @var {x3dom.fields.SFTime} pauseTime
+ * @memberof x3dom.nodeTypes.MovieTexture
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'pauseTime', 0);
+
+ /**
+ *
+ * @var {x3dom.fields.SFFloat} pitch
+ * @memberof x3dom.nodeTypes.MovieTexture
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'pitch', 1.0);
+
+ /**
+ * Sets a time to resume from pause.
+ * @var {x3dom.fields.SFTime} resumeTime
+ * @memberof x3dom.nodeTypes.MovieTexture
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'resumeTime', 0);
+
+ /**
+ * Sets a start time for the video.
+ * @var {x3dom.fields.SFTime} startTime
+ * @memberof x3dom.nodeTypes.MovieTexture
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'startTime', 0);
+
+ /**
+ * Sets a stop time for the video.
+ * @var {x3dom.fields.SFTime} stopTime
+ * @memberof x3dom.nodeTypes.MovieTexture
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFTime(ctx, 'stopTime', 0);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DTextureCoordinateNode ### */
+x3dom.registerNodeType(
+ "X3DTextureCoordinateNode",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DGeometricPropertyNode,
+
+ /**
+ * Constructor for X3DTextureCoordinateNode
+ * @constructs x3dom.nodeTypes.X3DTextureCoordinateNode
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGeometricPropertyNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all node types which specify texture coordinates.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DTextureCoordinateNode.superClass.call(this, ctx);
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName === "texCoord" || fieldName === "point" ||
+ fieldName === "parameter" || fieldName === "mode")
+ {
+ Array.forEach(this._parentNodes, function (node) {
+ node.fieldChanged("texCoord");
+ });
+ }
+ },
+
+ parentAdded: function(parent) {
+ if (parent._mesh && //parent._cf.coord.node &&
+ parent._cf.texCoord.node !== this) {
+ parent.fieldChanged("texCoord");
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TextureCoordinate ### */
+x3dom.registerNodeType(
+ "TextureCoordinate",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureCoordinateNode,
+
+ /**
+ * Constructor for TextureCoordinate
+ * @constructs x3dom.nodeTypes.TextureCoordinate
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureCoordinateNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The TextureCoordinate node is a geometry property node that specifies a set of 2D texture coordinates used by vertex-based geometry nodes (EXAMPLE IndexedFaceSet and ElevationGrid) to map textures to vertices.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TextureCoordinate.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies the array of texture coordinates.
+ * @var {x3dom.fields.MFVec2f} point
+ * @memberof x3dom.nodeTypes.TextureCoordinate
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec2f(ctx, 'point', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TextureCoordinateGenerator ### */
+x3dom.registerNodeType(
+ "TextureCoordinateGenerator",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureCoordinateNode,
+
+ /**
+ * Constructor for TextureCoordinateGenerator
+ * @constructs x3dom.nodeTypes.TextureCoordinateGenerator
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureCoordinateNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc TextureCoordinateGenerator supports the automatic generation of texture coordinates for geometric shapes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TextureCoordinateGenerator.superClass.call(this, ctx);
+
+
+ /**
+ * The mode field describes the algorithm used to compute texture coordinates.
+ * @var {x3dom.fields.SFString} mode
+ * @memberof x3dom.nodeTypes.TextureCoordinateGenerator
+ * @initvalue "SPHERE"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'mode', "SPHERE");
+
+ /**
+ * Specify the parameters. These are mode dependent.
+ * @var {x3dom.fields.MFFloat} parameter
+ * @memberof x3dom.nodeTypes.TextureCoordinateGenerator
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'parameter', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### MultiTextureCoordinate ### */
+x3dom.registerNodeType(
+ "MultiTextureCoordinate",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.X3DTextureCoordinateNode,
+
+ /**
+ * Constructor for MultiTextureCoordinate
+ * @constructs x3dom.nodeTypes.MultiTextureCoordinate
+ * @x3d 3.3
+ * @component Texturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureCoordinateNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc MultiTextureCoordinate supplies multiple texture coordinates per vertex. This node can be used to set the texture coordinates for the different texture channels.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.MultiTextureCoordinate.superClass.call(this, ctx);
+
+
+ /**
+ * Each entry in the texCoord field may contain a TextureCoordinate or TextureCoordinateGenerator node.
+ * @var {x3dom.fields.MFNode} texCoord
+ * @memberof x3dom.nodeTypes.MultiTextureCoordinate
+ * @initvalue x3dom.nodeTypes.X3DTextureCoordinateNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('texCoord', x3dom.nodeTypes.X3DTextureCoordinateNode);
+
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ImageTextureAtlas ### */
+x3dom.registerNodeType(
+ "ImageTextureAtlas",
+ "Texturing",
+ defineClass(x3dom.nodeTypes.Texture,
+
+ /**
+ * Constructor for ImageTextureAtlas
+ * @constructs x3dom.nodeTypes.ImageTextureAtlas
+ * @x3d x.x
+ * @component Texturing
+ * @extends x3dom.nodeTypes.Texture
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is a special helper node to represent tiles for volume rendering.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ImageTextureAtlas.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies the number of slices in the texture atlas.
+ * @var {x3dom.fields.SFInt32} numberOfSlices
+ * @memberof x3dom.nodeTypes.ImageTextureAtlas
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'numberOfSlices', 0);
+
+ /**
+ * Specifies the slices in x.
+ * @var {x3dom.fields.SFInt32} slicesOverX
+ * @memberof x3dom.nodeTypes.ImageTextureAtlas
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'slicesOverX', 0);
+
+ /**
+ * Specifies the slices in y.
+ * @var {x3dom.fields.SFInt32} slicesOverY
+ * @memberof x3dom.nodeTypes.ImageTextureAtlas
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'slicesOverY', 0);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DEnvironmentTextureNode ### */
+x3dom.registerNodeType(
+ "X3DEnvironmentTextureNode",
+ "CubeMapTexturing",
+ defineClass(x3dom.nodeTypes.X3DTextureNode,
+
+ /**
+ * Constructor for X3DEnvironmentTextureNode
+ * @constructs x3dom.nodeTypes.X3DEnvironmentTextureNode
+ * @x3d x.x
+ * @component CubeMapTexturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all node types that specify cubic environment map sources for texture images.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DEnvironmentTextureNode.superClass.call(this, ctx);
+
+ },
+ {
+ getTexUrl: function() {
+ return []; //abstract accessor for gfx
+ },
+
+ getTexSize: function() {
+ return -1; //abstract accessor for gfx
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ComposedCubeMapTexture ### */
+x3dom.registerNodeType(
+ "ComposedCubeMapTexture",
+ "CubeMapTexturing",
+ defineClass(x3dom.nodeTypes.X3DEnvironmentTextureNode,
+
+ /**
+ * Constructor for ComposedCubeMapTexture
+ * @constructs x3dom.nodeTypes.ComposedCubeMapTexture
+ * @x3d 3.3
+ * @component CubeMapTexturing
+ * @status full
+ * @extends x3dom.nodeTypes.X3DEnvironmentTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ComposedCubeMapTexture node defines a cubic environment map source as an explicit set of
+ * images drawn from individual 2D texture nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ComposedCubeMapTexture.superClass.call(this, ctx);
+
+
+ /**
+ * Texture for the back of the cubemap
+ * @var {x3dom.fields.SFNode} back
+ * @memberof x3dom.nodeTypes.ComposedCubeMapTexture
+ * @initvalue x3dom.nodeTypes.Texture
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('back', x3dom.nodeTypes.Texture);
+
+ /**
+ * Texture for the front of the cubemap
+ * @var {x3dom.fields.SFNode} front
+ * @memberof x3dom.nodeTypes.ComposedCubeMapTexture
+ * @initvalue x3dom.nodeTypes.Texture
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('front', x3dom.nodeTypes.Texture);
+
+ /**
+ * Texture for the bottom of the cubemap
+ * @var {x3dom.fields.SFNode} bottom
+ * @memberof x3dom.nodeTypes.ComposedCubeMapTexture
+ * @initvalue x3dom.nodeTypes.Texture
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('bottom', x3dom.nodeTypes.Texture);
+
+ /**
+ * Texture for the top of the cubemap
+ * @var {x3dom.fields.SFNode} top
+ * @memberof x3dom.nodeTypes.ComposedCubeMapTexture
+ * @initvalue x3dom.nodeTypes.Texture
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('top', x3dom.nodeTypes.Texture);
+
+ /**
+ * Texture for the left side of the cubemap
+ * @var {x3dom.fields.SFNode} left
+ * @memberof x3dom.nodeTypes.ComposedCubeMapTexture
+ * @initvalue x3dom.nodeTypes.Texture
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('left', x3dom.nodeTypes.Texture);
+
+ /**
+ * Texture for the right side of the cubemap
+ * @var {x3dom.fields.SFNode} right
+ * @memberof x3dom.nodeTypes.ComposedCubeMapTexture
+ * @initvalue x3dom.nodeTypes.Texture
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFNode('right', x3dom.nodeTypes.Texture);
+ this._type = "cubeMap";
+
+ },
+ {
+ getTexUrl: function() {
+ return [
+ this._nameSpace.getURL(this._cf.back.node._vf.url[0]),
+ this._nameSpace.getURL(this._cf.front.node._vf.url[0]),
+ this._nameSpace.getURL(this._cf.bottom.node._vf.url[0]),
+ this._nameSpace.getURL(this._cf.top.node._vf.url[0]),
+ this._nameSpace.getURL(this._cf.left.node._vf.url[0]),
+ this._nameSpace.getURL(this._cf.right.node._vf.url[0])
+ ];
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### GeneratedCubeMapTexture ### */
+x3dom.registerNodeType(
+ "GeneratedCubeMapTexture",
+ "CubeMapTexturing",
+ defineClass(x3dom.nodeTypes.X3DEnvironmentTextureNode,
+
+ /**
+ * Constructor for GeneratedCubeMapTexture
+ * @constructs x3dom.nodeTypes.GeneratedCubeMapTexture
+ * @x3d 3.3
+ * @component CubeMapTexturing
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DEnvironmentTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The GeneratedCubeMapTexture node defines a cubic environment map that sources its data from
+ * internally generated images, rendered from a virtual situated perspective in the scene.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.GeneratedCubeMapTexture.superClass.call(this, ctx);
+
+
+ /**
+ * The size field indicates the resolution of the generated images in number of pixels per side.
+ * @var {x3dom.fields.SFInt32} size
+ * @memberof x3dom.nodeTypes.GeneratedCubeMapTexture
+ * @initvalue 128
+ * @range (0, inf)
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'size', 128);
+
+ /**
+ * NOT YET IMPLEMENTED:
+ * The update field can be used to request a regeneration of the texture. Setting this field to "ALWAYS"
+ * will cause the texture to be rendered every frame. A value of "NONE" will stop rendering so that no
+ * further updates are performed even if the contained scene graph changes. When the value is set to
+ * "NEXT_FRAME_ONLY", it is an instruction to render the texture at the end of this frame, and then not
+ * render it again. In this case, the update frame indicator is set to this frame; at the start of the next
+ * frame, the update value shall be automatically set back to "NONE" to indicate that the rendering has already taken place.
+ * @var {x3dom.fields.SFString} update
+ * @memberof x3dom.nodeTypes.GeneratedCubeMapTexture
+ * @initvalue 'NONE'
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'update', 'NONE'); // ("NONE"|"NEXT_FRAME_ONLY"|"ALWAYS")
+
+ this._type = "cubeMap";
+ x3dom.debug.logWarning("GeneratedCubeMapTexture NYI"); // TODO; impl. in gfx when fbo type ready
+
+ },
+ {
+ getTexSize: function() {
+ return this._vf.size;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Uniform ### */
+x3dom.registerNodeType(
+ "Uniform",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.Field,
+
+ /**
+ * Constructor for Uniform
+ * @constructs x3dom.nodeTypes.Uniform
+ * @x3d x.x
+ * @component Shaders
+ * @extends x3dom.nodeTypes.Field
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Node representing a uniform.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Uniform.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### SurfaceShaderTexture ### */
+x3dom.registerNodeType(
+ "SurfaceShaderTexture",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.X3DTextureNode,
+
+ /**
+ * Constructor for SurfaceShaderTexture
+ * @constructs x3dom.nodeTypes.SurfaceShaderTexture
+ * @x3d x.x
+ * @component Shaders
+ * @extends x3dom.nodeTypes.X3DTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc A texture reference that can be used as a child of SurfaceShader.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.SurfaceShaderTexture.superClass.call(this, ctx);
+
+
+ /**
+ * Texture coordinate channel to use for this texture.
+ * @var {x3dom.fields.SFInt32} textureCoordinatesId
+ * @memberof x3dom.nodeTypes.SurfaceShaderTexture
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'textureCoordinatesId', 0);
+
+ /**
+ * Texture channels to use for this texture in the form of a glsl swizzle (e.g. "rgb", "abgr", "a").
+ * "DEFAULT" will use the default channels for the slot ("rgb" for colors and normals, "a" for alpha,
+ * shininess, ...).
+ * @var {x3dom.fields.SFString} channelMask
+ * @memberof x3dom.nodeTypes.SurfaceShaderTexture
+ * @initvalue "DEFAULT"
+ * @range [rgb,abgr,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'channelMask', "DEFAULT");
+
+ /**
+ * Whether texture contains sRGB content and need to be linearized (NOT IMPLEMENTED!).
+ * @var {x3dom.fields.SFBool} isSRGB
+ * @memberof x3dom.nodeTypes.SurfaceShaderTexture
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'isSRGB', false);
+
+ /**
+ * The texture to use.
+ * @var {x3dom.fields.SFNode} texture
+ * @memberof x3dom.nodeTypes.SurfaceShaderTexture
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('texture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * An optional texture transform.
+ * @var {x3dom.fields.SFNode} textureTransform
+ * @memberof x3dom.nodeTypes.SurfaceShaderTexture
+ * @initvalue x3dom.nodeTypes.X3DTextureTransformNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('textureTransform', x3dom.nodeTypes.X3DTextureTransformNode);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DShaderNode ### */
+x3dom.registerNodeType(
+ "X3DShaderNode",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.X3DAppearanceChildNode,
+
+ /**
+ * Constructor for X3DShaderNode
+ * @constructs x3dom.nodeTypes.X3DShaderNode
+ * @x3d 3.3
+ * @component Shaders
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DAppearanceChildNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all node types that specify a programmable shader.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DShaderNode.superClass.call(this, ctx);
+
+
+ /**
+ * The language field is used to indicate to the browser which shading language is used for the source
+ * file(s). This field may be used as a hint for the browser if the shading language is not immediately
+ * determinable from the source (e.g., a generic MIME type of text/plain is returned). A browser may use
+ * this field for determining which node instance will be selected and to ignore languages that it is not
+ * capable of supporting. Three basic language types are defined for this specification and others may be
+ * optionally supported by a browser.
+ * @var {x3dom.fields.SFString} language
+ * @memberof x3dom.nodeTypes.X3DShaderNode
+ * @initvalue ""
+ * @range ["Cg"|"GLSL"|"HLSL"|...]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'language', "");
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### CommonSurfaceShader ### */
+x3dom.registerNodeType(
+ "CommonSurfaceShader",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.X3DShaderNode,
+
+ /**
+ * Constructor for CommonSurfaceShader
+ * @constructs x3dom.nodeTypes.CommonSurfaceShader
+ * @x3d x.x
+ * @component Shaders
+ * @extends x3dom.nodeTypes.X3DShaderNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc Implements the Blinn-Phong BRDF with normal mapping and a perfect specular component.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.CommonSurfaceShader.superClass.call(this, ctx);
+
+
+ /**
+ * Texture coordinate channel that contains the tangents in u.
+ * @var {x3dom.fields.SFInt32} tangentTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'tangentTextureCoordinatesId', -1);
+
+ /**
+ * Texture coordinate channel that contains the tangents in v.
+ * @var {x3dom.fields.SFInt32} binormalTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'binormalTextureCoordinatesId', -1);
+
+ /**
+ * The value of emissiveTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFVec3f} emissiveFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'emissiveFactor', 0, 0, 0);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} emissiveTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'emissiveTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for emissiveTexture.
+ * @var {x3dom.fields.SFInt32} emissiveTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'emissiveTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for emissiveTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} emissiveTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'emissiveTextureChannelMask', 'rgb');
+
+ /**
+ * The value of ambientTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFVec3f} ambientFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0.2,0.2,0.2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'ambientFactor', 0.2, 0.2, 0.2);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} ambientTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'ambientTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for ambientTexture.
+ * @var {x3dom.fields.SFInt32} ambientTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'ambientTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for ambientTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} ambientTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'ambientTextureChannelMask', 'rgb');
+
+ /**
+ * The value of diffuseTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFVec3f} diffuseFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0.8,0.8,0.8
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'diffuseFactor', 0.8, 0.8, 0.8);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} diffuseTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'diffuseTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for diffuseTexture.
+ * @var {x3dom.fields.SFInt32} diffuseTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'diffuseTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for diffuseTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} diffuseTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'diffuseTextureChannelMask', 'rgb');
+
+ /**
+ * The value of specularTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFVec3f} specularFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'specularFactor', 0, 0, 0);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} specularTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'specularTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for specularTexture.
+ * @var {x3dom.fields.SFInt32} specularTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'specularTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for specularTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} specularTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'specularTextureChannelMask', 'rgb');
+
+ /**
+ * The value of shininessTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFFloat} shininessFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0.2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'shininessFactor', 0.2);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} shininessTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'shininessTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for shininessTexture.
+ * @var {x3dom.fields.SFInt32} shininessTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'shininessTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for shininessTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} shininessTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'a'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'shininessTextureChannelMask', 'a');
+
+ /**
+ * How normals are stored in normalTexture. Currently only "UNORM" (each component packed into a
+ * [0,1] color channel) is supported.
+ * @var {x3dom.fields.SFString} normalFormat
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'UNORM'
+ * @range [UNORM]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'normalFormat', 'UNORM');
+
+ /**
+ * Space in which normals in normalTexture are defined. Currently only "TANGENT" (a default tangent space
+ * normal map) is supported.
+ * @var {x3dom.fields.SFString} normalSpace
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'TANGENT'
+ * @range [TANGENT]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'normalSpace', 'TANGENT');
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} normalTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'normalTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for normalTexture.
+ * @var {x3dom.fields.SFInt32} normalTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'normalTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for normalTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} normalTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'normalTextureChannelMask', 'rgb');
+
+ /**
+ * The value of reflectionTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFVec3f} reflectionFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'reflectionFactor', 0, 0, 0);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} reflectionTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'reflectionTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for reflectionTexture.
+ * @var {x3dom.fields.SFInt32} reflectionTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'reflectionTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for reflectionTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} reflectionTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'reflectionTextureChannelMask', 'rgb');
+
+ /**
+ * The value of transmissionTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFVec3f} transmissionFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'transmissionFactor', 0, 0, 0);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} transmissionTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'transmissionTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for transmissionTexture.
+ * @var {x3dom.fields.SFInt32} transmissionTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'transmissionTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for transmissionTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} transmissionTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'transmissionTextureChannelMask', 'rgb');
+
+ /**
+ * The value of environmentTexture is multiplied by this value. If no texture is set, the value is used
+ * directly.
+ * @var {x3dom.fields.SFVec3f} environmentFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 1,1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'environmentFactor', 1, 1, 1);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} environmentTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'environmentTextureId', -1);
+
+ /**
+ * [Currently not used, coordinates are computed in shader.]
+ * @var {x3dom.fields.SFInt32} environmentTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'environmentTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for environmentTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} environmentTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'rgb'
+ * @range [rgb,a,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'environmentTextureChannelMask', 'rgb');
+
+ /**
+ * Relative IOR for perfect specular component.
+ * @var {x3dom.fields.SFFloat} relativeIndexOfRefraction
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'relativeIndexOfRefraction', 1);
+
+ /**
+ * To what degree the Fresnel equation for dielectrics should be used to blend the perfect specular
+ * reflection and transmission.
+ * @var {x3dom.fields.SFFloat} fresnelBlend
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'fresnelBlend', 0);
+
+ /**
+ * Axis along which the vertices are displacement
+ * @var {x3dom.fields.SFString} displacementAxis
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'y'
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'displacementAxis', 'y');
+
+ /**
+ * Factor for the displacement.
+ * @var {x3dom.fields.SFFloat} displacementFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 255.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'displacementFactor', 255.0);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} displacementTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'displacementTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for displacementTexture.
+ * @var {x3dom.fields.SFInt32} displacementTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'displacementTextureCoordinatesId', 0);
+
+ /**
+ * Texture containing emissive component.
+ * @var {x3dom.fields.SFNode} emissiveTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('emissiveTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing ambient component.
+ * @var {x3dom.fields.SFNode} ambientTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('ambientTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing diffuse component.
+ * @var {x3dom.fields.SFNode} diffuseTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('diffuseTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing specular component.
+ * @var {x3dom.fields.SFNode} specularTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('specularTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing shininess component.
+ * @var {x3dom.fields.SFNode} shininessTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('shininessTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing normal component for normal mapping.
+ * @var {x3dom.fields.SFNode} normalTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('normalTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing reflection component.
+ * @var {x3dom.fields.SFNode} reflectionTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('reflectionTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing transmission component.
+ * @var {x3dom.fields.SFNode} transmissionTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('transmissionTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Cube texture containing the environment for perfect specular reflection and transmission.
+ * @var {x3dom.fields.SFNode} environmentTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('environmentTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing displacement component.
+ * @var {x3dom.fields.SFNode} displacementTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('displacementTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Texture containing diffuse displacement component.
+ * @var {x3dom.fields.SFNode} diffuseDisplacementTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('diffuseDisplacementTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Multi diffuse alpha texture.
+ * @var {x3dom.fields.SFNode} multiDiffuseAlphaTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('multiDiffuseAlphaTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Multi specular shininess texture.
+ * @var {x3dom.fields.SFNode} multiSpecularShininessTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('multiSpecularShininessTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Multi emissive ambientIntensity texture.
+ * @var {x3dom.fields.SFNode} multiEmmisiveAmbientIntensityTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('multiEmissiveAmbientTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Multi visibility texture.
+ * @var {x3dom.fields.SFNode} multiVisibilityTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('multiVisibilityTexture', x3dom.nodeTypes.X3DTextureNode);
+
+
+ //this.addField_MFBool(ctx, 'textureTransformEnabled', []); // MFBool NYI
+
+ /**
+ * scale to apply to normal sampled from normalTexture
+ * @var {x3dom.fields.SFVec3f} normalScale
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 2,2,2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'normalScale', 2, 2, 2);
+
+ /**
+ * Bias to apply to normal sampled from normalTexture
+ * @var {x3dom.fields.SFVec3f} normalBias
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1,-1,-1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'normalBias', -1, -1, -1);
+
+ /**
+ * The value of alphaTexture is multiplied by this value. If no texture is set, the value is used directly.
+ * @var {x3dom.fields.SFFloat} alphaFactor
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'alphaFactor', 1);
+
+ /**
+ * If true, (1-sampledValue) is used as alpha. If false the sampled value is used.
+ * @var {x3dom.fields.SFBool} invertAlphaTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'invertAlphaTexture', false);
+
+ /**
+ * The texture unit.
+ * @var {x3dom.fields.SFInt32} alphaTextureId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'alphaTextureId', -1);
+
+ /**
+ * Texture coordinate channel to use for alphaTexture.
+ * @var {x3dom.fields.SFInt32} alphaTextureCoordinatesId
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'alphaTextureCoordinatesId', 0);
+
+ /**
+ * ChannelMask for alphaTexture in the form of a glsl swizzle (e.g. "rgb", "a").
+ * @var {x3dom.fields.SFString} alphaTextureChannelMask
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue 'a'
+ * @range [a,rgb,..]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'alphaTextureChannelMask', 'a');
+
+ /**
+ * Texture containing alpha component.
+ * @var {x3dom.fields.SFNode} alphaTexture
+ * @memberof x3dom.nodeTypes.CommonSurfaceShader
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('alphaTexture', x3dom.nodeTypes.X3DTextureNode);
+
+ this._dirty = {
+ // TODO; cp. Shape, allow for dynamic texture updates in gfx
+ };
+
+ },
+ {
+ getDiffuseMap: function()
+ {
+ if(this._cf.diffuseTexture.node) {
+ if (x3dom.isa(this._cf.diffuseTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.diffuseTexture.node._cf.texture.node._type = "diffuseMap";
+ return this._cf.diffuseTexture.node._cf.texture.node;
+ } else {
+ this._cf.diffuseTexture.node._type = "diffuseMap";
+ return this._cf.diffuseTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getNormalMap: function()
+ {
+ if(this._cf.normalTexture.node) {
+ if (x3dom.isa(this._cf.normalTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.normalTexture.node._cf.texture.node._type = "normalMap";
+ return this._cf.normalTexture.node._cf.texture.node;
+ } else {
+ this._cf.normalTexture.node._type = "normalMap";
+ return this._cf.normalTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getAmbientMap: function()
+ {
+ if(this._cf.ambientTexture.node) {
+ if (x3dom.isa(this._cf.ambientTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.ambientTexture.node._cf.texture.node._type = "ambientMap";
+ return this._cf.ambientTexture.node._cf.texture.node;
+ } else {
+ this._cf.ambientTexture.node._type = "ambientMap";
+ return this._cf.ambientTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getSpecularMap: function()
+ {
+ if(this._cf.specularTexture.node) {
+ if (x3dom.isa(this._cf.specularTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.specularTexture.node._cf.texture.node._type = "specularMap";
+ return this._cf.specularTexture.node._cf.texture.node;
+ } else {
+ this._cf.specularTexture.node._type = "specularMap";
+ return this._cf.specularTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getShininessMap: function()
+ {
+ if(this._cf.shininessTexture.node) {
+ if (x3dom.isa(this._cf.shininessTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.shininessTexture.node._cf.texture.node._type = "shininessMap";
+ return this._cf.shininessTexture.node._cf.texture.node;
+ } else {
+ this._cf.shininessTexture.node._type = "shininessMap";
+ return this._cf.shininessTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getAlphaMap: function()
+ {
+ if(this._cf.alphaTexture.node) {
+ if (x3dom.isa(this._cf.alphaTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.alphaTexture.node._cf.texture.node._type = "alphaMap";
+ return this._cf.alphaTexture.node._cf.texture.node;
+ } else {
+ this._cf.alphaTexture.node._type = "alphaMap";
+ return this._cf.alphaTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getDisplacementMap: function()
+ {
+ if(this._cf.displacementTexture.node) {
+ if (x3dom.isa(this._cf.displacementTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.displacementTexture.node._cf.texture.node._type = "displacementMap";
+ return this._cf.displacementTexture.node._cf.texture.node;
+ } else {
+ this._cf.displacementTexture.node._type = "displacementMap";
+ return this._cf.displacementTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getDiffuseDisplacementMap: function()
+ {
+ if(this._cf.diffuseDisplacementTexture.node) {
+ if (x3dom.isa(this._cf.diffuseDisplacementTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.diffuseDisplacementTexture.node._cf.texture.node._type = "diffuseDisplacementMap";
+ return this._cf.diffuseDisplacementTexture.node._cf.texture.node;
+ } else {
+ this._cf.diffuseDisplacementTexture.node._type = "diffuseDisplacementMap";
+ return this._cf.diffuseDisplacementTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getMultiDiffuseAlphaMap: function()
+ {
+ if(this._cf.multiDiffuseAlphaTexture.node) {
+ if (x3dom.isa(this._cf.multiDiffuseAlphaTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.multiDiffuseAlphaTexture.node._cf.texture.node._type = "multiDiffuseAlphaMap";
+ return this._cf.multiDiffuseAlphaTexture.node._cf.texture.node;
+ } else {
+ this._cf.multiDiffuseAlphaTexture.node._type = "multiDiffuseAlphaMap";
+ return this._cf.multiDiffuseAlphaTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getMultiEmissiveAmbientMap: function()
+ {
+ if(this._cf.multiEmissiveAmbientTexture.node) {
+ if (x3dom.isa(this._cf.multiEmissiveAmbientTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.multiEmissiveAmbientTexture.node._cf.texture.node._type = "multiEmissiveAmbientMap";
+ return this._cf.multiEmissiveAmbientTexture.node._cf.texture.node;
+ } else {
+ this._cf.multiEmissiveAmbientTexture.node._type = "multiEmissiveAmbientMap";
+ return this._cf.multiEmissiveAmbientTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getMultiSpecularShininessMap: function()
+ {
+ if(this._cf.multiSpecularShininessTexture.node) {
+ if (x3dom.isa(this._cf.multiSpecularShininessTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.multiSpecularShininessTexture.node._cf.texture.node._type = "multiSpecularShininessMap";
+ return this._cf.multiSpecularShininessTexture.node._cf.texture.node;
+ } else {
+ this._cf.multiSpecularShininessTexture.node._type = "multiSpecularShininessMap";
+ return this._cf.multiSpecularShininessTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getMultiVisibilityMap: function()
+ {
+ if(this._cf.multiVisibilityTexture.node) {
+ if (x3dom.isa(this._cf.multiVisibilityTexture.node, x3dom.nodeTypes.SurfaceShaderTexture)) {
+ this._cf.multiVisibilityTexture.node._cf.texture.node._type = "multiVisibilityMap";
+ return this._cf.multiVisibilityTexture.node._cf.texture.node;
+ } else {
+ this._cf.multiVisibilityTexture.node._type = "multiVisibilityMap";
+ return this._cf.multiVisibilityTexture.node;
+ }
+ } else {
+ return null;
+ }
+ },
+
+ getTextures: function()
+ {
+ var textures = [];
+
+ var diff = this.getDiffuseMap();
+ if(diff) textures.push(diff);
+
+ var norm = this.getNormalMap();
+ if(norm) textures.push(norm);
+
+ var spec = this.getSpecularMap();
+ if(spec) textures.push(spec);
+
+ var shin = this.getShininessMap();
+ if(shin) textures.push(shin);
+
+ var displacement = this.getDisplacementMap();
+ if(displacement) textures.push(displacement);
+
+ var diffuseDisplacement = this.getDiffuseDisplacementMap();
+ if(diffuseDisplacement) textures.push(diffuseDisplacement);
+
+ var multiDiffuseAlpha = this.getMultiDiffuseAlphaMap();
+ if(multiDiffuseAlpha) textures.push(multiDiffuseAlpha);
+
+ var multiEmissiveAmbient = this.getMultiEmissiveAmbientMap();
+ if(multiEmissiveAmbient) textures.push(multiEmissiveAmbient);
+
+ var multiSpecularShininess = this.getMultiSpecularShininessMap();
+ if(multiSpecularShininess) textures.push(multiSpecularShininess);
+
+ var multiVisibility = this.getMultiVisibilityMap();
+ if(multiVisibility) textures.push(multiVisibility);
+
+ return textures;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ComposedShader ### */
+x3dom.registerNodeType(
+ "ComposedShader",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.X3DShaderNode,
+
+ /**
+ * Constructor for ComposedShader
+ * @constructs x3dom.nodeTypes.ComposedShader
+ * @x3d 3.3
+ * @component Shaders
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DShaderNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ComposedShader node defines a shader where the individual source files are not individually
+ * programmable. All access to the shading capabilities is defined through a single interface that applies to
+ * all parts.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ComposedShader.superClass.call(this, ctx);
+
+
+ /**
+ * Contains all fields of shader parts.
+ * @var {x3dom.fields.MFNode} fields
+ * @memberof x3dom.nodeTypes.ComposedShader
+ * @initvalue x3dom.nodeTypes.Field
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('fields', x3dom.nodeTypes.Field);
+
+ /**
+ * List of shader parts.
+ * @var {x3dom.fields.MFNode} parts
+ * @memberof x3dom.nodeTypes.ComposedShader
+ * @initvalue x3dom.nodeTypes.ShaderPart
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('parts', x3dom.nodeTypes.ShaderPart);
+
+ // shortcut to shader parts
+ this._vertex = null;
+ this._fragment = null;
+ this._id = null;
+
+ if (!x3dom.nodeTypes.ComposedShader.ShaderInfoMsgShown) {
+ x3dom.debug.logInfo("Current ComposedShader node implementation limitations:\n" +
+ "Vertex attributes (if given in the standard X3D fields 'coord', 'color', " +
+ "'normal', 'texCoord'), matrices and texture are provided as follows...\n" +
+ "(see also <a href='http://x3dom.org/x3dom/doc/help/composedShader.html'>" +
+ "http://x3dom.org/x3dom/doc/help/composedShader.html</a>)\n" +
+ " attribute vec3 position;\n" +
+ " attribute vec3 normal;\n" +
+ " attribute vec2 texcoord;\n" +
+ " attribute vec3 color;\n" +
+ " uniform mat4 modelViewProjectionMatrix;\n" +
+ " uniform mat4 modelViewMatrix;\n" +
+ " uniform mat4 normalMatrix;\n" +
+ " uniform mat4 viewMatrix;\n" +
+ " uniform sampler2D tex;\n");
+ x3dom.nodeTypes.ComposedShader.ShaderInfoMsgShown = true;
+ }
+
+ },
+ {
+ nodeChanged: function()
+ {
+ var i, n = this._cf.parts.nodes.length;
+
+ for (i=0; i<n; i++)
+ {
+ if (this._cf.parts.nodes[i]._vf.type.toLowerCase() == 'vertex') {
+ this._vertex = this._cf.parts.nodes[i];
+ this._id = this._cf.parts.nodes[i]._id;
+ }
+ else if (this._cf.parts.nodes[i]._vf.type.toLowerCase() == 'fragment') {
+ this._fragment = this._cf.parts.nodes[i];
+ this._id += " - " + this._cf.parts.nodes[i]._id;
+ }
+ }
+
+ var ctx = {};
+ n = this._cf.fields.nodes.length;
+
+ for (i=0; i<n; i++)
+ {
+ var fieldName = this._cf.fields.nodes[i]._vf.name;
+ ctx.xmlNode = this._cf.fields.nodes[i]._xmlNode;
+
+ var needNode = false;
+
+ if (ctx.xmlNode === undefined || ctx.xmlNode === null) {
+ ctx.xmlNode = document.createElement("field");
+ needNode = true;
+ }
+
+ ctx.xmlNode.setAttribute(fieldName, this._cf.fields.nodes[i]._vf.value);
+
+ var funcName = "this.addField_" + this._cf.fields.nodes[i]._vf.type + "(ctx, name);";
+ var func = new Function('ctx', 'name', funcName);
+
+ func.call(this, ctx, fieldName);
+
+ if (needNode) {
+ ctx.xmlNode = null; // cleanup
+ }
+ }
+
+ Array.forEach(this._parentNodes, function (app) {
+ Array.forEach(app._parentNodes, function (shape) {
+ //shape.setAppDirty();
+ if (shape._cleanupGLObjects)
+ shape._cleanupGLObjects();
+ shape.setAllDirty();
+ });
+ });
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ var i, n = this._cf.fields.nodes.length;
+
+ for (i=0; i<n; i++)
+ {
+ var field = this._cf.fields.nodes[i]._vf.name;
+
+ if (field === fieldName)
+ {
+ var msg = this._cf.fields.nodes[i]._vf.value;
+
+ try {
+ this._vf[field].setValueByStr(msg);
+ }
+ catch (exc1) {
+ try {
+ switch ((typeof(this._vf[field])).toString()) {
+ case "number":
+ this._vf[field] = +msg;
+ break;
+ case "boolean":
+ this._vf[field] = (msg.toLowerCase() === "true");
+ break;
+ case "string":
+ this._vf[field] = msg;
+ break;
+ }
+ }
+ catch (exc2) {
+ x3dom.debug.logError("setValueByStr() NYI for " + typeof(this._vf[field]));
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (field === 'url')
+ {
+ Array.forEach(this._parentNodes, function (app) {
+ Array.forEach(app._parentNodes, function (shape) {
+ shape._dirty.shader = true;
+ });
+ });
+ }
+ },
+
+ parentAdded: function(parent)
+ {
+ //Array.forEach(this._parentNodes, function (app) {
+ // app.nodeChanged();
+ //});
+ parent.nodeChanged();
+ }
+ }
+ )
+);
+
+x3dom.nodeTypes.ComposedShader.ShaderInfoMsgShown = false;
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ShaderPart ### */
+x3dom.registerNodeType(
+ "ShaderPart",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.X3DNode,
+
+ /**
+ * Constructor for ShaderPart
+ * @constructs x3dom.nodeTypes.ShaderPart
+ * @x3d 3.3
+ * @component Shaders
+ * @status full
+ * @extends x3dom.nodeTypes.X3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ShaderPart node defines the source for a single object to be used by a ComposedShader node.
+ * The source is not required to be a complete shader for all of the vertex/fragment processing.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ShaderPart.superClass.call(this, ctx);
+
+
+ /**
+ * The shader source is read from the URL specified by the url field. When the url field contains no values
+ * ([]), this object instance is ignored.
+ * @var {x3dom.fields.MFString} url
+ * @memberof x3dom.nodeTypes.ShaderPart
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFString(ctx, 'url', []);
+
+ /**
+ * The type field indicates whether this object shall be compiled as a vertex shader, fragment shader, or
+ * other future-defined shader type.
+ * @var {x3dom.fields.SFString} type
+ * @memberof x3dom.nodeTypes.ShaderPart
+ * @initvalue "VERTEX"
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'type', "VERTEX");
+
+ this._id = (ctx && ctx.xmlNode && ctx.xmlNode.id != "") ?
+ ctx.xmlNode.id : ++x3dom.nodeTypes.Shape.shaderPartID;
+
+ x3dom.debug.assert(this._vf.type.toLowerCase() == 'vertex' ||
+ this._vf.type.toLowerCase() == 'fragment',
+ "Unknown shader part type!");
+ },
+ {
+ nodeChanged: function()
+ {
+ var ctx = {};
+ ctx.xmlNode = this._xmlNode;
+
+ if (ctx.xmlNode !== undefined && ctx.xmlNode !== null)
+ {
+ var that = this;
+
+ if (that._vf.url.length && that._vf.url[0].indexOf('\n') == -1)
+ {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", that._nameSpace.getURL(that._vf.url[0]), false);
+ xhr.onload = function() {
+ that._vf.url = new x3dom.fields.MFString( [] );
+ that._vf.url.push(xhr.response);
+ };
+ xhr.onerror = function() {
+ x3dom.debug.logError("Could not load file '" + that._vf.url[0] + "'.");
+ };
+ xhr.send(null);
+ }
+ else
+ {
+ if (that._vf.url.length) {
+ that._vf.url = new x3dom.fields.MFString( [] );
+ }
+ try {
+ that._vf.url.push(ctx.xmlNode.childNodes[1].nodeValue);
+ ctx.xmlNode.removeChild(ctx.xmlNode.childNodes[1]);
+ }
+ catch(e) {
+ Array.forEach( ctx.xmlNode.childNodes, function (childDomNode) {
+ if (childDomNode.nodeType === 3) {
+ that._vf.url.push(childDomNode.nodeValue);
+ }
+ else if (childDomNode.nodeType === 4) {
+ that._vf.url.push(childDomNode.data);
+ }
+ childDomNode.parentNode.removeChild(childDomNode);
+ } );
+ }
+ }
+ }
+ // else hope that url field was already set somehow
+
+ Array.forEach(this._parentNodes, function (shader) {
+ shader.nodeChanged();
+ });
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName === "url") {
+ Array.forEach(this._parentNodes, function (shader) {
+ shader.fieldChanged("url");
+ });
+ }
+ },
+
+ parentAdded: function(parent)
+ {
+ //Array.forEach(this._parentNodes, function (shader) {
+ // shader.nodeChanged();
+ //});
+ parent.nodeChanged();
+ }
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DVertexAttributeNode ### */
+x3dom.registerNodeType(
+ "X3DVertexAttributeNode",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.X3DGeometricPropertyNode,
+
+ /**
+ * Constructor for X3DVertexAttributeNode
+ * @constructs x3dom.nodeTypes.X3DVertexAttributeNode
+ * @x3d 3.3
+ * @component Shaders
+ * @status full
+ * @extends x3dom.nodeTypes.X3DGeometricPropertyNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all node types that specify per-vertex attribute
+ * information to the shader.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DVertexAttributeNode.superClass.call(this, ctx);
+
+
+ /**
+ * The name field describes a name that is mapped to the shading language-specific name for describing
+ * per-vertex data. The appropriate shader language annex contains language-specific binding information.
+ * @var {x3dom.fields.SFString} name
+ * @memberof x3dom.nodeTypes.X3DVertexAttributeNode
+ * @initvalue ""
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFString(ctx, 'name', "");
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### FloatVertexAttribute ### */
+x3dom.registerNodeType(
+ "FloatVertexAttribute",
+ "Shaders",
+ defineClass(x3dom.nodeTypes.X3DVertexAttributeNode,
+
+ /**
+ * Constructor for FloatVertexAttribute
+ * @constructs x3dom.nodeTypes.FloatVertexAttribute
+ * @x3d 3.3
+ * @component Shaders
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DVertexAttributeNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The FloatVertexAttribute node defines a set of per-vertex single-precision floating point
+ * attributes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.FloatVertexAttribute.superClass.call(this, ctx);
+
+
+ /**
+ * The numComponents field specifies how many consecutive floating point values should be grouped together
+ * per vertex. The length of the value field shall be a multiple of numComponents.
+ * @var {x3dom.fields.SFInt32} numComponents
+ * @memberof x3dom.nodeTypes.FloatVertexAttribute
+ * @initvalue 4
+ * @range [1..4]
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'numComponents', 4);
+
+ /**
+ * The value field specifies an arbitrary collection of floating point values that will be passed to the
+ * shader as per-vertex information. The specific type mapping to the individual shading language data
+ * types is in the appropriate language-specific annex.
+ * @var {x3dom.fields.MFFloat} value
+ * @memberof x3dom.nodeTypes.FloatVertexAttribute
+ * @initvalue []
+ * @range (-inf, inf)
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFFloat(ctx, 'value', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DSpatialGeometryNode ### */
+x3dom.registerNodeType(
+ "X3DSpatialGeometryNode",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DGeometryNode,
+
+ /**
+ * Constructor for X3DSpatialGeometryNode
+ * @constructs x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @x3d x.x
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This is the abstract node for spatial geometry nodes.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DSpatialGeometryNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Plane ### */
+x3dom.registerNodeType(
+ "Plane",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for Plane
+ * @constructs x3dom.nodeTypes.Plane
+ * @x3d x.x
+ * @component Geometry3D
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @class The plane node describes a plane shape that extents in x and y direction.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Plane.superClass.call(this, ctx);
+
+
+ /**
+ * The edge lengths of the plane.
+ * @var {x3dom.fields.SFVec2f} size
+ * @memberof x3dom.nodeTypes.Plane
+ * @initvalue 2,2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'size', 2, 2);
+
+ /**
+ * Defines the number of single elements that are generated to represent the plane.
+ * @var {x3dom.fields.SFVec2f} subdivision
+ * @memberof x3dom.nodeTypes.Plane
+ * @initvalue 1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'subdivision', 1, 1);
+
+ /**
+ * Defines the center point in the local coordinate system.
+ * @var {x3dom.fields.SFVec3f} center
+ * @memberof x3dom.nodeTypes.Plane
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'center', 0, 0, 0);
+
+ /**
+ * Specifies the primitive type that is used to build the plane.
+ * @var {x3dom.fields.MFString} primType
+ * @memberof x3dom.nodeTypes.Plane
+ * @initvalue ['TRIANGLES']
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'primType', ['TRIANGLES']);
+
+ // this way currently an initialize only field
+ if (this._vf.primType.length)
+ this._mesh._primType = this._vf.primType[0];
+
+ var sx = this._vf.size.x, sy = this._vf.size.y;
+ var subx = this._vf.subdivision.x, suby = this._vf.subdivision.y;
+
+ var geoCacheID = 'Plane_' + sx + '-' + sy + '-' + subx + '-' + suby + '-' +
+ this._vf.center.x + '-' + this._vf.center.y + '-' + this._vf.center.z;
+
+ // Attention: DynamicLOD node internally creates Plane nodes, but MUST NOT
+ // use geoCache, therefore only use cache if "ctx" is defined!
+ // TODO: move mesh generation of all primitives to nodeChanged()
+ if (ctx && this._vf.useGeoCache && x3dom.geoCache[geoCacheID] !== undefined) {
+ //x3dom.debug.logInfo("Using Plane from Cache");
+ this._mesh = x3dom.geoCache[geoCacheID];
+ }
+ else {
+ var x = 0, y = 0;
+ var xstep = sx / subx;
+ var ystep = sy / suby;
+
+ sx /= 2; sy /= 2;
+
+ for (y = 0; y <= suby; y++) {
+ for (x = 0; x <= subx; x++) {
+ this._mesh._positions[0].push(this._vf.center.x + x * xstep - sx);
+ this._mesh._positions[0].push(this._vf.center.y + y * ystep - sy);
+ this._mesh._positions[0].push(this._vf.center.z);
+ this._mesh._normals[0].push(0);
+ this._mesh._normals[0].push(0);
+ this._mesh._normals[0].push(1);
+ this._mesh._texCoords[0].push(x / subx);
+ this._mesh._texCoords[0].push(y / suby);
+ }
+ }
+
+ for (y = 1; y <= suby; y++) {
+ for (x = 0; x < subx; x++) {
+ this._mesh._indices[0].push((y - 1) * (subx + 1) + x);
+ this._mesh._indices[0].push((y - 1) * (subx + 1) + x + 1);
+ this._mesh._indices[0].push(y * (subx + 1) + x);
+
+ this._mesh._indices[0].push(y * (subx + 1) + x);
+ this._mesh._indices[0].push((y - 1) * (subx + 1) + x + 1);
+ this._mesh._indices[0].push(y * (subx + 1) + x + 1);
+ }
+ }
+
+ this._mesh._invalidate = true;
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ x3dom.geoCache[geoCacheID] = this._mesh;
+ }
+
+ },
+ {
+ fieldChanged: function (fieldName) {
+ if (fieldName == "size" || fieldName == "center") {
+ this._mesh._positions[0] = [];
+
+ var sx = this._vf.size.x, sy = this._vf.size.y;
+ var subx = this._vf.subdivision.x, suby = this._vf.subdivision.y;
+ var x = 0, y = 0;
+ var xstep = sx / subx;
+ var ystep = sy / suby;
+
+ sx /= 2; sy /= 2;
+
+ for (y = 0; y <= suby; y++) {
+ for (x = 0; x <= subx; x++) {
+ this._mesh._positions[0].push(this._vf.center.x + x * xstep - sx);
+ this._mesh._positions[0].push(this._vf.center.y + y * ystep - sy);
+ this._mesh._positions[0].push(this._vf.center.z);
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "subdivision") {
+ this._mesh._positions[0] = [];
+ this._mesh._indices[0] = [];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+
+ var sx = this._vf.size.x, sy = this._vf.size.y;
+ var subx = this._vf.subdivision.x, suby = this._vf.subdivision.y;
+
+ var x = 0, y = 0;
+ var xstep = sx / subx;
+ var ystep = sy / suby;
+
+ sx /= 2; sy /= 2;
+
+ for (y = 0; y <= suby; y++) {
+ for (x = 0; x <= subx; x++) {
+ this._mesh._positions[0].push(this._vf.center.x + x * xstep - sx);
+ this._mesh._positions[0].push(this._vf.center.y + y * ystep - sy);
+ this._mesh._positions[0].push(this._vf.center.z);
+ this._mesh._normals[0].push(0);
+ this._mesh._normals[0].push(0);
+ this._mesh._normals[0].push(1);
+ this._mesh._texCoords[0].push(x / subx);
+ this._mesh._texCoords[0].push(y / suby);
+ }
+ }
+
+ for (y = 1; y <= suby; y++) {
+ for (x = 0; x < subx; x++) {
+ this._mesh._indices[0].push((y - 1) * (subx + 1) + x);
+ this._mesh._indices[0].push((y - 1) * (subx + 1) + x + 1);
+ this._mesh._indices[0].push(y * (subx + 1) + x);
+
+ this._mesh._indices[0].push(y * (subx + 1) + x);
+ this._mesh._indices[0].push((y - 1) * (subx + 1) + x + 1);
+ this._mesh._indices[0].push(y * (subx + 1) + x + 1);
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node.setAllDirty();
+ node.invalidateVolume();
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Box ### */
+x3dom.registerNodeType(
+ "Box",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for Box
+ * @constructs x3dom.nodeTypes.Box
+ * @x3d 3.3
+ * @component Geometry3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Box node specifies a rectangular parallelepiped box centred at (0, 0, 0) in the local coordinate system and aligned with the local coordinate axes. By default, the box measures 2 units in each dimension, from -1 to +1.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Box.superClass.call(this, ctx);
+
+
+ /**
+ * The size field specifies the extents of the box along the X-, Y-, and Z-axes respectively and each component value shall be greater than zero.
+ * @var {x3dom.fields.SFVec3f} size
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Box
+ * @initvalue 2,2,2
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'size', 2, 2, 2);
+
+ /**
+ * Specifies whether helper colors should be used, which will color each vertex with a different color. This will overwrite the color of the corresponding appearance node.
+ * @var {x3dom.fields.SFBool} hasHelperColors
+ * @memberof x3dom.nodeTypes.Box
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'hasHelperColors', false);
+
+ var sx = this._vf.size.x,
+ sy = this._vf.size.y,
+ sz = this._vf.size.z;
+
+ var geoCacheID = 'Box_'+sx+'-'+sy+'-'+sz;
+
+ if( this._vf.useGeoCache && x3dom.geoCache[geoCacheID] !== undefined )
+ {
+ //x3dom.debug.logInfo("Using Box from Cache");
+ this._mesh = x3dom.geoCache[geoCacheID];
+ }
+ else
+ {
+ sx /= 2; sy /= 2; sz /= 2;
+
+ this._mesh._positions[0] = [
+ -sx,-sy,-sz, -sx, sy,-sz, sx, sy,-sz, sx,-sy,-sz, //hinten 0,0,-1
+ -sx,-sy, sz, -sx, sy, sz, sx, sy, sz, sx,-sy, sz, //vorne 0,0,1
+ -sx,-sy,-sz, -sx,-sy, sz, -sx, sy, sz, -sx, sy,-sz, //links -1,0,0
+ sx,-sy,-sz, sx,-sy, sz, sx, sy, sz, sx, sy,-sz, //rechts 1,0,0
+ -sx, sy,-sz, -sx, sy, sz, sx, sy, sz, sx, sy,-sz, //oben 0,1,0
+ -sx,-sy,-sz, -sx,-sy, sz, sx,-sy, sz, sx,-sy,-sz //unten 0,-1,0
+ ];
+ this._mesh._normals[0] = [
+ 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1,
+ 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+ -1,0,0, -1,0,0, -1,0,0, -1,0,0,
+ 1,0,0, 1,0,0, 1,0,0, 1,0,0,
+ 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+ 0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0
+ ];
+ this._mesh._texCoords[0] = [
+ 1,0, 1,1, 0,1, 0,0,
+ 0,0, 0,1, 1,1, 1,0,
+ 0,0, 1,0, 1,1, 0,1,
+ 1,0, 0,0, 0,1, 1,1,
+ 0,1, 0,0, 1,0, 1,1,
+ 0,0, 0,1, 1,1, 1,0
+ ];
+ if (this._vf.hasHelperColors) {
+ this._mesh._colors[0] = [
+ 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0
+ ];
+ }
+ this._mesh._indices[0] = [
+ 0,1,2, 2,3,0,
+ 4,7,5, 5,7,6,
+ 8,9,10, 10,11,8,
+ 12,14,13, 14,12,15,
+ 16,17,18, 18,19,16,
+ 20,22,21, 22,20,23
+ ];
+ this._mesh._invalidate = true;
+ this._mesh._numFaces = 12;
+ this._mesh._numCoords = 24;
+
+ x3dom.geoCache[geoCacheID] = this._mesh;
+ }
+
+ },
+ {
+ fieldChanged: function (fieldName)
+ {
+ if (fieldName === "size") {
+ var sx = this._vf.size.x / 2,
+ sy = this._vf.size.y / 2,
+ sz = this._vf.size.z / 2;
+
+ this._mesh._positions[0] = [
+ -sx,-sy,-sz, -sx, sy,-sz, sx, sy,-sz, sx,-sy,-sz, //back 0,0,-1
+ -sx,-sy, sz, -sx, sy, sz, sx, sy, sz, sx,-sy, sz, //front 0,0,1
+ -sx,-sy,-sz, -sx,-sy, sz, -sx, sy, sz, -sx, sy,-sz, //left -1,0,0
+ sx,-sy,-sz, sx,-sy, sz, sx, sy, sz, sx, sy,-sz, //right 1,0,0
+ -sx, sy,-sz, -sx, sy, sz, sx, sy, sz, sx, sy,-sz, //top 0,1,0
+ -sx,-sy,-sz, -sx,-sy, sz, sx,-sy, sz, sx,-sy,-sz //bottom 0,-1,0
+ ];
+
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName === "hasHelperColors") {
+ if (this._vf.hasHelperColors) {
+ this._mesh._colors[0] = [
+ 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0
+ ];
+ }
+ else {
+ this._mesh._colors[0] = [];
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Sphere ### */
+x3dom.registerNodeType(
+ "Sphere",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for Sphere
+ * @constructs x3dom.nodeTypes.Sphere
+ * @x3d 3.3
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Sphere node specifies a sphere centred at (0, 0, 0) in the local coordinate system.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Sphere.superClass.call(this, ctx);
+
+ // sky box background creates sphere with r = 10000
+
+ /**
+ * The radius field specifies the radius of the sphere.
+ * @var {x3dom.fields.SFFloat} radius
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Sphere
+ * @initvalue ctx?1:10000
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'radius', ctx ? 1 : 10000);
+
+ /**
+ * Specifies the number of faces that are generated to approximate the surface of the sphere.
+ * @var {x3dom.fields.SFVec2f} subdivision
+ * @memberof x3dom.nodeTypes.Sphere
+ * @initvalue 24,24
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'subdivision', 24, 24);
+
+ var qfactor = 1.0;
+ var r = this._vf.radius;
+ var subx = this._vf.subdivision.x, suby = this._vf.subdivision.y;
+
+ var geoCacheID = 'Sphere_' + r + '-' + subx + '-' + suby;
+
+ if (this._vf.useGeoCache && x3dom.geoCache[geoCacheID] !== undefined) {
+ //x3dom.debug.logInfo("Using Sphere from Cache");
+ this._mesh = x3dom.geoCache[geoCacheID];
+ }
+ else {
+ if(ctx) {
+ qfactor = ctx.doc.properties.getProperty("PrimitiveQuality", "Medium");
+ }
+ if (!x3dom.Utils.isNumber(qfactor)) {
+ switch (qfactor.toLowerCase()) {
+ case "low":
+ qfactor = 0.3;
+ break;
+ case "medium":
+ qfactor = 0.5;
+ break;
+ case "high":
+ qfactor = 1.0;
+ break;
+ }
+ } else {
+ qfactor = parseFloat(qfactor);
+ }
+
+ this._quality = qfactor;
+
+ var latNumber, longNumber;
+ var latitudeBands = Math.floor(subx * qfactor);
+ var longitudeBands = Math.floor(suby * qfactor);
+
+ var theta, sinTheta, cosTheta;
+ var phi, sinPhi, cosPhi;
+ var x, y, z, u, v;
+
+ for (latNumber = 0; latNumber <= latitudeBands; latNumber++) {
+ theta = (latNumber * Math.PI) / latitudeBands;
+ sinTheta = Math.sin(theta);
+ cosTheta = Math.cos(theta);
+
+ for (longNumber = 0; longNumber <= longitudeBands; longNumber++) {
+ phi = (longNumber * 2.0 * Math.PI) / longitudeBands;
+ sinPhi = Math.sin(phi);
+ cosPhi = Math.cos(phi);
+
+ x = -cosPhi * sinTheta;
+ y = -cosTheta;
+ z = -sinPhi * sinTheta;
+
+ u = 0.25 - (longNumber / longitudeBands);
+ v = latNumber / latitudeBands;
+
+ this._mesh._positions[0].push(r * x);
+ this._mesh._positions[0].push(r * y);
+ this._mesh._positions[0].push(r * z);
+ this._mesh._normals[0].push(x);
+ this._mesh._normals[0].push(y);
+ this._mesh._normals[0].push(z);
+ this._mesh._texCoords[0].push(u);
+ this._mesh._texCoords[0].push(v);
+ }
+ }
+
+ var first, second;
+
+ for (latNumber = 0; latNumber < latitudeBands; latNumber++) {
+ for (longNumber = 0; longNumber < longitudeBands; longNumber++) {
+ first = (latNumber * (longitudeBands + 1)) + longNumber;
+ second = first + longitudeBands + 1;
+
+ this._mesh._indices[0].push(first);
+ this._mesh._indices[0].push(second);
+ this._mesh._indices[0].push(first + 1);
+
+ this._mesh._indices[0].push(second);
+ this._mesh._indices[0].push(second + 1);
+ this._mesh._indices[0].push(first + 1);
+ }
+ }
+
+ this._mesh._invalidate = true;
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ x3dom.geoCache[geoCacheID] = this._mesh;
+ }
+
+ },
+ {
+ fieldChanged: function(fieldName) {
+ if (fieldName === "radius") {
+ this._mesh._positions[0] = [];
+ var r = this._vf.radius;
+ var subx = this._vf.subdivision.x, suby = this._vf.subdivision.y;
+ var qfactor = this._quality;
+
+ var latNumber, longNumber;
+ var latitudeBands = Math.floor(subx * qfactor);
+ var longitudeBands = Math.floor(suby * qfactor);
+
+ var theta, sinTheta, cosTheta;
+ var phi, sinPhi, cosPhi;
+ var x, y, z;
+
+ for (latNumber = 0; latNumber <= latitudeBands; latNumber++) {
+ theta = (latNumber * Math.PI) / latitudeBands;
+ sinTheta = Math.sin(theta);
+ cosTheta = Math.cos(theta);
+
+ for (longNumber = 0; longNumber <= longitudeBands; longNumber++) {
+ phi = (longNumber * 2.0 * Math.PI) / longitudeBands;
+ sinPhi = Math.sin(phi);
+ cosPhi = Math.cos(phi);
+
+ x = -cosPhi * sinTheta;
+ y = -cosTheta;
+ z = -sinPhi * sinTheta;
+
+ this._mesh._positions[0].push(r * x);
+ this._mesh._positions[0].push(r * y);
+ this._mesh._positions[0].push(r * z);
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName === "subdivision") {
+ this._mesh._positions[0] = [];
+ this._mesh._indices[0] =[];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] =[];
+
+ var r = this._vf.radius;
+ var subx = this._vf.subdivision.x, suby = this._vf.subdivision.y;
+ var qfactor = this._quality;
+
+ var latNumber, longNumber;
+ var latitudeBands = Math.floor(subx * qfactor);
+ var longitudeBands = Math.floor(suby * qfactor);
+
+ var theta, sinTheta, cosTheta;
+ var phi, sinPhi, cosPhi;
+ var x, y, z, u, v;
+
+ for (latNumber = 0; latNumber <= latitudeBands; latNumber++) {
+ theta = (latNumber * Math.PI) / latitudeBands;
+ sinTheta = Math.sin(theta);
+ cosTheta = Math.cos(theta);
+
+ for (longNumber = 0; longNumber <= longitudeBands; longNumber++) {
+ phi = (longNumber * 2.0 * Math.PI) / longitudeBands;
+ sinPhi = Math.sin(phi);
+ cosPhi = Math.cos(phi);
+
+ x = -cosPhi * sinTheta;
+ y = -cosTheta;
+ z = -sinPhi * sinTheta;
+
+ u = 0.25 - (longNumber / longitudeBands);
+ v = latNumber / latitudeBands;
+
+ this._mesh._positions[0].push(r * x);
+ this._mesh._positions[0].push(r * y);
+ this._mesh._positions[0].push(r * z);
+ this._mesh._normals[0].push(x);
+ this._mesh._normals[0].push(y);
+ this._mesh._normals[0].push(z);
+ this._mesh._texCoords[0].push(u);
+ this._mesh._texCoords[0].push(v);
+ }
+ }
+
+ var first, second;
+
+ for (latNumber = 0; latNumber < latitudeBands; latNumber++) {
+ for (longNumber = 0; longNumber < longitudeBands; longNumber++) {
+ first = (latNumber * (longitudeBands + 1)) + longNumber;
+ second = first + longitudeBands + 1;
+
+ this._mesh._indices[0].push(first);
+ this._mesh._indices[0].push(second);
+ this._mesh._indices[0].push(first + 1);
+
+ this._mesh._indices[0].push(second);
+ this._mesh._indices[0].push(second + 1);
+ this._mesh._indices[0].push(first + 1);
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node.setAllDirty();
+ node.invalidateVolume();
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Torus ### */
+x3dom.registerNodeType(
+ "Torus",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for Torus
+ * @constructs x3dom.nodeTypes.Torus
+ * @x3d x.x
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Torus node specifies a torus shape centred at (0, 0, 0) in the local coordinate system.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Torus.superClass.call(this, ctx);
+
+ var twoPi = 2.0 * Math.PI;
+
+
+ /**
+ * Specifies the inner radius of the torus.
+ * @var {x3dom.fields.SFFloat} innerRadius
+ * @memberof x3dom.nodeTypes.Torus
+ * @initvalue 0.5
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'innerRadius', 0.5);
+
+ /**
+ * Specifies the outer radius of the torus.
+ * @var {x3dom.fields.SFFloat} outerRadius
+ * @memberof x3dom.nodeTypes.Torus
+ * @initvalue 1.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'outerRadius', 1.0);
+
+ /**
+ * Specifies the size of the torus as an angle.
+ * @var {x3dom.fields.SFFloat} angle
+ * @range [0, 2*pi]
+ * @memberof x3dom.nodeTypes.Torus
+ * @initvalue twoPi
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'angle', twoPi);
+
+ /**
+ * Specifies whether the torus ends are closed with caps (when angle is smaller than a full circle).
+ * @var {x3dom.fields.SFBool} caps
+ * @memberof x3dom.nodeTypes.Torus
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'caps', true);
+
+ /**
+ * Specifies the number of faces that are generated to approximate the torus.
+ * @var {x3dom.fields.SFVec2f} subdivision
+ * @memberof x3dom.nodeTypes.Torus
+ * @initvalue 24,24
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'subdivision', 24, 24);
+
+ /**
+ * Use a different interpretation mode for the inside and outside radius.
+ * @var {x3dom.fields.SFBool} insideOutsideRadius
+ * @memberof x3dom.nodeTypes.Torus
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'insideOutsideRadius', false);
+
+ // assure that angle in [0, 2 * PI]
+ if (this._vf.angle < 0)
+ this._vf.angle = 0;
+ else if (this._vf.angle > twoPi)
+ this._vf.angle = twoPi;
+
+ this._origCCW = this._vf.ccw;
+
+ var innerRadius = this._vf.innerRadius;
+ var outerRadius = this._vf.outerRadius;
+
+ if (this._vf.insideOutsideRadius == true)
+ {
+ if (innerRadius > outerRadius) {
+ var tmp = innerRadius;
+ innerRadius = outerRadius;
+ outerRadius = tmp;
+ }
+
+ var rad = (outerRadius - innerRadius) / 2;
+
+ outerRadius = innerRadius + rad;
+ innerRadius = rad;
+
+ // fix wrong face orientation in case of clockwise rotation
+ this._vf.ccw = !this._origCCW;
+ }
+
+ var rings = this._vf.subdivision.x, sides = this._vf.subdivision.y;
+ rings = Math.max(3, Math.round((this._vf.angle / twoPi) * rings));
+
+ // FIXME; check/update geoCache on field update (for ALL primitives)!
+ var geoCacheID = 'Torus_'+innerRadius+'_'+outerRadius+'_'+this._vf.angle+'_'+
+ this._vf.subdivision+'-'+this._vf.caps;
+
+ if( this._vf.useGeoCache && x3dom.geoCache[geoCacheID] !== undefined )
+ {
+ //x3dom.debug.logInfo("Using Torus from Cache");
+ this._mesh = x3dom.geoCache[geoCacheID];
+ }
+ else
+ {
+ var ringDelta = this._vf.angle / rings;
+ var sideDelta = twoPi / sides;
+ var a, b, theta, phi;
+ var cosTheta, sinTheta, cosPhi, sinPhi, dist;
+
+ for (a=0, theta=0; a <= rings; a++, theta+=ringDelta)
+ {
+ cosTheta = Math.cos(theta);
+ sinTheta = Math.sin(theta);
+
+ for (b=0, phi=0; b<=sides; b++, phi+=sideDelta)
+ {
+ cosPhi = Math.cos(phi);
+ sinPhi = Math.sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(cosTheta * dist, innerRadius * sinPhi, -sinTheta * dist);
+ this._mesh._normals[0].push(cosTheta * cosPhi, sinPhi, -sinTheta * cosPhi);
+ }
+ else {
+ this._mesh._positions[0].push(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi);
+ this._mesh._normals[0].push(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
+ }
+ this._mesh._texCoords[0].push(-a / rings, b / sides);
+ }
+ }
+
+ for (a=0; a<sides; a++)
+ {
+ for (b=0; b<rings; b++)
+ {
+ this._mesh._indices[0].push(b * (sides+1) + a);
+ this._mesh._indices[0].push(b * (sides+1) + a + 1);
+ this._mesh._indices[0].push((b + 1) * (sides+1) + a);
+
+ this._mesh._indices[0].push(b * (sides+1) + a + 1);
+ this._mesh._indices[0].push((b + 1) * (sides+1) + a + 1);
+ this._mesh._indices[0].push((b + 1) * (sides+1) + a);
+ }
+ }
+
+ if (this._vf.angle < twoPi && this._vf.caps == true)
+ {
+ // create first cap
+ var origPos = this._mesh._positions[0].length / 3;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(outerRadius, 0, 0);
+ this._mesh._normals[0].push(0, 0, 1);
+ }
+ else {
+ this._mesh._positions[0].push(outerRadius, 0, 0);
+ this._mesh._normals[0].push(0, 1, 0);
+ }
+ this._mesh._texCoords[0].push(0.5, 0.5);
+
+ for (b=0, phi=0; b<=sides; b++, phi+=sideDelta)
+ {
+ cosPhi = Math.cos(phi);
+ sinPhi = Math.sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(dist, sinPhi * innerRadius, 0);
+ this._mesh._normals[0].push(0, 0, 1);
+ }
+ else {
+ this._mesh._positions[0].push(dist, 0, sinPhi * innerRadius);
+ this._mesh._normals[0].push(0, 1, 0);
+ }
+ this._mesh._texCoords[0].push((1 + cosPhi) * 0.5, (1 - sinPhi) * 0.5);
+
+ if (b > 0) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + b);
+ this._mesh._indices[0].push(origPos + b - 1);
+ }
+ if (b == sides) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + 1);
+ this._mesh._indices[0].push(origPos + b);
+ }
+ }
+
+ // second cap
+ cosTheta = Math.cos(this._vf.angle);
+ sinTheta = Math.sin(this._vf.angle);
+
+ origPos = this._mesh._positions[0].length / 3;
+ var nx = -sinTheta, ny = -cosTheta;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(cosTheta * outerRadius, 0, -sinTheta * outerRadius);
+ this._mesh._normals[0].push(nx, 0, ny);
+ }
+ else {
+ this._mesh._positions[0].push(cosTheta * outerRadius, -sinTheta * outerRadius, 0);
+ this._mesh._normals[0].push(nx, ny, 0);
+ }
+ this._mesh._texCoords[0].push(0.5, 0.5);
+
+ for (b=0, phi=0; b<=sides; b++, phi+=sideDelta)
+ {
+ cosPhi = Math.cos(phi);
+ sinPhi = Math.sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(cosTheta * dist, sinPhi * innerRadius, -sinTheta * dist);
+ this._mesh._normals[0].push(nx, 0, ny);
+ }
+ else {
+ this._mesh._positions[0].push(cosTheta * dist, -sinTheta * dist, sinPhi * innerRadius);
+ this._mesh._normals[0].push(nx, ny, 0);
+ }
+ this._mesh._texCoords[0].push(1 - (1 + cosPhi) * 0.5, (1 - sinPhi) * 0.5);
+
+ if (b > 0) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + b - 1);
+ this._mesh._indices[0].push(origPos + b);
+ }
+ if (b == sides) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + b);
+ this._mesh._indices[0].push(origPos + 1);
+ }
+ }
+ }
+
+ this._mesh._invalidate = true;
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ x3dom.geoCache[geoCacheID] = this._mesh;
+ }
+
+ },
+ {
+ fieldChanged: function(fieldName)
+ {
+ // TODO; invalidate geometry cache if necessary (to be fixed for all primitives)!
+ if (fieldName == "innerRadius" || fieldName == "outerRadius" ||
+ fieldName == "subdivision" || fieldName == "angle" ||
+ fieldName == "insideOutsideRadius" || fieldName == "caps")
+ {
+ // assure that angle in [0, 2 * PI]
+ var twoPi = 2.0 * Math.PI;
+
+ if (this._vf.angle < 0)
+ this._vf.angle = 0;
+ else if (this._vf.angle > twoPi)
+ this._vf.angle = twoPi;
+
+ var innerRadius = this._vf.innerRadius;
+ var outerRadius = this._vf.outerRadius;
+
+ if (this._vf.insideOutsideRadius == true)
+ {
+ if (innerRadius > outerRadius) {
+ var tmp = innerRadius;
+ innerRadius = outerRadius;
+ outerRadius = tmp;
+ }
+
+ var rad = (outerRadius - innerRadius) / 2;
+
+ outerRadius = innerRadius + rad;
+ innerRadius = rad;
+
+ this._vf.ccw = !this._origCCW;
+ }
+ else
+ this._vf.ccw = this._origCCW;
+
+ var rings = this._vf.subdivision.x, sides = this._vf.subdivision.y;
+ rings = Math.max(3, Math.round((this._vf.angle / twoPi) * rings));
+
+ var ringDelta = this._vf.angle / rings;
+ var sideDelta = twoPi / sides;
+ var a, b, theta, phi;
+ var cosTheta, sinTheta, cosPhi, sinPhi, dist;
+
+ this._mesh._positions[0] = [];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+ this._mesh._indices[0] = [];
+
+ for (a=0, theta=0; a <= rings; a++, theta+=ringDelta)
+ {
+ cosTheta = Math.cos(theta);
+ sinTheta = Math.sin(theta);
+
+ for (b=0, phi=0; b<=sides; b++, phi+=sideDelta)
+ {
+ cosPhi = Math.cos(phi);
+ sinPhi = Math.sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(cosTheta * dist, innerRadius * sinPhi, -sinTheta * dist);
+ this._mesh._normals[0].push(cosTheta * cosPhi, sinPhi, -sinTheta * cosPhi);
+ }
+ else {
+ this._mesh._positions[0].push(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi);
+ this._mesh._normals[0].push(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
+ }
+ this._mesh._texCoords[0].push(-a / rings, b / sides);
+ }
+ }
+
+ for (a=0; a<sides; a++)
+ {
+ for (b=0; b<rings; b++)
+ {
+ this._mesh._indices[0].push(b * (sides+1) + a);
+ this._mesh._indices[0].push(b * (sides+1) + a + 1);
+ this._mesh._indices[0].push((b + 1) * (sides+1) + a);
+
+ this._mesh._indices[0].push(b * (sides+1) + a + 1);
+ this._mesh._indices[0].push((b + 1) * (sides+1) + a + 1);
+ this._mesh._indices[0].push((b + 1) * (sides+1) + a);
+ }
+ }
+
+ if (this._vf.angle < twoPi && this._vf.caps == true)
+ {
+ // create first cap
+ var origPos = this._mesh._positions[0].length / 3;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(outerRadius, 0, 0);
+ this._mesh._normals[0].push(0, 0, 1);
+ }
+ else {
+ this._mesh._positions[0].push(outerRadius, 0, 0);
+ this._mesh._normals[0].push(0, 1, 0);
+ }
+ this._mesh._texCoords[0].push(0.5, 0.5);
+
+ for (b=0, phi=0; b<=sides; b++, phi+=sideDelta)
+ {
+ cosPhi = Math.cos(phi);
+ sinPhi = Math.sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(dist, sinPhi * innerRadius, 0);
+ this._mesh._normals[0].push(0, 0, 1);
+ }
+ else {
+ this._mesh._positions[0].push(dist, 0, sinPhi * innerRadius);
+ this._mesh._normals[0].push(0, 1, 0);
+ }
+ this._mesh._texCoords[0].push((1 + cosPhi) * 0.5, (1 - sinPhi) * 0.5);
+
+ if (b > 0) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + b);
+ this._mesh._indices[0].push(origPos + b - 1);
+ }
+ if (b == sides) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + 1);
+ this._mesh._indices[0].push(origPos + b);
+ }
+ }
+
+ // second cap
+ cosTheta = Math.cos(this._vf.angle);
+ sinTheta = Math.sin(this._vf.angle);
+
+ origPos = this._mesh._positions[0].length / 3;
+ var nx = -sinTheta, ny = -cosTheta;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(cosTheta * outerRadius, 0, -sinTheta * outerRadius);
+ this._mesh._normals[0].push(nx, 0, ny);
+ }
+ else {
+ this._mesh._positions[0].push(cosTheta * outerRadius, -sinTheta * outerRadius, 0);
+ this._mesh._normals[0].push(nx, ny, 0);
+ }
+ this._mesh._texCoords[0].push(0.5, 0.5);
+
+ for (b=0, phi=0; b<=sides; b++, phi+=sideDelta)
+ {
+ cosPhi = Math.cos(phi);
+ sinPhi = Math.sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ if (this._vf.insideOutsideRadius) {
+ this._mesh._positions[0].push(cosTheta * dist, sinPhi * innerRadius, -sinTheta * dist);
+ this._mesh._normals[0].push(nx, 0, ny);
+ }
+ else {
+ this._mesh._positions[0].push(cosTheta * dist, -sinTheta * dist, sinPhi * innerRadius);
+ this._mesh._normals[0].push(nx, ny, 0);
+ }
+ this._mesh._texCoords[0].push(1 - (1 + cosPhi) * 0.5, (1 - sinPhi) * 0.5);
+
+ if (b > 0) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + b - 1);
+ this._mesh._indices[0].push(origPos + b);
+ }
+ if (b == sides) {
+ this._mesh._indices[0].push(origPos);
+ this._mesh._indices[0].push(origPos + b);
+ this._mesh._indices[0].push(origPos + 1);
+ }
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node.setAllDirty();
+ node.invalidateVolume();
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Cone ### */
+x3dom.registerNodeType(
+ "Cone",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for Cone
+ * @constructs x3dom.nodeTypes.Cone
+ * @x3d 3.3
+ * @component Geometry3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Cone node specifies a cone which is centred in the local coordinate system and whose central axis is aligned with the local Y-axis.
+ * By default, the cone has a radius of 1.0 at the bottom and a height of 2.0
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Cone.superClass.call(this, ctx);
+
+
+ /**
+ * The bottomRadius field specifies the radius of the cone's base.
+ * @var {x3dom.fields.SFFloat} bottomRadius
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Cone
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'bottomRadius', 1.0);
+
+ /**
+ * The topRadius field specifies the radius of the cone at the apex.
+ * @var {x3dom.fields.SFFloat} topRadius
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Cone
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'topRadius', 0);
+
+ /**
+ * The height field specifies the height of the cone from the centre of the base to the apex.
+ * @var {x3dom.fields.SFFloat} height
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Cone
+ * @initvalue 2.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'height', 2.0);
+
+ /**
+ * The bottom field specifies whether the bottom cap of the cone is created.
+ * @var {x3dom.fields.SFBool} bottom
+ * @memberof x3dom.nodeTypes.Cone
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'bottom', true);
+
+ /**
+ * The side field specifies whether sides of the cone are created.
+ * @var {x3dom.fields.SFBool} side
+ * @memberof x3dom.nodeTypes.Cone
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'side', true);
+
+ /**
+ * The top field specifies whether the top cap of the cone is created.
+ * @var {x3dom.fields.SFBool} top
+ * @memberof x3dom.nodeTypes.Cone
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'top', true);
+
+ /**
+ * Specifies the number of faces that are generated to approximate the sides of the cone.
+ * @var {x3dom.fields.SFFloat} subdivision
+ * @range [2, inf]
+ * @memberof x3dom.nodeTypes.Cone
+ * @initvalue 32
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'subdivision', 32);
+
+ var geoCacheID = 'Cone_' + this._vf.bottomRadius + '_' + this._vf.height + '_' + this._vf.top + '_' +
+ this._vf.bottom + '_' + this._vf.side + '_' + this._vf.topRadius + '_' + this._vf.subdivision;
+
+ if (this._vf.useGeoCache && x3dom.geoCache[geoCacheID] !== undefined) {
+ //x3dom.debug.logInfo("Using Cone from Cache");
+ this._mesh = x3dom.geoCache[geoCacheID];
+ }
+ else {
+ var bottomRadius = this._vf.bottomRadius, height = this._vf.height;
+ var topRadius = this._vf.topRadius, sides = this._vf.subdivision;
+
+ var beta, x, z;
+ var delta = 2.0 * Math.PI / sides;
+
+ var incl = (bottomRadius - topRadius) / height;
+ var nlen = 1.0 / Math.sqrt(1.0 + incl * incl);
+
+ var j = 0, k = 0;
+ var h, base;
+
+ if (this._vf.side && height > 0) {
+ var px = 0, pz = 0;
+
+ for (j = 0, k = 0; j <= sides; j++) {
+ beta = j * delta;
+ x = Math.sin(beta);
+ z = -Math.cos(beta);
+
+ if (topRadius > x3dom.fields.Eps) {
+ px = x * topRadius;
+ pz = z * topRadius;
+ }
+
+ this._mesh._positions[0].push(px, height / 2, pz);
+ this._mesh._normals[0].push(x / nlen, incl / nlen, z / nlen);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 1);
+
+ this._mesh._positions[0].push(x * bottomRadius, -height / 2, z * bottomRadius);
+ this._mesh._normals[0].push(x / nlen, incl / nlen, z / nlen);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 0);
+
+ if (j > 0) {
+ this._mesh._indices[0].push(k );
+ this._mesh._indices[0].push(k + 2);
+ this._mesh._indices[0].push(k + 1);
+
+ this._mesh._indices[0].push(k + 1);
+ this._mesh._indices[0].push(k + 2);
+ this._mesh._indices[0].push(k + 3);
+
+ k += 2;
+ }
+ }
+ }
+
+ if (this._vf.bottom && bottomRadius > 0) {
+ base = this._mesh._positions[0].length / 3;
+
+ for (j = sides - 1; j >= 0; j--) {
+ beta = j * delta;
+ x = bottomRadius * Math.sin(beta);
+ z = -bottomRadius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, -height / 2, z);
+ this._mesh._normals[0].push(0, -1, 0);
+ this._mesh._texCoords[0].push(x / bottomRadius / 2 + 0.5, z / bottomRadius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j = 2; j < sides; j++) {
+ this._mesh._indices[0].push(h);
+ this._mesh._indices[0].push(base);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+ }
+
+ if (this._vf.top && topRadius > x3dom.fields.Eps) {
+ base = this._mesh._positions[0].length / 3;
+
+ for (j = sides - 1; j >= 0; j--) {
+ beta = j * delta;
+ x = topRadius * Math.sin(beta);
+ z = -topRadius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, height / 2, z);
+ this._mesh._normals[0].push(0, 1, 0);
+ this._mesh._texCoords[0].push(x / topRadius / 2 + 0.5, 1.0 - z / topRadius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j = 2; j < sides; j++) {
+ this._mesh._indices[0].push(base);
+ this._mesh._indices[0].push(h);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+ }
+
+ this._mesh._invalidate = true;
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ x3dom.geoCache[geoCacheID] = this._mesh;
+ }
+
+ },
+ {
+ fieldChanged: function (fieldName)
+ {
+ if (fieldName == "bottomRadius" || fieldName == "topRadius" ||
+ fieldName == "height" || fieldName == "subdivision" ||
+ fieldName == "bottom" || fieldName == "top" || fieldName == "side")
+ {
+ this._mesh._positions[0] = [];
+ this._mesh._indices[0] = [];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+
+ var bottomRadius = this._vf.bottomRadius, height = this._vf.height;
+ var topRadius = this._vf.topRadius, sides = this._vf.subdivision;
+
+ var beta, x, z;
+ var delta = 2.0 * Math.PI / sides;
+
+ var incl = (bottomRadius - topRadius) / height;
+ var nlen = 1.0 / Math.sqrt(1.0 + incl * incl);
+
+ var j = 0, k = 0;
+ var h, base;
+
+ if (this._vf.side && height > 0)
+ {
+ var px = 0, pz = 0;
+
+ for (j = 0, k = 0; j <= sides; j++) {
+ beta = j * delta;
+ x = Math.sin(beta);
+ z = -Math.cos(beta);
+
+ if (topRadius > x3dom.fields.Eps) {
+ px = x * topRadius;
+ pz = z * topRadius;
+ }
+
+ this._mesh._positions[0].push(px, height / 2, pz);
+ this._mesh._normals[0].push(x / nlen, incl / nlen, z / nlen);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 1);
+
+ this._mesh._positions[0].push(x * bottomRadius, -height / 2, z * bottomRadius);
+ this._mesh._normals[0].push(x / nlen, incl / nlen, z / nlen);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 0);
+
+ if (j > 0) {
+ this._mesh._indices[0].push(k );
+ this._mesh._indices[0].push(k + 2);
+ this._mesh._indices[0].push(k + 1);
+
+ this._mesh._indices[0].push(k + 1);
+ this._mesh._indices[0].push(k + 2);
+ this._mesh._indices[0].push(k + 3);
+
+ k += 2;
+ }
+ }
+ }
+
+ if (this._vf.bottom && bottomRadius > 0)
+ {
+ base = this._mesh._positions[0].length / 3;
+
+ for (j = sides - 1; j >= 0; j--) {
+ beta = j * delta;
+ x = bottomRadius * Math.sin(beta);
+ z = -bottomRadius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, -height / 2, z);
+ this._mesh._normals[0].push(0, -1, 0);
+ this._mesh._texCoords[0].push(x / bottomRadius / 2 + 0.5, z / bottomRadius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j = 2; j < sides; j++) {
+ this._mesh._indices[0].push(h);
+ this._mesh._indices[0].push(base);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+ }
+
+ if (this._vf.top && topRadius > x3dom.fields.Eps)
+ {
+ base = this._mesh._positions[0].length / 3;
+
+ for (j = sides - 1; j >= 0; j--) {
+ beta = j * delta;
+ x = topRadius * Math.sin(beta);
+ z = -topRadius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, height / 2, z);
+ this._mesh._normals[0].push(0, 1, 0);
+ this._mesh._texCoords[0].push(x / topRadius / 2 + 0.5, 1.0 - z / topRadius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j = 2; j < sides; j++) {
+ this._mesh._indices[0].push(base);
+ this._mesh._indices[0].push(h);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node.setAllDirty();
+ node.invalidateVolume();
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### Cylinder ### */
+x3dom.registerNodeType(
+ "Cylinder",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for Cylinder
+ * @constructs x3dom.nodeTypes.Cylinder
+ * @x3d 3.3
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The Cylinder node specifies a capped cylinder centred at (0,0,0) in the local coordinate system and with a central axis oriented along the local Y-axis.
+ * By default, the cylinder is sized at "-1" to "+1" in all three dimensions.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.Cylinder.superClass.call(this, ctx);
+
+
+ /**
+ * The radius field specifies the radius of the cylinder.
+ * @var {x3dom.fields.SFFloat} radius
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Cylinder
+ * @initvalue 1.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'radius', 1.0);
+
+ /**
+ * The height field specifies the height of the cylinder along the central axis.
+ * @var {x3dom.fields.SFFloat} height
+ * @range [0, inf]
+ * @memberof x3dom.nodeTypes.Cylinder
+ * @initvalue 2.0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'height', 2.0);
+
+ /**
+ * The bottom field specifies whether the bottom cap of the cylinder is created.
+ * @var {x3dom.fields.SFBool} bottom
+ * @memberof x3dom.nodeTypes.Cylinder
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'bottom', true);
+
+ /**
+ * The top field specifies whether the top cap of the cylinder is created.
+ * @var {x3dom.fields.SFBool} top
+ * @memberof x3dom.nodeTypes.Cylinder
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'top', true);
+
+ /**
+ * Specifies the number of faces that are generated to approximate the sides of the cylinder.
+ * @var {x3dom.fields.SFFloat} subdivision
+ * @range [2, inf]
+ * @memberof x3dom.nodeTypes.Cylinder
+ * @initvalue 32
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'subdivision', 32);
+
+ /**
+ * The side field specifies whether sides of the cylinder are created.
+ * @var {x3dom.fields.SFBool} side
+ * @memberof x3dom.nodeTypes.Cylinder
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'side', true);
+
+ var sides = this._vf.subdivision;
+
+ var geoCacheID = 'Cylinder_'+this._vf.radius+'_'+this._vf.height+'_'+this._vf.bottom+'_'+this._vf.top+'_'+
+ this._vf.side+'_'+this._vf.subdivision;
+
+ if( this._vf.useGeoCache && x3dom.geoCache[geoCacheID] !== undefined )
+ {
+ //x3dom.debug.logInfo("Using Cylinder from Cache");
+ this._mesh = x3dom.geoCache[geoCacheID];
+ }
+ else
+ {
+ var radius = this._vf.radius;
+ var height = this._vf.height / 2;
+
+ var beta, x, z;
+ var delta = 2.0 * Math.PI / sides;
+ var j, k;
+
+ if (this._vf.side)
+ {
+ for (j=0, k=0; j<=sides; j++)
+ {
+ beta = j * delta;
+ x = Math.sin(beta);
+ z = -Math.cos(beta);
+
+ this._mesh._positions[0].push(x * radius, -height, z * radius);
+ this._mesh._normals[0].push(x, 0, z);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 0);
+
+ this._mesh._positions[0].push(x * radius, height, z * radius);
+ this._mesh._normals[0].push(x, 0, z);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 1);
+
+ if (j > 0)
+ {
+ this._mesh._indices[0].push(k );
+ this._mesh._indices[0].push(k + 1);
+ this._mesh._indices[0].push(k + 2);
+
+ this._mesh._indices[0].push(k + 2);
+ this._mesh._indices[0].push(k + 1);
+ this._mesh._indices[0].push(k + 3);
+
+ k += 2;
+ }
+ }
+ }
+
+ if (radius > 0)
+ {
+ var h, base = this._mesh._positions[0].length / 3;
+
+ if (this._vf.top)
+ {
+ for (j=sides-1; j>=0; j--)
+ {
+ beta = j * delta;
+ x = radius * Math.sin(beta);
+ z = -radius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, height, z);
+ this._mesh._normals[0].push(0, 1, 0);
+ this._mesh._texCoords[0].push(x / radius / 2 + 0.5, -z / radius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j=2; j<sides; j++)
+ {
+ this._mesh._indices[0].push(base);
+ this._mesh._indices[0].push(h);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+
+ base = this._mesh._positions[0].length / 3;
+ }
+
+ if (this._vf.bottom)
+ {
+ for (j=sides-1; j>=0; j--)
+ {
+ beta = j * delta;
+ x = radius * Math.sin(beta);
+ z = -radius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, -height, z);
+ this._mesh._normals[0].push(0, -1, 0);
+ this._mesh._texCoords[0].push(x / radius / 2 + 0.5, z / radius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j=2; j<sides; j++)
+ {
+ this._mesh._indices[0].push(h);
+ this._mesh._indices[0].push(base);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+ }
+ }
+
+ this._mesh._invalidate = true;
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ x3dom.geoCache[geoCacheID] = this._mesh;
+ }
+
+ },
+ {
+ fieldChanged: function(fieldName) {
+ if (fieldName === "radius" || fieldName === "height")
+ {
+ this._mesh._positions[0] = [];
+
+ var radius = this._vf.radius, height = this._vf.height / 2;
+ var sides = this._vf.subdivision;
+
+ var beta, x, z, j;
+ var delta = 2.0 * Math.PI / sides;
+
+ if (this._vf.side)
+ {
+ for (j=0; j<=sides; j++)
+ {
+ beta = j * delta;
+ x = Math.sin(beta);
+ z = -Math.cos(beta);
+
+ this._mesh._positions[0].push(x * radius, -height, z * radius);
+ this._mesh._positions[0].push(x * radius, height, z * radius);
+ }
+ }
+
+ if (radius > 0)
+ {
+ var h, base = this._mesh._positions[0].length / 3;
+
+ if (this._vf.top)
+ {
+ for (j=sides-1; j>=0; j--)
+ {
+ beta = j * delta;
+ x = radius * Math.sin(beta);
+ z = -radius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, height, z);
+ }
+ }
+ }
+
+ if (this._vf.bottom)
+ {
+ for (j=sides-1; j>=0; j--)
+ {
+ beta = j * delta;
+ x = radius * Math.sin(beta);
+ z = -radius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, -height, z);
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName === "subdivision" || fieldName === "bottom" ||
+ fieldName === "top" || fieldName === "side")
+ {
+ this._mesh._positions[0] = [];
+ this._mesh._indices[0] =[];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] =[];
+
+ var radius = this._vf.radius, height = this._vf.height / 2;
+ var sides = this._vf.subdivision;
+
+ var beta, x, z, j;
+ var delta = 2.0 * Math.PI / sides;
+ var k = 0;
+
+ if (this._vf.side)
+ {
+ for (j=0, k=0; j<=sides; j++)
+ {
+ beta = j * delta;
+ x = Math.sin(beta);
+ z = -Math.cos(beta);
+
+ this._mesh._positions[0].push(x * radius, -height, z * radius);
+ this._mesh._normals[0].push(x, 0, z);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 0);
+
+ this._mesh._positions[0].push(x * radius, height, z * radius);
+ this._mesh._normals[0].push(x, 0, z);
+ this._mesh._texCoords[0].push(1.0 - j / sides, 1);
+
+ if (j > 0)
+ {
+ this._mesh._indices[0].push(k + 0);
+ this._mesh._indices[0].push(k + 1);
+ this._mesh._indices[0].push(k + 2);
+
+ this._mesh._indices[0].push(k + 2);
+ this._mesh._indices[0].push(k + 1);
+ this._mesh._indices[0].push(k + 3);
+
+ k += 2;
+ }
+ }
+ }
+
+ if (radius > 0)
+ {
+ var h, base = this._mesh._positions[0].length / 3;
+
+ if (this._vf.top)
+ {
+ for (j=sides-1; j>=0; j--)
+ {
+ beta = j * delta;
+ x = radius * Math.sin(beta);
+ z = -radius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, height, z);
+ this._mesh._normals[0].push(0, 1, 0);
+ this._mesh._texCoords[0].push(x / radius / 2 + 0.5, -z / radius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j=2; j<sides; j++)
+ {
+ this._mesh._indices[0].push(base);
+ this._mesh._indices[0].push(h);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+
+ base = this._mesh._positions[0].length / 3;
+ }
+
+ if (this._vf.bottom)
+ {
+ for (j=sides-1; j>=0; j--)
+ {
+ beta = j * delta;
+ x = radius * Math.sin(beta);
+ z = -radius * Math.cos(beta);
+
+ this._mesh._positions[0].push(x, -height, z);
+ this._mesh._normals[0].push(0, -1, 0);
+ this._mesh._texCoords[0].push(x / radius / 2 + 0.5, z / radius / 2 + 0.5);
+ }
+
+ h = base + 1;
+
+ for (j=2; j<sides; j++)
+ {
+ this._mesh._indices[0].push(h);
+ this._mesh._indices[0].push(base);
+
+ h = base + j;
+ this._mesh._indices[0].push(h);
+ }
+ }
+ }
+
+ this.invalidateVolume();
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ Array.forEach(this._parentNodes, function (node) {
+ node.setAllDirty();
+ node.invalidateVolume();
+ });
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+
+/* ### ExternalGeometry ### */
+x3dom.registerNodeType(
+ "ExternalGeometry",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for ExternalGeometry
+ * @constructs x3dom.nodeTypes.ExternalGeometry
+ * @x3d x.x
+ * @component Geometry3D
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ExternalGeometry node loads data from a Shape Resource Container (SRC). The used data can be progressively updated during transmission.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ExternalGeometry.superClass.call(this, ctx);
+
+ /**
+ * Defines the url to the Shape Resource Container. A suffix with a leading # can be used to reference single meshes inside a SRC: "path/to/data.src#mesh0".
+ * @var {x3dom.fields.SFString} url
+ * @memberof x3dom.nodeTypes.Geometry3D
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'url', "");
+
+
+ //initialization of rendering-related X3DOM structures
+ this._mesh._invalidate = false;
+ this._mesh._numCoords = 0;
+ this._mesh._numFaces = 0;
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * Updates the render data, stored in the given objects, with data from this ExternalGeometry.
+ * If necessary, the referenced file is downloaded first.
+ *
+ * @param {Object} shape - x3dom shape node
+ * @param {Object} shaderProgram - x3dom shader program
+ * @param {Object} gl - WebGL context
+ * @param {Object} viewarea - x3dom view area
+ * @param {Object} context - x3dom context object
+ */
+ updateRenderData: function(shape, shaderProgram, gl, viewarea, context) {
+ var that = this;
+ var xhr;
+
+ if (this._vf['url'] == "") {
+ return;
+ }
+
+ //check if there is still memory available
+ if (x3dom.BinaryContainerLoader.outOfMemory) {
+ return;
+ }
+
+ //TODO: check SOURCE child nodes
+ shape._webgl.internalDownloadCount = 1;
+ shape._nameSpace.doc.downloadCount = 1;
+
+ //TODO: check this object - when is it called, where is it really needed?
+ //shape._webgl.makeSeparateTris = {...};
+
+
+ //post request
+ xhr = new XMLHttpRequest();
+
+ xhr.open("GET", this._vf['url'], true);
+
+ xhr.responseType = "arraybuffer";
+
+ xhr.send(null);
+
+ xhr.onerror = function() {
+ x3dom.debug.logError("Unable to load SRC data from URL \"" + that._vf['url'] + "\"");
+ };
+
+ //TODO: currently, we assume that the referenced file is always an SRC file
+ xhr.onload = function() {
+ shape._webgl.internalDownloadCount = 0;
+ shape._nameSpace.doc.downloadCount = 0;
+
+ var responseBeginUint32 = new Uint32Array(xhr.response, 0, 12);
+
+ var srcHeaderSize, srcBodySize, srcBodyOffset;
+ var srcHeaderView, srcBodyView;
+
+ var srcHeaderObj;
+
+ if ((xhr.status == 200 || xhr.status == 0) && responseBeginUint32.length >= 3) {
+
+ srcHeaderSize = responseBeginUint32[2];
+ srcBodyOffset = srcHeaderSize + 12;
+ srcBodySize = xhr.response.byteLength - srcBodyOffset;
+
+ if (srcHeaderSize > 0 && srcBodySize >= 0)
+ {
+ srcHeaderView = new Uint8Array(xhr.response, 12, srcHeaderSize);
+ srcBodyView = new Uint8Array(xhr.response, srcBodyOffset, srcBodySize );
+
+ //decode SRC header
+ //currently, we assume ASCII JSON encoding
+ try
+ {
+ srcHeaderObj = JSON.parse(String.fromCharCode.apply(null, srcHeaderView));
+ }
+ catch (exc)
+ {
+ x3dom.debug.logError("Unable to parse SRC header: " + exc);
+ return;
+ }
+
+ that._updateRenderDataFromSRC(shape, shaderProgram, gl, srcHeaderObj, srcBodyView);
+ }
+ else
+ {
+ x3dom.debug.logError("Invalid SRC data, loaded from URL \"" +
+ that._vf['url'] + "\"");
+ return;
+ }
+ }
+ else
+ {
+ x3dom.debug.logError("Unable to load SRC data from URL \"" + that._vf['url'] + "\"");
+ }
+ };
+ } ,
+
+ //----------------------------------------------------------------------------------------------------------
+
+ //----------------------------------------------------------------------------------------------------------
+ // PRIVATE FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------
+
+ //TODO: we currently assume that we always read data from exactly one SRC (i.e., no Source nodes)
+ /**
+ * Helper function, updating the render data, stored in the given objects,
+ * with data read from the given SRC.
+ *
+ * @param {Object} shape - x3dom shape node
+ * @param {Object} shaderProgram - x3dom shader program
+ * @param {Object} gl - WebGL context
+ * @param {Object} srcHeaderObj - the JS object which was created from the SRC header
+ * @param {Uint8Array} srcBodyView - a typed array view on the body of the SRC file
+ * @private
+ */
+ _updateRenderDataFromSRC: function(shape, shaderProgram, gl, srcHeaderObj, srcBodyView)
+ {
+ var INDEX_BUFFER_IDX = 0;
+ var POSITION_BUFFER_IDX = 1;
+ var NORMAL_BUFFER_IDX = 2;
+ var TEXCOORD_BUFFER_IDX = 3;
+ var COLOR_BUFFER_IDX = 4;
+ var ID_BUFFER_IDX = 5;
+
+ var MAX_NUM_BUFFERS_PER_DRAW = 6;
+
+ var indexViews = srcHeaderObj["accessors"]["indexViews"];
+ var indexViewID, indexView;
+
+ var attributeViews = srcHeaderObj["accessors"]["attributeViews"];
+ var attributes;
+ var attributeID, attributeView;
+ var x3domTypeID, x3domShortTypeID, numComponents;
+
+ var meshes = srcHeaderObj["meshes"];
+ var mesh, meshID;
+ var meshIdx, bufferOffset;
+
+
+ //the meta data object is currently unused
+ //var metadataObj = srcHeaderObj["meta"];
+
+
+ //1. create GL buffers for bufferChunks / bufferViews
+
+ //create buffers and GL buffer views, and store their identifiers in a map
+ var viewIDsToGLBufferIDs = {};
+
+ //due to the differentiation between targets ARRAY and ELEMENT_ARRAY, we need to check the usage
+ //of the buffer view objects here first, before uploading them for the matching target
+ var indexViewBufferIDs = {};
+ for (indexViewID in indexViews)
+ {
+ indexView = indexViews[indexViewID];
+ indexViewBufferIDs[indexView["bufferView"]] = true;
+ }
+
+ this._createGLBuffersFromSRCChunks(gl,
+ srcHeaderObj["bufferChunks"], srcHeaderObj["bufferViews"],
+ srcBodyView, indexViewBufferIDs, viewIDsToGLBufferIDs);
+
+
+ //2. remember GL index buffer properties, if any
+
+ for (indexViewID in indexViews)
+ {
+ indexView = indexViews[indexViewID];
+
+ //we currently assume 16 bit index data
+ if (indexView["componentType"] != gl.UNSIGNED_SHORT)
+ {
+ x3dom.debug.logWarning("SRC index componentType " + indexView["componentType"] +
+ " is not UNSIGNED_SHORT. " +
+ "Ignoring given value and assuming UNSIGNED_SHORT indices.");
+ }
+ shape._webgl.indexType = gl.UNSIGNED_SHORT;
+ }
+
+
+ //3. remember necessary information to setup GL draw parameters and attribute pointers
+
+ meshIdx = 0;
+ bufferOffset = 0;
+
+ shape._webgl.primType = [];
+ shape._webgl.indexOffset = [];
+ shape._webgl.drawCount = [];
+
+ //hints for stats display
+ this._mesh._numCoords = 0;
+ this._mesh._numFaces = 0;
+
+ for (meshID in meshes)
+ {
+ mesh = meshes[meshID];
+
+ //setup indices, if any
+ indexViewID = mesh["indices"];
+ //TODO: allow the renderer to switch between indexed and non-indexed rendering, for one extGeo
+ if (indexViewID != "")
+ {
+ shape._webgl.externalGeometry = 1; //indexed EG
+
+ indexView = indexViews[indexViewID];
+
+ shape._webgl.indexOffset[meshIdx] = indexView["byteOffset"];
+ shape._webgl.drawCount[meshIdx] = indexView["count"];
+
+ shape._webgl.buffers[INDEX_BUFFER_IDX + bufferOffset] =
+ viewIDsToGLBufferIDs[indexView["bufferView"]];
+
+ //TODO: add support for LINES and POINTS
+ this._mesh._numFaces += indexView["count"] / 3;
+ }
+ else
+ {
+ shape._webgl.externalGeometry = -1; //non-indexed EG
+ }
+
+ //setup primType
+ shape._webgl.primType[meshIdx] = mesh["primitive"];
+
+ //setup attributes
+ attributes = mesh["attributes"];
+
+ for (attributeID in attributes)
+ {
+ attributeView = attributeViews[attributes[attributeID]];
+
+ //the current renderer does not support generic vertex attributes, so simply look for useable cases
+ switch (attributeID)
+ {
+ case "position":
+ x3domTypeID = "coord";
+ x3domShortTypeID = "Pos";
+ shape._webgl.buffers[POSITION_BUFFER_IDX + bufferOffset] =
+ viewIDsToGLBufferIDs[attributeView["bufferView"]];
+ //for non-indexed rendering, we assume that all attributes have the same count
+ if (mesh["indices"] == "")
+ {
+ shape._webgl.drawCount[meshIdx] = attributeView["count"];
+ //TODO: add support for LINES and POINTS
+ this._mesh._numFaces += attributeView["count"] / 3;
+ }
+ this._mesh._numCoords += attributeView["count"];
+ break;
+
+ case "normal":
+ x3domTypeID = "normal";
+ x3domShortTypeID = "Norm";
+ shape._webgl.buffers[NORMAL_BUFFER_IDX + bufferOffset] =
+ viewIDsToGLBufferIDs[attributeView["bufferView"]];
+ break;
+
+ case "texcoord":
+ x3domTypeID = "texCoord";
+ x3domShortTypeID = "Tex";
+ shape._webgl.buffers[TEXCOORD_BUFFER_IDX + bufferOffset] =
+ viewIDsToGLBufferIDs[attributeView["bufferView"]];
+ break;
+
+ case "color":
+ x3domTypeID = "color";
+ x3domShortTypeID = "Col";
+ shape._webgl.buffers[COLOR_BUFFER_IDX + bufferOffset] =
+ viewIDsToGLBufferIDs[attributeView["bufferView"]];
+ break;
+
+ case "id":
+ x3domTypeID = "id";
+ x3domShortTypeID = "Id";
+ shape._webgl.buffers[ID_BUFFER_IDX + bufferOffset] =
+ viewIDsToGLBufferIDs[attributeView["bufferView"]];
+ break;
+ }
+
+ shape["_" + x3domTypeID + "StrideOffset"][0] = attributeView["byteStride"];
+ shape["_" + x3domTypeID + "StrideOffset"][1] = attributeView["byteOffset"];
+ shape._webgl[x3domTypeID + "Type"] = attributeView["componentType"];
+
+ numComponents = x3dom.nodeTypes.ExternalGeometry._findNumComponentsForSRCAccessorType(attributeView["type"]);
+ this._mesh["_num" + x3domShortTypeID + "Components"] = numComponents;
+ }
+
+ ++meshIdx;
+ bufferOffset += MAX_NUM_BUFFERS_PER_DRAW;
+ }
+
+
+ //4. notify renderer
+
+ shape._nameSpace.doc.needRender = true;
+
+ x3dom.BinaryContainerLoader.checkError(gl);
+ },
+
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * Helper function, creating WebGL buffers for the given SRC data structures.
+ * The result is stored in the given map from bufferView IDs to GL buffer IDs.
+ *
+ * @param {Object} gl - WebGL context
+ * @param {Object} bufferChunksObj - the SRC header's bufferChunks object
+ * @param {Object} bufferViewsObj - the SRC header's bufferViews object
+ * @param {Uint8Array} srcBodyView - a typed array view on the body of the SRC file
+ * @param {Object} indexViewBufferIDs - an object which holds the IDs of all index data bufferViews
+ * @param {Object} viewIDsToGLBufferIDs - map that will be filled with a GL buffer ID for each bufferView ID
+ * @private
+ */
+ _createGLBuffersFromSRCChunks: function(gl, bufferChunksObj, bufferViewsObj, srcBodyView,
+ indexViewBufferIDs, viewIDsToGLBufferIDs)
+ {
+ var i;
+ var bufferView;
+ var chunkIDList;
+ var bufferType;
+
+ var chunk;
+ var newBuffer;
+ var chunkDataView;
+ var currentChunkDataOffset;
+
+ //for each buffer view object, create and fill a GL buffer from its buffer chunks
+ for (var bufferViewID in bufferViewsObj)
+ {
+ bufferType = (typeof indexViewBufferIDs[bufferViewID] !== 'undefined') ? gl.ELEMENT_ARRAY_BUFFER :
+ gl.ARRAY_BUFFER;
+
+ bufferView = bufferViewsObj[bufferViewID];
+
+ chunkIDList = bufferView["chunks"];
+
+ //case 1: single chunk
+ if (chunkIDList.length == 1)
+ {
+ chunk = bufferChunksObj[chunkIDList[0]];
+
+ chunkDataView = new Uint8Array(srcBodyView.buffer,
+ srcBodyView.byteOffset + chunk["byteOffset"],
+ chunk["byteLength"]);
+
+ newBuffer = gl.createBuffer();
+
+ gl.bindBuffer(bufferType, newBuffer);
+
+ //upload all chunk data to GPU
+ gl.bufferData(bufferType, chunkDataView, gl.STATIC_DRAW);
+
+ viewIDsToGLBufferIDs[bufferViewID] = newBuffer;
+ }
+ //case 2: multiple chunks
+ else
+ {
+ newBuffer = gl.createBuffer();
+
+ gl.bindBuffer(bufferType, newBuffer);
+
+ //reserve GPU memory for all chunks
+ gl.bufferData(bufferType, bufferView["byteLength"], gl.STATIC_DRAW);
+
+ currentChunkDataOffset = 0;
+
+ for (i = 0; i < chunkIDList.length; ++i)
+ {
+ chunk = bufferChunksObj[chunkIDList[i]];
+
+ chunkDataView = new Uint8Array(srcBodyView.buffer,
+ srcBodyView.byteOffset + chunk["byteOffset"],
+ chunk["byteLength"]);
+
+ //upload chunk data to GPU
+ gl.bufferSubData(bufferType, currentChunkDataOffset, chunkDataView);
+
+ currentChunkDataOffset += chunk["byteLength"];
+ }
+
+ viewIDsToGLBufferIDs[bufferViewID] = newBuffer;
+ }
+ }
+ },
+
+ /**
+ * Returns the node's local volume
+ * @returns {x3dom.fields.BoxVolume} the local, axis-aligned bounding volume
+ */
+ getVolume: function()
+ {
+ var vol = this._mesh._vol;
+ var shapeNode;
+
+ if (!vol.isValid())
+ {
+ //an ExternalGeometry node must _always_ be a child of (at least) one shape node
+ //for multiple Shape nodes using a single ExternalGeometry node,
+ //we assume that either all of them, or no one have specified a bounding volume
+ shapeNode = this._parentNodes[0];
+
+ if (typeof shapeNode._vf["bboxCenter"] != 'undefined' &&
+ typeof shapeNode._vf["bboxSize"] != 'undefined' )
+ {
+ vol.setBoundsByCenterSize(shapeNode._vf["bboxCenter"], shapeNode._vf["bboxSize"]);
+ }
+ //if no bbox information was specified for the Shape node, use information from the SRC header
+ else
+ {
+ //TODO: implement
+ }
+ }
+
+ return vol;
+ }
+
+ //----------------------------------------------------------------------------------------------------------
+
+ /*nodeChanged: function()
+ {
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node._dirty.normals = true;
+ node._dirty.texcoords = true;
+ node._dirty.colors = true;
+ });
+ this._vol.invalidate();
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName == "index" ||fieldName == "coord" || fieldName == "normal" ||
+ fieldName == "texCoord" || fieldName == "color") {
+ this._dirty[fieldName] = true;
+ this._vol.invalidate();
+ }
+ else if (fieldName == "implicitMeshSize") {
+ this._vol.invalidate();
+ }
+ }*/
+
+ }
+ )
+);
+
+
+//----------------------------------------------------------------------------------------------------------------------
+// PUBLIC STATIC FUNCTIONS
+//----------------------------------------------------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------------------------------------------
+// PRIVATE STATIC FUNCTIONS
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ *
+ * @param {STRING} type - accessor type, must be "SCALAR", "VEC2", "VEC3" or "VEC4"
+ * @private
+ */
+x3dom.nodeTypes.ExternalGeometry._findNumComponentsForSRCAccessorType = function(type)
+{
+ switch (type)
+ {
+ case "SCALAR": return 1;
+ case "VEC2": return 2;
+ case "VEC3": return 3;
+ case "VEC4": return 4;
+ default: return 0;
+ }
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DBinaryContainerGeometryNode ### */
+x3dom.registerNodeType(
+ "X3DBinaryContainerGeometryNode",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DSpatialGeometryNode,
+
+ /**
+ * Constructor for X3DBinaryContainerGeometryNode
+ * @constructs x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @x3d x.x
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DSpatialGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DBinaryContainerGeometryNode.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.SFVec3f} position
+ * @memberof x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'position', 0, 0, 0);
+
+ /**
+ *
+ * @var {x3dom.fields.SFVec3f} size
+ * @memberof x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @initvalue 1,1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'size', 1, 1, 1);
+
+ /**
+ *
+ * @var {x3dom.fields.MFInt32} vertexCount
+ * @memberof x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @initvalue [0]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'vertexCount', [0]);
+
+ /**
+ *
+ * @var {x3dom.fields.MFString} primType
+ * @memberof x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @initvalue ['TRIANGLES']
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFString(ctx, 'primType', ['TRIANGLES']);
+
+ // correct min/max of bounding volume set in BinaryContainerGeometry
+ this._mesh._invalidate = false;
+ this._mesh._numCoords = 0;
+ this._mesh._numFaces = 0;
+
+ this._diameter = this._vf.size.length();
+
+ },
+ {
+ getMin: function() {
+ var vol = this._mesh._vol;
+
+ if (!vol.isValid()) {
+ vol.setBoundsByCenterSize(this._vf.position, this._vf.size);
+ }
+
+ return vol.min;
+ },
+
+ getMax: function() {
+ var vol = this._mesh._vol;
+
+ if (!vol.isValid()) {
+ vol.setBoundsByCenterSize(this._vf.position, this._vf.size);
+ }
+
+ return vol.max;
+ },
+
+ getVolume: function() {
+ var vol = this._mesh._vol;
+
+ if (!vol.isValid()) {
+ vol.setBoundsByCenterSize(this._vf.position, this._vf.size);
+ }
+
+ return vol;
+ },
+
+ invalidateVolume: function() {
+ // at the moment, do nothing here since field updates are not impl.
+ },
+
+ getCenter: function() {
+ return this._vf.position;
+ },
+
+ getDiameter: function() {
+ return this._diameter;
+ },
+
+ needLighting: function() {
+ var hasTris = (this._vf.primType.length && this._vf.primType[0].indexOf("TRIANGLE") >= 0);
+ return (this._vf.lit && hasTris);
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### BinaryGeometry ### */
+x3dom.registerNodeType(
+ "BinaryGeometry",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DBinaryContainerGeometryNode,
+
+ /**
+ * Constructor for BinaryGeometry
+ * @constructs x3dom.nodeTypes.BinaryGeometry
+ * @x3d x.x
+ * @component Geometry3D
+ * @extends x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The BinaryGeometry node can load binary data exported by AOPT.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.BinaryGeometry.superClass.call(this, ctx);
+
+
+ /**
+ * The url to the binary file, that contains the index data.
+ * @var {x3dom.fields.SFString} index
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'index', ""); // Uint16
+
+ /**
+ * The url to the binary file, that contains the mesh coordinates.
+ * @var {x3dom.fields.SFString} coord
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'coord', ""); // Float32
+
+ /**
+ * The url to the binary file, that contains the normals.
+ * @var {x3dom.fields.SFString} normal
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'normal', "");
+
+ /**
+ * The url to the binary file, that contains the texture coordinates.
+ * @var {x3dom.fields.SFString} texCoord
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'texCoord', ""); // THINKABOUTME: add texCoord1, texCoord2, ...?
+
+ /**
+ * The url to the binary file, that contains the colors.
+ * @var {x3dom.fields.SFString} color
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'color', "");
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} tangent
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'tangent', ""); // TODO
+
+ /**
+ *
+ * @var {x3dom.fields.SFString} binormal
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'binormal', ""); // TODO
+
+ // Typed Array View Types
+ // Int8, Uint8, Int16, Uint16, Int32, Uint32, Float32, Float64
+
+ /**
+ * Specifies the byte format of the index data.
+ * @var {x3dom.fields.SFString} indexType
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue "Uint16"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'indexType', "Uint16");
+
+ /**
+ * Specifies the byte format of the coordinates.
+ * @var {x3dom.fields.SFString} coordType
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue "Float32"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'coordType', "Float32");
+
+ /**
+ * Specifies the byte format of the normals.
+ * @var {x3dom.fields.SFString} normalType
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue "Float32"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'normalType', "Float32");
+
+ /**
+ * Specifies the byte format of the texture coordinates.
+ * @var {x3dom.fields.SFString} texCoordType
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue "Float32"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'texCoordType', "Float32");
+
+ /**
+ * Specifies the byte format of the colors.
+ * @var {x3dom.fields.SFString} colorType
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue "Float32"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'colorType', "Float32");
+
+ /**
+ * Specifies the byte format of the tangents.
+ * @var {x3dom.fields.SFString} tangentType
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue "Float32"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'tangentType', "Float32");
+
+ /**
+ * Specifies the byte format of the binormals.
+ * @var {x3dom.fields.SFString} binormalType
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue "Float32"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'binormalType', "Float32");
+
+
+ /**
+ * Specifies whether the normals are encoded as spherical coordinates.
+ * @var {x3dom.fields.SFBool} normalAsSphericalCoordinates
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'normalAsSphericalCoordinates', false);
+
+ /**
+ * Enables RGBA colors.
+ * @var {x3dom.fields.SFBool} rgbaColors
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'rgbaColors', false);
+
+ /**
+ * Specifies the number of texture coordinates per vertex.
+ * @var {x3dom.fields.SFInt32} numTexCoordComponents
+ * @range [1, inf]
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue 2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'numTexCoordComponents', 2);
+
+ /**
+ * Specifies whether normals are stored per vertex or per face.
+ * @var {x3dom.fields.SFBool} normalPerVertex
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'normalPerVertex', true);
+
+ /**
+ * Flag that specifies whether vertex IDs are given as texture coordinates.
+ * @var {x3dom.fields.SFBool} idsPerVertex
+ * @memberof x3dom.nodeTypes.BinaryGeometry
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'idsPerVertex', false);
+
+ // workaround
+ this._hasStrideOffset = false;
+ this._mesh._numPosComponents = this._vf.normalAsSphericalCoordinates ? 4 : 3;
+ this._mesh._numTexComponents = this._vf.numTexCoordComponents;
+ this._mesh._numColComponents = this._vf.rgbaColors ? 4 : 3;
+ this._mesh._numNormComponents = this._vf.normalAsSphericalCoordinates ? 2 : 3;
+
+ // info helper members
+ this._vertexCountSum = 0;
+ for (var i=0; i<this._vf.vertexCount.length; ++i) {
+ this._vertexCountSum += this._vf.vertexCount[i];
+ }
+
+ },
+ {
+ parentAdded: function(parent)
+ {
+ // TODO; also handle multiple shape parents!
+ var offsetInd, strideInd, offset, stride;
+
+ offsetInd = this._vf.coord.lastIndexOf('#');
+ strideInd = this._vf.coord.lastIndexOf('+');
+ if (offsetInd >= 0 && strideInd >= 0) {
+ offset = +this._vf.coord.substring(++offsetInd, strideInd);
+ stride = +this._vf.coord.substring(strideInd);
+ parent._coordStrideOffset = [stride, offset];
+ this._hasStrideOffset = true;
+ if ((offset / 8) - Math.floor(offset / 8) == 0) {
+ this._mesh._numPosComponents = 4;
+ }
+ //x3dom.debug.logInfo("coord stride/offset: " + stride + ", " + offset);
+ }
+ else if (strideInd >= 0) {
+ stride = +this._vf.coord.substring(strideInd);
+ parent._coordStrideOffset = [stride, 0];
+ if ((stride / 8) - Math.floor(stride / 8) == 0) {
+ this._mesh._numPosComponents = 4; // ???
+ }
+ //x3dom.debug.logInfo("coord stride: " + stride);
+ }
+
+ offsetInd = this._vf.normal.lastIndexOf('#');
+ strideInd = this._vf.normal.lastIndexOf('+');
+ if (offsetInd >= 0 && strideInd >= 0) {
+ offset = +this._vf.normal.substring(++offsetInd, strideInd);
+ stride = +this._vf.normal.substring(strideInd);
+ parent._normalStrideOffset = [stride, offset];
+ //x3dom.debug.logInfo("normal stride/offset: " + stride + ", " + offset);
+ }
+ else if (strideInd >= 0) {
+ stride = +this._vf.normal.substring(strideInd);
+ parent._normalStrideOffset = [stride, 0];
+ //x3dom.debug.logInfo("normal stride: " + stride);
+ }
+
+ offsetInd = this._vf.texCoord.lastIndexOf('#');
+ strideInd = this._vf.texCoord.lastIndexOf('+');
+ if (offsetInd >= 0 && strideInd >= 0) {
+ offset = +this._vf.texCoord.substring(++offsetInd, strideInd);
+ stride = +this._vf.texCoord.substring(strideInd);
+ parent._texCoordStrideOffset = [stride, offset];
+ //x3dom.debug.logInfo("texCoord stride/offset: " + stride + ", " + offset);
+ }
+ else if (strideInd >= 0) {
+ stride = +this._vf.texCoord.substring(strideInd);
+ parent._texCoordStrideOffset = [stride, 0];
+ //x3dom.debug.logInfo("texCoord stride: " + stride);
+ }
+
+ offsetInd = this._vf.color.lastIndexOf('#');
+ strideInd = this._vf.color.lastIndexOf('+');
+ if (offsetInd >= 0 && strideInd >= 0) {
+ offset = +this._vf.color.substring(++offsetInd, strideInd);
+ stride = +this._vf.color.substring(strideInd);
+ parent._colorStrideOffset = [stride, offset];
+ //x3dom.debug.logInfo("color stride/offset: " + stride + ", " + offset);
+ }
+ else if (strideInd >= 0) {
+ stride = +this._vf.color.substring(strideInd);
+ parent._colorStrideOffset = [stride, 0];
+ //x3dom.debug.logInfo("color stride: " + stride);
+ }
+
+ if (this._vf.indexType != "Uint16" && !x3dom.caps.INDEX_UINT)
+ x3dom.debug.logWarning("Index type " + this._vf.indexType + " problematic");
+ },
+
+ doIntersect: function(line)
+ {
+ var min = this.getMin();
+ var max = this.getMax();
+ var isect = line.intersect(min, max);
+
+ if (isect && line.enter < line.dist) {
+ line.dist = line.enter;
+ line.hitObject = this;
+ line.hitPoint = line.pos.add(line.dir.multiply(line.enter));
+ return true;
+ }
+ else {
+ return false;
+ }
+ },
+
+ getPrecisionMax: function(type)
+ {
+ switch(this._vf[type])
+ {
+ case "Int8":
+ return 127.0;
+ case "Uint8":
+ return 255.0;
+ case "Int16":
+ return 32767.0;
+ case "Uint16":
+ return 65535.0;
+ case "Int32":
+ return 2147483647.0;
+ case "Uint32":
+ return 4294967295.0;
+ case "Float32":
+ case "Float64":
+ default:
+ return 1.0;
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PopGeometryLevel ### */
+x3dom.registerNodeType(
+ "PopGeometryLevel",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DGeometricPropertyNode,
+
+ /**
+ * Constructor for PopGeometryLevel
+ * @constructs x3dom.nodeTypes.PopGeometryLevel
+ * @x3d x.x
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DGeometricPropertyNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PopGeometryLevel node holds data of one refinement level for the PopGeometry node.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PopGeometryLevel.superClass.call(this, ctx);
+
+
+ /**
+ * Location of the binary file that contains the data of this refinement level.
+ * @var {x3dom.fields.SFString} src
+ * @memberof x3dom.nodeTypes.PopGeometryLevel
+ * @initvalue ""
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'src', "");
+
+ /**
+ * Number of indices shipped with this refinement level.
+ * @var {x3dom.fields.SFInt32} numIndices
+ * @memberof x3dom.nodeTypes.PopGeometryLevel
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'numIndices', 0);
+
+ /**
+ * Offset of the interleaved attribute data of this refinement level within the target vertex buffer.
+ * @var {x3dom.fields.SFInt32} vertexDataBufferOffset
+ * @memberof x3dom.nodeTypes.PopGeometryLevel
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'vertexDataBufferOffset', 0);
+
+ },
+ {
+ getSrc: function () {
+ return this._vf.src;
+ },
+
+ getNumIndices: function () {
+ return this._vf.numIndices;
+ },
+
+ getVertexDataBufferOffset: function () {
+ return this._vf.vertexDataBufferOffset;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PopGeometry ### */
+x3dom.registerNodeType(
+ "PopGeometry",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DBinaryContainerGeometryNode,
+
+ /**
+ * Constructor for PopGeometry
+ * @constructs x3dom.nodeTypes.PopGeometry
+ * @x3d x.x
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PopGeometry node provides a first, experimental implementation of the POP Buffer algorithm for progressive streaming of triangular mesh data.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PopGeometry.superClass.call(this, ctx);
+
+ /**
+ * The size of the bounding box of this geometry, as it is used for culling.
+ * @var {x3dom.fields.SFVec3f} tightSize
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 1,1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f (ctx, 'tightSize', 1, 1, 1);
+ //@todo: add this on export
+
+ /**
+ * The size of the bounding box used to quantize data in this geometry,
+ * which is usually the largest bounding box of all sub-meshes of a given mesh.
+ * @var {x3dom.fields.SFVec3f} maxBBSize
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 1,1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f (ctx, 'maxBBSize', 1, 1, 1);
+
+ /**
+ * The minimum coordinates of the bounding box, in a normalized range between [0,1],
+ * and given modulo maxBBSize.
+ * @var {x3dom.fields.SFVec3f} bbMinModF
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f (ctx, 'bbMinModF', 0, 0, 0);
+
+ /**
+ * The maximum coordinates of the bounding box, in a normalized range between [0,1],
+ * and given modulo maxBBSize.
+ * @var {x3dom.fields.SFVec3f} bbMaxModF
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 1,1,1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f (ctx, 'bbMaxModF', 1, 1, 1);
+
+ /**
+ * Minimum coordinates of the bounding box, in object coordinates.
+ * @var {x3dom.fields.SFVec3f} bbMin
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f (ctx, 'bbMin', 0, 0, 0);
+
+ /**
+ * Field for internal use.
+ * @var {x3dom.fields.SFVec3f} bbShiftVec
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec3f (ctx, 'bbShiftVec', 0, 0, 0);
+
+ if (this._vf.bbMinModF.x > this._vf.bbMaxModF.x)
+ this._vf.bbShiftVec.x = 1.0;
+ if (this._vf.bbMinModF.y > this._vf.bbMaxModF.y)
+ this._vf.bbShiftVec.y = 1.0;
+ if (this._vf.bbMinModF.z > this._vf.bbMaxModF.z)
+ this._vf.bbShiftVec.z = 1.0;
+
+
+ /**
+ * Number of levels of this pop geometry.
+ * @var {x3dom.fields.MFNode} levels
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue x3dom.nodeTypes.PopGeometryLevel
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFNode('levels', x3dom.nodeTypes.PopGeometryLevel);
+
+
+ /**
+ * Stride of all (interleaved) attributes, given in bytes.
+ * @var {x3dom.fields.SFInt32} attributeStride
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'attributeStride', 0);
+
+ /**
+ * Offset, given in bytes, for the position attribute inside the interleaved attribute array.
+ * @var {x3dom.fields.SFInt32} positionOffset
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'positionOffset', 0);
+
+ /**
+ * Offset, given in bytes, for the normal attribute inside the interleaved attribute array.
+ * @var {x3dom.fields.SFInt32} normalOffset
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'normalOffset', 0);
+
+ /**
+ * Offset, given in bytes, for the texture coordinate attribute inside the interleaved attribute array.
+ * @var {x3dom.fields.SFInt32} texcoordOffset
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'texcoordOffset', 0);
+
+ /**
+ * Offset, given in bytes, for the color attribute inside the interleaved attribute array.
+ * @var {x3dom.fields.SFInt32} colorOffset
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'colorOffset', 0);
+
+ /**
+ * Number of anchor vertices (can be 0).
+ * Anchor vertices are used to keep some vertices on the bordes between sub-meshes fixed during refinement.
+ * @var {x3dom.fields.SFInt32} numAnchorVertices
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'numAnchorVertices', 0);
+
+
+ /**
+ * Precision, given in bytes, for the components of the position attribute.
+ * @var {x3dom.fields.SFInt32} positionPrecision
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'positionPrecision', 2);
+
+ /**
+ * Precision, given in bytes, for the components of the normal attribute.
+ * @var {x3dom.fields.SFInt32} normalPrecision
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'normalPrecision', 1);
+
+ /**
+ * Precision, given in bytes, for the components of the texture coordinate attribute.
+ * @var {x3dom.fields.SFInt32} texcoordPrecision
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'texcoordPrecision', 2);
+
+ /**
+ * Precision, given in bytes, for the components of the color attribute.
+ * @var {x3dom.fields.SFInt32} colorPrecision
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'colorPrecision', 1);
+
+
+ /**
+ * Minimum precision level of this PopGeometry node.
+ * This can be used to clamp displayed precision - if the value is -1, no clamping takes place.
+ * @var {x3dom.fields.SFInt32} minPrecisionLevel
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'minPrecisionLevel', -1);
+
+ /**
+ * Maximum precision level of this PopGeometry node.
+ * This can be used to clamp displayed precision - if the value is -1, no clamping takes place.
+ * @var {x3dom.fields.SFInt32} maxPrecisionLevel
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue -1
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'maxPrecisionLevel', -1);
+
+ /**
+ * Additional precision multiplication factor, for tuning the displayed precision.
+ * @var {x3dom.fields.SFFloat} precisionFactor
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 1.0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'precisionFactor', 1.0);
+
+ //those four fields are read by the x3dom renderer
+
+ /**
+ * Field for internal use by the X3DOM renderer.
+ * @var {x3dom.fields.SFString} coordType
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue "Uint16"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'coordType', "Uint16");
+
+ /**
+ * Field for internal use by the X3DOM renderer.
+ * @var {x3dom.fields.SFString} normalType
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue "Uint8"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'normalType', "Uint8");
+
+ /**
+ * Field for internal use by the X3DOM renderer.
+ * @var {x3dom.fields.SFString} texCoordType
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue "Uint16"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'texCoordType', "Uint16");
+
+ /**
+ * Field for internal use by the X3DOM renderer.
+ * @var {x3dom.fields.SFString} colorType
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue "Uint8"
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFString(ctx, 'colorType', "Uint8");
+
+
+ /**
+ * Size of the vertex buffer, used to pre-allocate the buffer before downloading data.
+ * @var {x3dom.fields.SFInt32} vertexBufferSize
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'vertexBufferSize', 0);
+
+
+ /**
+ * Specifies whether this PopGeometry was encoded for indexed rendering.
+ * @var {x3dom.fields.SFBool} indexedRendering
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'indexedRendering', true);
+ //ATTENTION: Although it might be supported by aopt,
+ // X3DOM does not accept 16 bit spherical normals yet,
+ // spherical normals are assumed to be 8 bit and get
+ // encoded as the 4th 16 bit position component
+
+ /**
+ * Specifies whether this PopGeometry was encoded for rendering with spherical normals.
+ * @var {x3dom.fields.SFBool} sphericalNormals
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue false
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'sphericalNormals', false);
+
+ //needed as we manipulate vertexCount during loading
+
+ /**
+ * Vertex count at the highest possible level of precision.
+ * @var {x3dom.fields.MFInt32} originalVertexCount
+ * @memberof x3dom.nodeTypes.PopGeometry
+ * @initvalue [0]
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'originalVertexCount', [0]);
+
+ for (var i = 0; i < this._vf.vertexCount.length; ++i) {
+ this._vf.originalVertexCount[i] = this._vf.vertexCount[i];
+ }
+
+ //@todo: remove this three lines after cleanup
+ this._vf.maxBBSize = x3dom.fields.SFVec3f.copy(this._vf.size);
+ this._vf.size = this._vf.tightSize;
+ this._diameter = this._vf.size.length();
+
+ this._bbMinBySize = [ Math.floor(this._vf.bbMin.x / this._vf.maxBBSize.x),
+ Math.floor(this._vf.bbMin.y / this._vf.maxBBSize.y),
+ Math.floor(this._vf.bbMin.z / this._vf.maxBBSize.z) ];
+ this._volRadius = this._vf.size.length() / 2;
+ this._volLargestRadius = this._vf.maxBBSize.length() / 2;
+
+ // workaround
+ this._mesh._numPosComponents = this._vf.sphericalNormals ? 4 : 3;
+ this._mesh._numNormComponents = this._vf.sphericalNormals ? 2 : 3;
+ this._mesh._numTexComponents = 2;
+ this._mesh._numColComponents = 3;
+
+ x3dom.nodeTypes.PopGeometry.numTotalVerts += this.getVertexCount();
+ x3dom.nodeTypes.PopGeometry.numTotalTris += (this.hasIndex() ?
+ this.getTotalNumberOfIndices() : this.getVertexCount()) / 3;
+
+ },
+ {
+ forceUpdateCoverage: function() {
+ return true;
+ },
+
+ getBBoxShiftVec: function() {
+ return this._vf.bbShiftVec;
+ },
+
+ getBBoxSize: function() {
+ return this._vf.size;
+ },
+
+ hasIndex: function() {
+ return this._vf.indexedRendering;
+ },
+
+ getTotalNumberOfIndices: function() {
+ if (this._vf.indexedRendering) {
+ var sum = 0;
+ for (var i = 0; i < this._vf.originalVertexCount.length; ++i) {
+ sum += this._vf.originalVertexCount[i];
+ }
+ return sum;
+ }
+ else {
+ return 0;
+ }
+ },
+
+ getVertexCount: function() {
+ var sum = 0;
+ for (var i = 0; i < this._vf.originalVertexCount.length; ++i) {
+ sum += this._vf.originalVertexCount[i];
+ }
+ return sum;
+ },
+
+ //adapts the vertex count according to the given total number of indices / vertices
+ //which is used by the renderer
+ adaptVertexCount: function(numVerts) {
+ var verts = 0;
+ for (var i = 0; i < this._vf.originalVertexCount.length; ++i) {
+ if ((this._vf.originalVertexCount[i] + verts) <= numVerts) {
+ this._vf.vertexCount[i] = this._vf.originalVertexCount[i];
+ verts += this._vf.originalVertexCount[i];
+ }
+ else {
+ this._vf.vertexCount[i] = numVerts - verts;
+ break;
+ }
+ }
+ },
+
+ hasNormal: function() {
+ return (this._vf.normalOffset != 0) && !this._vf.sphericalNormals;
+ },
+
+ hasTexCoord: function() {
+ return (this._vf.texcoordOffset != 0);
+ },
+
+ hasColor: function() {
+ return (this._vf.colorOffset != 0);
+ },
+
+ getPositionPrecision : function() {
+ return this._vf.positionPrecision;
+ },
+
+ getNormalPrecision : function() {
+ return this._vf.normalPrecision;
+ },
+
+ getTexCoordPrecision : function() {
+ return this._vf.texcoordPrecision;
+ },
+
+ getColorPrecision : function() {
+ return this._vf.colorPrecision;
+ },
+
+ getAttributeStride : function() {
+ return this._vf.attributeStride;
+ },
+
+ getPositionOffset : function() {
+ return this._vf.positionOffset;
+ },
+
+ getNormalOffset : function() {
+ return this._vf.normalOffset;
+ },
+
+ getTexCoordOffset : function() {
+ return this._vf.texcoordOffset;
+ },
+
+ getColorOffset : function() {
+ return this._vf.colorOffset;
+ },
+
+ getBufferTypeStringFromByteCount: function(bytes) {
+ switch(bytes)
+ {
+ case 1:
+ return "Uint8";
+ case 2:
+ return "Uint16";
+ //case 4: //currently not supported by PopGeometry
+ // return "Float32";
+ default:
+ return 0;
+ }
+ },
+
+ getDataURLs : function() {
+ var urls = [];
+
+ for (var i = 0; i < this._cf.levels.nodes.length; ++i) {
+ urls.push(this._cf.levels.nodes[i].getSrc());
+ }
+
+ return urls;
+ },
+
+ getNumIndicesByLevel : function(lvl) {
+ return this._cf.levels.nodes[lvl].getNumIndices();
+ },
+
+ getNumLevels : function(lvl) {
+ return this._cf.levels.nodes.length;
+ },
+
+ getVertexDataBufferOffset : function(lvl) {
+ return this._cf.levels.nodes[lvl].getVertexDataBufferOffset();
+ },
+
+ getPrecisionMax: function(type) {
+ switch(this._vf[type])
+ {
+ //currently, only Uint8 and Uint16 are supported
+ //case "Int8":
+ // return 127.0;
+ case "Uint8":
+ return 255.0;
+ //case "Int16":
+ // return 32767.0;
+ case "Uint16":
+ return 65535.0;
+ //case "Int32":
+ //return 2147483647.0;
+ //case "Uint32":
+ //return 4294967295.0;
+ //case "Float32":
+ //case "Float64":
+ default:
+ return 1.0;
+ }
+ }
+ }
+ )
+);
+
+
+/** Static class members (needed for stats) */
+x3dom.nodeTypes.PopGeometry.ErrorToleranceFactor = 1;
+x3dom.nodeTypes.PopGeometry.PrecisionFactorOnMove = 1;
+x3dom.nodeTypes.PopGeometry.numRenderedVerts = 0;
+x3dom.nodeTypes.PopGeometry.numRenderedTris = 0;
+x3dom.nodeTypes.PopGeometry.numTotalVerts = 0;
+x3dom.nodeTypes.PopGeometry.numTotalTris = 0;
+
+/** Static LUT for LOD computation */
+x3dom.nodeTypes.PopGeometry.powLUT = [32768, 16384, 8192, 4096, 2048, 1024, 512, 256,
+ 128, 64, 32, 16, 8, 4, 2, 1];
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ImageGeometry ### */
+x3dom.registerNodeType(
+ "ImageGeometry",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DBinaryContainerGeometryNode,
+
+ /**
+ * Constructor for ImageGeometry
+ * @constructs x3dom.nodeTypes.ImageGeometry
+ * @x3d x.x
+ * @component Geometry3D
+ * @extends x3dom.nodeTypes.X3DBinaryContainerGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The image geometry node loads data stored in an image file.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ImageGeometry.superClass.call(this, ctx);
+
+
+ /**
+ *
+ * @var {x3dom.fields.SFVec2f} implicitMeshSize
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue 256,256
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'implicitMeshSize', 256, 256);
+
+ /**
+ * Specifies the number of color components.
+ * @var {x3dom.fields.SFInt32} numColorComponents
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue 3
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'numColorComponents', 3);
+
+ /**
+ * Specifies the number of texture coordinate components.
+ * @var {x3dom.fields.SFInt32} numTexCoordComponents
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue 2
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFInt32(ctx, 'numTexCoordComponents', 2);
+
+
+ /**
+ * Specifies the image file that contains the index data.
+ * @var {x3dom.fields.SFNode} index
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('index', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Specifies the image file that contains the coord data.
+ * @var {x3dom.fields.MFNode} coord
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFNode('coord', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Specifies the image file that contains the normal data.
+ * @var {x3dom.fields.SFNode} normal
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('normal', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Specifies the image file that contains the texcoord data.
+ * @var {x3dom.fields.SFNode} texCoord
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('texCoord', x3dom.nodeTypes.X3DTextureNode);
+
+ /**
+ * Specifies the image file that contains the color data.
+ * @var {x3dom.fields.SFNode} color
+ * @memberof x3dom.nodeTypes.ImageGeometry
+ * @initvalue x3dom.nodeTypes.X3DTextureNode
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFNode('color', x3dom.nodeTypes.X3DTextureNode);
+
+ this._mesh._numColComponents = this._vf.numColorComponents;
+ this._mesh._numTexComponents = this._vf.numTexCoordComponents;
+
+ if (this._vf.implicitMeshSize.y == 0)
+ this._vf.implicitMeshSize.y = this._vf.implicitMeshSize.x;
+
+ //TODO check if GPU-Version is supported (Flash, etc.)
+ //Dummy mesh generation only needed for GPU-Version
+ if (x3dom.caps.BACKEND == 'webgl' && x3dom.caps.MAX_VERTEX_TEXTURE_IMAGE_UNITS > 0) {
+
+ var geoCacheID = 'ImageGeometry_' + this._vf.implicitMeshSize.x + '_' + this._vf.implicitMeshSize.y;
+
+ if( this._vf.useGeoCache && x3dom.geoCache[geoCacheID] !== undefined )
+ {
+ //x3dom.debug.logInfo("Using ImageGeometry-Mesh from Cache");
+ this._mesh = x3dom.geoCache[geoCacheID];
+ }
+ else
+ {
+ for(var y=0; y<this._vf.implicitMeshSize.y; y++)
+ {
+ for(var x=0; x<this._vf.implicitMeshSize.x; x++)
+ {
+ this._mesh._positions[0].push(x / this._vf.implicitMeshSize.x,
+ y / this._vf.implicitMeshSize.y, 0);
+ }
+ }
+
+ //this._mesh._invalidate = true;
+ this._mesh._numFaces = this._mesh._indices[0].length / 3;
+ this._mesh._numCoords = this._mesh._positions[0].length / 3;
+
+ x3dom.geoCache[geoCacheID] = this._mesh;
+ }
+ }
+
+ // needed because mesh is shared due to cache
+ this._vol = new x3dom.fields.BoxVolume();
+
+ this._dirty = {
+ coord: true,
+ normal: true,
+ texCoord: true,
+ color: true,
+ index: true
+ };
+
+ },
+ {
+ setGeoDirty: function () {
+ this._dirty.coord = true;
+ this._dirty.normal = true;
+ this._dirty.texCoords = true;
+ this._dirty.color = true;
+ this._dirty.index = true;
+ },
+
+ unsetGeoDirty: function () {
+ this._dirty.coord = false;
+ this._dirty.normal = false;
+ this._dirty.texCoords = false;
+ this._dirty.color = false;
+ this._dirty.index = false;
+ },
+
+ nodeChanged: function()
+ {
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ node._dirty.normals = true;
+ node._dirty.texcoords = true;
+ node._dirty.colors = true;
+ });
+ this._vol.invalidate();
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName == "index" ||fieldName == "coord" || fieldName == "normal" ||
+ fieldName == "texCoord" || fieldName == "color") {
+ this._dirty[fieldName] = true;
+ this._vol.invalidate();
+ }
+ else if (fieldName == "implicitMeshSize") {
+ this._vol.invalidate();
+ }
+ },
+
+ getMin: function() {
+ var vol = this._vol;
+
+ if (!vol.isValid()) {
+ vol.setBoundsByCenterSize(this._vf.position, this._vf.size);
+ }
+
+ return vol.min;
+ },
+
+ getMax: function() {
+ var vol = this._vol;
+
+ if (!vol.isValid()) {
+ vol.setBoundsByCenterSize(this._vf.position, this._vf.size);
+ }
+
+ return vol.max;
+ },
+
+ getVolume: function() {
+ var vol = this._vol;
+
+ if (!vol.isValid()) {
+ vol.setBoundsByCenterSize(this._vf.position, this._vf.size);
+ }
+
+ return vol;
+ },
+
+ numCoordinateTextures: function()
+ {
+ return this._cf.coord.nodes.length;
+ },
+
+ getIndexTexture: function()
+ {
+ if(this._cf.index.node) {
+ this._cf.index.node._type = "IG_index";
+ return this._cf.index.node;
+ } else {
+ return null;
+ }
+ },
+
+ getIndexTextureURL: function()
+ {
+ if(this._cf.index.node) {
+ return this._cf.index.node._vf.url;
+ } else {
+ return null;
+ }
+ },
+
+ getCoordinateTexture: function(pos)
+ {
+ if(this._cf.coord.nodes[pos]) {
+ this._cf.coord.nodes[pos]._type = "IG_coords" + pos;
+ return this._cf.coord.nodes[pos];
+ } else {
+ return null;
+ }
+ },
+
+ getCoordinateTextureURL: function(pos)
+ {
+ if(this._cf.coord.nodes[pos]) {
+ return this._cf.coord.nodes[pos]._vf.url;
+ } else {
+ return null;
+ }
+ },
+
+ getCoordinateTextureURLs: function()
+ {
+ var urls = [];
+ for(var i=0; i<this._cf.coord.nodes.length; i++)
+ {
+ urls.push(this._cf.coord.nodes[i]._vf.url);
+ }
+ return urls;
+ },
+
+ getNormalTexture: function()
+ {
+ if(this._cf.normal.node) {
+ this._cf.normal.node._type = "IG_normals";
+ return this._cf.normal.node;
+ } else {
+ return null;
+ }
+ },
+
+ getNormalTextureURL: function()
+ {
+ if(this._cf.normal.node) {
+ return this._cf.normal.node._vf.url;
+ } else {
+ return null;
+ }
+ },
+
+ getTexCoordTexture: function()
+ {
+ if(this._cf.texCoord.node) {
+ this._cf.texCoord.node._type = "IG_texCoords";
+ return this._cf.texCoord.node;
+ } else {
+ return null;
+ }
+ },
+
+ getTexCoordTextureURL: function()
+ {
+ if(this._cf.texCoord.node) {
+ return this._cf.texCoord.node._vf.url;
+ } else {
+ return null;
+ }
+ },
+
+ getColorTexture: function()
+ {
+ if(this._cf.color.node) {
+ this._cf.color.node._type = "IG_colors";
+ return this._cf.color.node;
+ } else {
+ return null;
+ }
+ },
+
+ getColorTextureURL: function()
+ {
+ if(this._cf.color.node) {
+ return this._cf.color.node._vf.url;
+ } else {
+ return null;
+ }
+ },
+
+ getTextures: function()
+ {
+ var textures = [];
+
+ var index = this.getIndexTexture();
+ if(index) textures.push(index);
+
+ for(i=0; i<this.numCoordinateTextures(); i++) {
+ var coord = this.getCoordinateTexture(i);
+ if(coord) textures.push(coord);
+ }
+
+ var normal = this.getNormalTexture();
+ if(normal) textures.push(normal);
+
+ var texCoord = this.getTexCoordTexture();
+ if(texCoord) textures.push(texCoord);
+
+ var color = this.getColorTexture();
+ if(color) textures.push(color);
+
+ return textures;
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### IndexedFaceSet ### */
+x3dom.registerNodeType(
+ "IndexedFaceSet",
+ "Geometry3D",
+ defineClass(x3dom.nodeTypes.X3DComposedGeometryNode,
+
+ /**
+ * Constructor for IndexedFaceSet
+ * @constructs x3dom.nodeTypes.IndexedFaceSet
+ * @x3d 3.3
+ * @component Geometry3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DComposedGeometryNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * The IndexedFaceSet node represents a 3D shape formed by constructing faces (polygons) from vertices listed in the coord field.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.IndexedFaceSet.superClass.call(this, ctx);
+
+
+ /**
+ * The creaseAngle field affects how default normals are generated.
+ * If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced.
+ * Crease angles shall be greater than or equal to 0.0 angle base units.
+ * @var {x3dom.fields.SFFloat} creaseAngle
+ * @memberof x3dom.nodeTypes.IndexedFaceSet
+ * @initvalue 0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'creaseAngle', 0); // TODO
+
+ /**
+ * The convex field indicates whether all polygons in the shape are convex (TRUE).
+ * A polygon is convex if it is planar, does not intersect itself, and all of the interior angles at its vertices are less than 180 degrees.
+ * @var {x3dom.fields.SFBool} convex
+ * @memberof x3dom.nodeTypes.IndexedFaceSet
+ * @initvalue true
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'convex', true);
+
+
+ /**
+ * The index data for the coord data.
+ * @var {x3dom.fields.MFInt32} coordIndex
+ * @memberof x3dom.nodeTypes.IndexedFaceSet
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'coordIndex', []);
+
+ /**
+ * The index data for the normal data.
+ * @var {x3dom.fields.MFInt32} normalIndex
+ * @memberof x3dom.nodeTypes.IndexedFaceSet
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'normalIndex', []);
+
+ /**
+ * The index data for the color data.
+ * @var {x3dom.fields.MFInt32} colorIndex
+ * @memberof x3dom.nodeTypes.IndexedFaceSet
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'colorIndex', []);
+
+ /**
+ * The index data for the texcoord data.
+ * @var {x3dom.fields.MFInt32} texCoordIndex
+ * @memberof x3dom.nodeTypes.IndexedFaceSet
+ * @initvalue []
+ * @field x3dom
+ * @instance
+ */
+ this.addField_MFInt32(ctx, 'texCoordIndex', []);
+
+ },
+ {
+ nodeChanged: function()
+ {
+ var time0 = new Date().getTime();
+
+ this.handleAttribs();
+
+ var indexes = this._vf.coordIndex;
+
+ if (indexes.length && indexes[indexes.length-1] != -1)
+ {
+ indexes.push(-1);
+ x3dom.debug.logWarning('Last index value should be -1.');
+ }
+
+ var normalInd = this._vf.normalIndex;
+ var texCoordInd = this._vf.texCoordIndex;
+ var colorInd = this._vf.colorIndex;
+
+ var hasNormal = false, hasNormalInd = false;
+ var hasTexCoord = false, hasTexCoordInd = false;
+ var hasColor = false, hasColorInd = false;
+
+ var colPerVert = this._vf.colorPerVertex;
+ var normPerVert = this._vf.normalPerVertex;
+
+ if (normalInd.length > 0)
+ {
+ hasNormalInd = true;
+ }
+ if (texCoordInd.length > 0)
+ {
+ hasTexCoordInd = true;
+ }
+ if (colorInd.length > 0)
+ {
+ hasColorInd = true;
+ }
+
+ var positions, normals, texCoords, colors;
+
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode);
+ positions = coordNode.getPoints();
+
+ var normalNode = this._cf.normal.node;
+ if (normalNode)
+ {
+ hasNormal = true;
+ normals = normalNode._vf.vector;
+ }
+ else {
+ hasNormal = false;
+ }
+
+ var texMode = "", numTexComponents = 2;
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ if (texCoordNode)
+ {
+ if (texCoordNode._vf.point) {
+ hasTexCoord = true;
+ texCoords = texCoordNode._vf.point;
+
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.TextureCoordinate3D)) {
+ numTexComponents = 3;
+ }
+ }
+ else if (texCoordNode._vf.mode) {
+ texMode = texCoordNode._vf.mode;
+ }
+ }
+ else {
+ hasTexCoord = false;
+ }
+ this._mesh._numTexComponents = numTexComponents;
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ if (colorNode)
+ {
+ hasColor = true;
+ colors = colorNode._vf.color;
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+ else {
+ hasColor = false;
+ }
+ this._mesh._numColComponents = numColComponents;
+
+ this._mesh._indices[0] = [];
+ this._mesh._positions[0] = [];
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] = [];
+ this._mesh._colors[0] = [];
+
+ var i, j, t, cnt, faceCnt;
+ var p0, p1, p2, n0, n1, n2, t0, t1, t2, c0, c1, c2;
+
+ if ( (this._vf.creaseAngle <= x3dom.fields.Eps) || // FIXME; what to do for ipols?
+ (positions.length > x3dom.Utils.maxIndexableCoords) ||
+ (hasNormal && hasNormalInd) ||
+ (hasTexCoord && hasTexCoordInd) ||
+ (hasColor && hasColorInd) )
+ {
+ if (this._vf.creaseAngle <= x3dom.fields.Eps)
+ x3dom.debug.logWarning('Fallback to inefficient multi-index mode since creaseAngle=0.');
+
+ // Found MultiIndex Mesh
+ if(this._vf.convex) {
+ t = 0;
+ cnt = 0;
+ faceCnt = 0;
+ this._mesh._multiIndIndices = [];
+ this._mesh._posSize = positions.length;
+
+ for (i=0; i < indexes.length; ++i)
+ {
+ // Convert non-triangular polygons to a triangle fan
+ // (TODO: this assumes polygons are convex)
+ if (indexes[i] == -1) {
+ t = 0;
+ faceCnt++;
+ continue;
+ }
+
+ if (hasNormalInd) {
+ x3dom.debug.assert(normalInd[i] != -1);
+ }
+ if (hasTexCoordInd) {
+ x3dom.debug.assert(texCoordInd[i] != -1);
+ }
+ if (hasColorInd) {
+ x3dom.debug.assert(colorInd[i] != -1);
+ }
+
+ //TODO: OPTIMIZE but think about cache coherence regarding arrays!!!
+ switch (t)
+ {
+ case 0:
+ p0 = +indexes[i];
+ if (hasNormalInd && normPerVert) { n0 = +normalInd[i]; }
+ else if (hasNormalInd && !normPerVert) { n0 = +normalInd[faceCnt]; }
+ else if (normPerVert) { n0 = p0; }
+ else { n0 = faceCnt; }
+
+ if (hasTexCoordInd) { t0 = +texCoordInd[i]; }
+ else { t0 = p0; }
+ if (hasColorInd && colPerVert) { c0 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c0 = +colorInd[faceCnt]; }
+ else if (colPerVert) { c0 = p0; }
+ else { c0 = faceCnt; }
+ t = 1;
+ break;
+ case 1:
+ p1 = +indexes[i];
+ if (hasNormalInd && normPerVert) { n1 = +normalInd[i]; }
+ else if (hasNormalInd && !normPerVert) { n1 = +normalInd[faceCnt]; }
+ else if (normPerVert) { n1 = p1; }
+ else { n1 = faceCnt; }
+
+ if (hasTexCoordInd) { t1 = +texCoordInd[i]; }
+ else { t1 = p1; }
+ if (hasColorInd && colPerVert) { c1 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c1 = +colorInd[faceCnt]; }
+ else if (colPerVert) { c1 = p1; }
+ else { c1 = faceCnt; }
+ t = 2;
+ break;
+ case 2:
+ p2 = +indexes[i];
+ if (hasNormalInd && normPerVert) { n2 = +normalInd[i]; }
+ else if (hasNormalInd && !normPerVert) { n2 = +normalInd[faceCnt]; }
+ else if (normPerVert) { n2 = p2; }
+ else { n2 = faceCnt; }
+
+ if (hasTexCoordInd) { t2 = +texCoordInd[i]; }
+ else { t2 = p2; }
+ if (hasColorInd && colPerVert) { c2 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c2 = +colorInd[faceCnt]; }
+ else if (colPerVert) { c2 = p2; }
+ else { c2 = faceCnt; }
+ t = 3;
+
+ //this._mesh._indices[0].push(cnt++, cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p0].x);
+ this._mesh._positions[0].push(positions[p0].y);
+ this._mesh._positions[0].push(positions[p0].z);
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+ this._mesh._positions[0].push(positions[p2].x);
+ this._mesh._positions[0].push(positions[p2].y);
+ this._mesh._positions[0].push(positions[p2].z);
+
+ if (hasNormal) {
+ this._mesh._normals[0].push(normals[n0].x);
+ this._mesh._normals[0].push(normals[n0].y);
+ this._mesh._normals[0].push(normals[n0].z);
+ this._mesh._normals[0].push(normals[n1].x);
+ this._mesh._normals[0].push(normals[n1].y);
+ this._mesh._normals[0].push(normals[n1].z);
+ this._mesh._normals[0].push(normals[n2].x);
+ this._mesh._normals[0].push(normals[n2].y);
+ this._mesh._normals[0].push(normals[n2].z);
+ }
+ //else {
+ this._mesh._multiIndIndices.push(p0, p1, p2);
+ //this._mesh._multiIndIndices.push(cnt-3, cnt-2, cnt-1);
+ //}
+
+ if (hasColor) {
+ this._mesh._colors[0].push(colors[c0].r);
+ this._mesh._colors[0].push(colors[c0].g);
+ this._mesh._colors[0].push(colors[c0].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c0].a);
+ }
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c1].a);
+ }
+ this._mesh._colors[0].push(colors[c2].r);
+ this._mesh._colors[0].push(colors[c2].g);
+ this._mesh._colors[0].push(colors[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c2].a);
+ }
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(texCoords[t0].x);
+ this._mesh._texCoords[0].push(texCoords[t0].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t0].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t1].x);
+ this._mesh._texCoords[0].push(texCoords[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t1].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t2].x);
+ this._mesh._texCoords[0].push(texCoords[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t2].z);
+ }
+ }
+
+ //faceCnt++;
+ break;
+ case 3:
+ p1 = p2;
+ t1 = t2;
+ if (normPerVert) {
+ n1 = n2;
+ }
+ if (colPerVert) {
+ c1 = c2;
+ }
+ p2 = +indexes[i];
+
+ if (hasNormalInd && normPerVert) {
+ n2 = +normalInd[i];
+ } else if (hasNormalInd && !normPerVert) {
+ /*n2 = +normalInd[faceCnt];*/
+ } else if (normPerVert) {
+ n2 = p2;
+ } else {
+ n2 = faceCnt;
+ }
+
+ if (hasTexCoordInd) {
+ t2 = +texCoordInd[i];
+ } else {
+ t2 = p2;
+ }
+
+ if (hasColorInd && colPerVert) {
+ c2 = +colorInd[i];
+ } else if (hasColorInd && !colPerVert) {
+ /*c2 = +colorInd[faceCnt];*/
+ } else if (colPerVert) {
+ c2 = p2;
+ } else {
+ c2 = faceCnt;
+ }
+
+ //this._mesh._indices[0].push(cnt++, cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p0].x);
+ this._mesh._positions[0].push(positions[p0].y);
+ this._mesh._positions[0].push(positions[p0].z);
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+ this._mesh._positions[0].push(positions[p2].x);
+ this._mesh._positions[0].push(positions[p2].y);
+ this._mesh._positions[0].push(positions[p2].z);
+
+ if (hasNormal) {
+ this._mesh._normals[0].push(normals[n0].x);
+ this._mesh._normals[0].push(normals[n0].y);
+ this._mesh._normals[0].push(normals[n0].z);
+ this._mesh._normals[0].push(normals[n1].x);
+ this._mesh._normals[0].push(normals[n1].y);
+ this._mesh._normals[0].push(normals[n1].z);
+ this._mesh._normals[0].push(normals[n2].x);
+ this._mesh._normals[0].push(normals[n2].y);
+ this._mesh._normals[0].push(normals[n2].z);
+ }
+ //else {
+ this._mesh._multiIndIndices.push(p0, p1, p2);
+ //this._mesh._multiIndIndices.push(cnt-3, cnt-2, cnt-1);
+ //}
+
+ if (hasColor) {
+ this._mesh._colors[0].push(colors[c0].r);
+ this._mesh._colors[0].push(colors[c0].g);
+ this._mesh._colors[0].push(colors[c0].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c0].a);
+ }
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c1].a);
+ }
+ this._mesh._colors[0].push(colors[c2].r);
+ this._mesh._colors[0].push(colors[c2].g);
+ this._mesh._colors[0].push(colors[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c2].a);
+ }
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(texCoords[t0].x);
+ this._mesh._texCoords[0].push(texCoords[t0].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t0].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t1].x);
+ this._mesh._texCoords[0].push(texCoords[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t1].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t2].x);
+ this._mesh._texCoords[0].push(texCoords[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t2].z);
+ }
+ }
+
+ //faceCnt++;
+ break;
+ default:
+ }
+ }
+ }
+ else {
+ var linklist = new x3dom.DoublyLinkedList();
+ var data = {};
+ cnt = 0; faceCnt = 0;
+
+ for (i = 0; i < indexes.length; ++i)
+ {
+ if (indexes[i] == -1) {
+ var multi_index_data = x3dom.EarClipping.getMultiIndexes(linklist);
+
+ for (j = 0; j < multi_index_data.indices.length; j++)
+ {
+ this._mesh._indices[0].push(cnt);
+ cnt++;
+
+ this._mesh._positions[0].push(multi_index_data.point[j].x,
+ multi_index_data.point[j].y,
+ multi_index_data.point[j].z);
+ if (hasNormal) {
+ this._mesh._normals[0].push(multi_index_data.normals[j].x,
+ multi_index_data.normals[j].y,
+ multi_index_data.normals[j].z);
+ }
+ if (hasColor) {
+ this._mesh._colors[0].push(multi_index_data.colors[j].r,
+ multi_index_data.colors[j].g,
+ multi_index_data.colors[j].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(multi_index_data.colors[j].a);
+ }
+ }
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(multi_index_data.texCoords[j].x,
+ multi_index_data.texCoords[j].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(multi_index_data.texCoords[j].z);
+ }
+ }
+ }
+
+ linklist = new x3dom.DoublyLinkedList();
+ faceCnt++;
+ continue;
+ }
+
+ if (hasNormal) {
+ if (hasNormalInd && normPerVert) {
+ data.normals = normals[normalInd[i]];
+ } else if (hasNormalInd && !normPerVert) {
+ data.normals = normals[normalInd[faceCnt]];
+ } else {
+ data.normals = normals[indexes[i]];
+ }
+ }
+
+ if (hasColor) {
+ if (hasColorInd && colPerVert) {
+ data.colors = colors[colorInd[i]];
+ } else if (hasColorInd && !colPerVert) {
+ data.colors = colors[colorInd[faceCnt]];
+ } else if (colPerVert) {
+ data.colors = colors[indexes[i]];
+ } else {
+ data.colors = colors[faceCnt];
+ }
+ }
+ if (hasTexCoord) {
+ if (hasTexCoordInd) {
+ data.texCoords = texCoords[texCoordInd[i]];
+ } else {
+ data.texCoords = texCoords[indexes[i]];
+ }
+ }
+
+ linklist.appendNode(new x3dom.DoublyLinkedList.ListNode(
+ positions[indexes[i]], indexes[i], data.normals, data.colors, data.texCoords));
+ }
+
+ this._mesh.splitMesh();
+ }
+
+ if (!hasNormal) {
+ this._mesh.calcNormals(this._vf.creaseAngle, this._vf.ccw);
+ }
+ if (!hasTexCoord) {
+ this._mesh.calcTexCoords(texMode);
+ }
+ } // if isMulti
+ else
+ {
+ t = 0;
+ if (this._vf.convex) {
+ for (i = 0; i < indexes.length; ++i)
+ {
+ // Convert non-triangular polygons to a triangle fan
+ if (indexes[i] == -1) {
+ t = 0;
+ continue;
+ }
+
+ switch (t) {
+ case 0: n0 = +indexes[i]; t = 1; break;
+ case 1: n1 = +indexes[i]; t = 2; break;
+ case 2: n2 = +indexes[i]; t = 3; this._mesh._indices[0].push(n0, n1, n2); break;
+ case 3: n1 = n2; n2 = +indexes[i]; this._mesh._indices[0].push(n0, n1, n2); break;
+ }
+
+ }
+ }
+ else {
+ // Convert non-triangular convex polygons to a triangle fan
+ linklist = new x3dom.DoublyLinkedList();
+ for (i = 0; i < indexes.length; ++i)
+ {
+ if (indexes[i] == -1) {
+ var linklist_indices = x3dom.EarClipping.getIndexes(linklist);
+
+ for (j = 0; j < linklist_indices.length; j++) {
+ this._mesh._indices[0].push(linklist_indices[j]);
+ }
+ linklist = new x3dom.DoublyLinkedList();
+ continue;
+ }
+
+ linklist.appendNode(new x3dom.DoublyLinkedList.ListNode(positions[indexes[i]], indexes[i]));
+ }
+ }
+
+ this._mesh._positions[0] = positions.toGL();
+
+ if (hasNormal) {
+ this._mesh._normals[0] = normals.toGL();
+ }
+ else {
+ this._mesh.calcNormals(this._vf.creaseAngle, this._vf.ccw);
+ }
+ if (hasTexCoord) {
+ this._mesh._texCoords[0] = texCoords.toGL();
+ this._mesh._numTexComponents = numTexComponents;
+ }
+ else {
+ this._mesh.calcTexCoords(texMode);
+ }
+ if (hasColor) {
+ this._mesh._colors[0] = colors.toGL();
+ this._mesh._numColComponents = numColComponents;
+ }
+ }
+
+ this.invalidateVolume();
+
+ this._mesh._numFaces = 0;
+ this._mesh._numCoords = 0;
+
+ for (i=0; i<this._mesh._positions.length; i++) {
+ var indexLength = this._mesh._indices[i].length;
+ var numCoords = this._mesh._positions[i].length / 3;
+ this._mesh._numCoords += numCoords;
+ if (indexLength > 0)
+ this._mesh._numFaces += indexLength / 3;
+ else
+ this._mesh._numFaces += numCoords / 3;
+ }
+
+ //var time1 = new Date().getTime() - time0;
+ //x3dom.debug.logInfo("Mesh load time: " + time1 + " ms");
+ },
+
+ fieldChanged: function(fieldName)
+ {
+ if (fieldName != "coord" && fieldName != "normal" &&
+ fieldName != "texCoord" && fieldName != "color" &&
+ fieldName != "coordIndex")
+ {
+ x3dom.debug.logWarning("IndexedFaceSet: fieldChanged for " +
+ fieldName + " not yet implemented!");
+ return;
+ }
+
+ var pnts = this._cf.coord.node._vf.point;
+ var n = pnts.length;
+
+ var texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+
+ if (((this._vf.creaseAngle <= x3dom.fields.Eps) || (n > x3dom.Utils.maxIndexableCoords) ||
+ (this._vf.normalIndex.length > 0 && this._cf.normal.node) ||
+ (this._vf.texCoordIndex.length > 0 && texCoordNode) ||
+ (this._vf.colorIndex.length > 0 && this._cf.color.node)) && this._mesh._multiIndIndices)
+ {
+ var needNormals = !this._cf.normal.node && this._vf.normalUpdateMode.toLowerCase() != 'none';
+
+ n = this._mesh._multiIndIndices.length;
+
+ this._mesh._positions[0] = [];
+ this._mesh._indices[0] =[];
+
+ // special coordinate interpolator handler
+ if (fieldName == "coord" && n)
+ {
+ if (needNormals) {
+ this._mesh._normals[0] = [];
+ }
+
+ for (i=0; i<n; i+=3) {
+ var ind0 = this._mesh._multiIndIndices[i ];
+ var ind1 = this._mesh._multiIndIndices[i+1];
+ var ind2 = this._mesh._multiIndIndices[i+2];
+
+ var pos0 = pnts[ind0];
+ var pos1 = pnts[ind1];
+ var pos2 = pnts[ind2];
+
+ this._mesh._positions[0].push(pos0.x, pos0.y, pos0.z);
+ this._mesh._positions[0].push(pos1.x, pos1.y, pos1.z);
+ this._mesh._positions[0].push(pos2.x, pos2.y, pos2.z);
+
+ if (needNormals) {
+ var a = pos0.subtract(pos1);
+ var b = pos1.subtract(pos2);
+
+ var norm = a.cross(b).normalize();
+ if (!this._vf.ccw)
+ norm = norm.negate();
+
+ this._mesh._normals[0].push(norm.x, norm.y, norm.z);
+ this._mesh._normals[0].push(norm.x, norm.y, norm.z);
+ this._mesh._normals[0].push(norm.x, norm.y, norm.z);
+ }
+ }
+
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ if (needNormals)
+ node._dirty.normals = true;
+ });
+
+ return;
+ }
+
+ // TODO; optimize this very slow and brute force code, at least for creaseAngle=0 case!
+ this._mesh._normals[0] = [];
+ this._mesh._texCoords[0] =[];
+ this._mesh._colors[0] = [];
+
+ var indexes = this._vf.coordIndex;
+ var normalInd = this._vf.normalIndex;
+ var texCoordInd = this._vf.texCoordIndex;
+ var colorInd = this._vf.colorIndex;
+ var hasNormal = false, hasNormalInd = false;
+ var hasTexCoord = false, hasTexCoordInd = false;
+ var hasColor = false, hasColorInd = false;
+
+ var colPerVert = this._vf.colorPerVertex;
+ var normPerVert = this._vf.normalPerVertex;
+
+ if (normalInd.length > 0)
+ {
+ hasNormalInd = true;
+ }
+ if (texCoordInd.length > 0)
+ {
+ hasTexCoordInd = true;
+ }
+ if (colorInd.length > 0)
+ {
+ hasColorInd = true;
+ }
+
+ var positions, normals, texCoords, colors;
+
+ var coordNode = this._cf.coord.node;
+ x3dom.debug.assert(coordNode);
+ positions = coordNode.getPoints();
+
+ var normalNode = this._cf.normal.node;
+ if (normalNode)
+ {
+ hasNormal = true;
+ normals = normalNode._vf.vector;
+ }
+ else {
+ hasNormal = false;
+ }
+
+ var texMode = "", numTexComponents = 2;
+ texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ if (texCoordNode)
+ {
+ if (texCoordNode._vf.point) {
+ hasTexCoord = true;
+ texCoords = texCoordNode._vf.point;
+
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.TextureCoordinate3D)) {
+ numTexComponents = 3;
+ }
+ }
+ else if (texCoordNode._vf.mode) {
+ texMode = texCoordNode._vf.mode;
+ }
+ }
+ else {
+ hasTexCoord = false;
+ }
+ this._mesh._numTexComponents = numTexComponents;
+
+ var numColComponents = 3;
+ var colorNode = this._cf.color.node;
+ if (colorNode)
+ {
+ hasColor = true;
+ colors = colorNode._vf.color;
+
+ if (x3dom.isa(colorNode, x3dom.nodeTypes.ColorRGBA)) {
+ numColComponents = 4;
+ }
+ }
+ else {
+ hasColor = false;
+ }
+ this._mesh._numColComponents = numColComponents;
+
+ var i, j, t, cnt, faceCnt;
+ var p0, p1, p2, n0, n1, n2, t0, t1, t2, c0, c1, c2;
+
+ if(this._vf.convex) {
+ t = 0;
+ cnt = 0;
+ faceCnt = 0;
+ this._mesh._multiIndIndices = [];
+ this._mesh._posSize = positions.length;
+
+ for (i=0; i < indexes.length; ++i)
+ {
+ if (indexes[i] == -1) {
+ t = 0;
+ faceCnt++;
+ continue;
+ }
+
+ if (hasNormalInd) {
+ x3dom.debug.assert(normalInd[i] != -1);
+ }
+ if (hasTexCoordInd) {
+ x3dom.debug.assert(texCoordInd[i] != -1);
+ }
+ if (hasColorInd) {
+ x3dom.debug.assert(colorInd[i] != -1);
+ }
+
+ switch (t)
+ {
+ case 0:
+ p0 = +indexes[i];
+ if (hasNormalInd && normPerVert) { n0 = +normalInd[i]; }
+ else if (hasNormalInd && !normPerVert) { n0 = +normalInd[faceCnt]; }
+ else if (normPerVert) { n0 = p0; }
+ else { n0 = faceCnt; }
+
+ if (hasTexCoordInd) { t0 = +texCoordInd[i]; }
+ else { t0 = p0; }
+ if (hasColorInd && colPerVert) { c0 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c0 = +colorInd[faceCnt]; }
+ else if (colPerVert) { c0 = p0; }
+ else { c0 = faceCnt; }
+ t = 1;
+ break;
+ case 1:
+ p1 = +indexes[i];
+ if (hasNormalInd && normPerVert) { n1 = +normalInd[i]; }
+ else if (hasNormalInd && !normPerVert) { n1 = +normalInd[faceCnt]; }
+ else if (normPerVert) { n1 = p1; }
+ else { n1 = faceCnt; }
+
+ if (hasTexCoordInd) { t1 = +texCoordInd[i]; }
+ else { t1 = p1; }
+ if (hasColorInd && colPerVert) { c1 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c1 = +colorInd[faceCnt]; }
+ else if (colPerVert) { c1 = p1; }
+ else { c1 = faceCnt; }
+ t = 2;
+ break;
+ case 2:
+ p2 = +indexes[i];
+ if (hasNormalInd && normPerVert) { n2 = +normalInd[i]; }
+ else if (hasNormalInd && !normPerVert) { n2 = +normalInd[faceCnt]; }
+ else if (normPerVert) { n2 = p2; }
+ else { n2 = faceCnt; }
+
+ if (hasTexCoordInd) { t2 = +texCoordInd[i]; }
+ else { t2 = p2; }
+ if (hasColorInd && colPerVert) { c2 = +colorInd[i]; }
+ else if (hasColorInd && !colPerVert) { c2 = +colorInd[faceCnt]; }
+ else if (colPerVert) { c2 = p2; }
+ else { c2 = faceCnt; }
+ t = 3;
+
+ //this._mesh._indices[0].push(cnt++, cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p0].x);
+ this._mesh._positions[0].push(positions[p0].y);
+ this._mesh._positions[0].push(positions[p0].z);
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+ this._mesh._positions[0].push(positions[p2].x);
+ this._mesh._positions[0].push(positions[p2].y);
+ this._mesh._positions[0].push(positions[p2].z);
+
+ if (hasNormal) {
+ this._mesh._normals[0].push(normals[n0].x);
+ this._mesh._normals[0].push(normals[n0].y);
+ this._mesh._normals[0].push(normals[n0].z);
+ this._mesh._normals[0].push(normals[n1].x);
+ this._mesh._normals[0].push(normals[n1].y);
+ this._mesh._normals[0].push(normals[n1].z);
+ this._mesh._normals[0].push(normals[n2].x);
+ this._mesh._normals[0].push(normals[n2].y);
+ this._mesh._normals[0].push(normals[n2].z);
+ }
+ //else {
+ this._mesh._multiIndIndices.push(p0, p1, p2);
+ //}
+
+ if (hasColor) {
+ this._mesh._colors[0].push(colors[c0].r);
+ this._mesh._colors[0].push(colors[c0].g);
+ this._mesh._colors[0].push(colors[c0].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c0].a);
+ }
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c1].a);
+ }
+ this._mesh._colors[0].push(colors[c2].r);
+ this._mesh._colors[0].push(colors[c2].g);
+ this._mesh._colors[0].push(colors[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c2].a);
+ }
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(texCoords[t0].x);
+ this._mesh._texCoords[0].push(texCoords[t0].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t0].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t1].x);
+ this._mesh._texCoords[0].push(texCoords[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t1].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t2].x);
+ this._mesh._texCoords[0].push(texCoords[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t2].z);
+ }
+ }
+
+ //faceCnt++;
+ break;
+ case 3:
+ p1 = p2;
+ t1 = t2;
+ if (normPerVert) {
+ n1 = n2;
+ }
+ if (colPerVert) {
+ c1 = c2;
+ }
+ p2 = +indexes[i];
+
+ if (hasNormalInd && normPerVert) {
+ n2 = +normalInd[i];
+ } else if (hasNormalInd && !normPerVert) {
+ /*n2 = +normalInd[faceCnt];*/
+ } else if (normPerVert) {
+ n2 = p2;
+ } else {
+ n2 = faceCnt;
+ }
+
+ if (hasTexCoordInd) {
+ t2 = +texCoordInd[i];
+ } else {
+ t2 = p2;
+ }
+
+ if (hasColorInd && colPerVert) {
+ c2 = +colorInd[i];
+ } else if (hasColorInd && !colPerVert) {
+ /*c2 = +colorInd[faceCnt];*/
+ } else if (colPerVert) {
+ c2 = p2;
+ } else {
+ c2 = faceCnt;
+ }
+
+ //this._mesh._indices[0].push(cnt++, cnt++, cnt++);
+
+ this._mesh._positions[0].push(positions[p0].x);
+ this._mesh._positions[0].push(positions[p0].y);
+ this._mesh._positions[0].push(positions[p0].z);
+ this._mesh._positions[0].push(positions[p1].x);
+ this._mesh._positions[0].push(positions[p1].y);
+ this._mesh._positions[0].push(positions[p1].z);
+ this._mesh._positions[0].push(positions[p2].x);
+ this._mesh._positions[0].push(positions[p2].y);
+ this._mesh._positions[0].push(positions[p2].z);
+
+ if (hasNormal) {
+ this._mesh._normals[0].push(normals[n0].x);
+ this._mesh._normals[0].push(normals[n0].y);
+ this._mesh._normals[0].push(normals[n0].z);
+ this._mesh._normals[0].push(normals[n1].x);
+ this._mesh._normals[0].push(normals[n1].y);
+ this._mesh._normals[0].push(normals[n1].z);
+ this._mesh._normals[0].push(normals[n2].x);
+ this._mesh._normals[0].push(normals[n2].y);
+ this._mesh._normals[0].push(normals[n2].z);
+ }
+ //else {
+ this._mesh._multiIndIndices.push(p0, p1, p2);
+ //}
+
+ if (hasColor) {
+ this._mesh._colors[0].push(colors[c0].r);
+ this._mesh._colors[0].push(colors[c0].g);
+ this._mesh._colors[0].push(colors[c0].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c0].a);
+ }
+ this._mesh._colors[0].push(colors[c1].r);
+ this._mesh._colors[0].push(colors[c1].g);
+ this._mesh._colors[0].push(colors[c1].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c1].a);
+ }
+ this._mesh._colors[0].push(colors[c2].r);
+ this._mesh._colors[0].push(colors[c2].g);
+ this._mesh._colors[0].push(colors[c2].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(colors[c2].a);
+ }
+ }
+
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(texCoords[t0].x);
+ this._mesh._texCoords[0].push(texCoords[t0].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t0].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t1].x);
+ this._mesh._texCoords[0].push(texCoords[t1].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t1].z);
+ }
+ this._mesh._texCoords[0].push(texCoords[t2].x);
+ this._mesh._texCoords[0].push(texCoords[t2].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(texCoords[t2].z);
+ }
+ }
+
+ //faceCnt++;
+ break;
+ default:
+ }
+ }
+ }
+ else {
+ var linklist = new x3dom.DoublyLinkedList();
+ var data = {};
+ cnt = 0; faceCnt = 0;
+
+ for (i = 0; i < indexes.length; ++i)
+ {
+ if (indexes[i] == -1) {
+ var multi_index_data = x3dom.EarClipping.getMultiIndexes(linklist);
+
+ for (j = 0; j < multi_index_data.indices.length; j++)
+ {
+ this._mesh._indices[0].push(cnt);
+ cnt++;
+
+ this._mesh._positions[0].push(multi_index_data.point[j].x,
+ multi_index_data.point[j].y,
+ multi_index_data.point[j].z);
+ if (hasNormal) {
+ this._mesh._normals[0].push(multi_index_data.normals[j].x,
+ multi_index_data.normals[j].y,
+ multi_index_data.normals[j].z);
+ }
+ if (hasColor) {
+ this._mesh._colors[0].push(multi_index_data.colors[j].r,
+ multi_index_data.colors[j].g,
+ multi_index_data.colors[j].b);
+ if (numColComponents === 4) {
+ this._mesh._colors[0].push(multi_index_data.colors[j].a);
+ }
+ }
+ if (hasTexCoord) {
+ this._mesh._texCoords[0].push(multi_index_data.texCoords[j].x,
+ multi_index_data.texCoords[j].y);
+ if (numTexComponents === 3) {
+ this._mesh._texCoords[0].push(multi_index_data.texCoords[j].z);
+ }
+ }
+ }
+
+ linklist = new x3dom.DoublyLinkedList();
+ faceCnt++;
+ continue;
+ }
+
+ if (hasNormal) {
+ if (hasNormalInd && normPerVert) {
+ data.normals = normals[normalInd[i]];
+ } else if (hasNormalInd && !normPerVert) {
+ data.normals = normals[normalInd[faceCnt]];
+ } else {
+ data.normals = normals[indexes[i]];
+ }
+ }
+
+ if (hasColor) {
+ if (hasColorInd && colPerVert) {
+ data.colors = colors[colorInd[i]];
+ } else if (hasColorInd && !colPerVert) {
+ data.colors = colors[colorInd[faceCnt]];
+ } else {
+ data.colors = colors[indexes[i]];
+ }
+ }
+ if (hasTexCoord) {
+ if (hasTexCoordInd) {
+ data.texCoords = texCoords[texCoordInd[i]];
+ } else {
+ data.texCoords = texCoords[indexes[i]];
+ }
+ }
+
+ linklist.appendNode(new x3dom.DoublyLinkedList.ListNode(
+ positions[indexes[i]], indexes[i], data.normals, data.colors, data.texCoords));
+ }
+
+ this._mesh.splitMesh();
+ }
+
+ if (!hasNormal) {
+ this._mesh.calcNormals(this._vf.creaseAngle, this._vf.ccw);
+ }
+ if (!hasTexCoord) {
+ this._mesh.calcTexCoords(texMode);
+ }
+
+ this.invalidateVolume();
+
+ this._mesh._numFaces = 0;
+ this._mesh._numCoords = 0;
+
+ for (i=0; i<this._mesh._positions.length; i++) {
+ var indexLength = this._mesh._indices[i].length;
+ var numCoords = this._mesh._positions[i].length / 3;
+ this._mesh._numCoords += numCoords;
+ if (indexLength > 0)
+ this._mesh._numFaces += indexLength / 3;
+ else
+ this._mesh._numFaces += numCoords / 3;
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node.setGeoDirty();
+ });
+ }
+ else {
+ if (fieldName == "coord")
+ {
+ var needNormals = !this._cf.normal.node && this._vf.normalUpdateMode.toLowerCase() != 'none';
+
+ this._mesh._positions[0] = pnts.toGL();
+
+ if (needNormals) {
+ // position update usually also requires update of vertex normals
+ this._mesh.calcNormals(this._vf.creaseAngle, this._vf.ccw);
+ }
+
+ // tells the mesh that its bbox requires update
+ this.invalidateVolume();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.positions = true;
+ if (needNormals)
+ node._dirty.normals = true;
+ node.invalidateVolume();
+ });
+ }
+ else if (fieldName == "color")
+ {
+ pnts = this._cf.color.node._vf.color;
+
+ this._mesh._colors[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.colors = true;
+ });
+ }
+ else if (fieldName == "normal")
+ {
+ pnts = this._cf.normal.node._vf.vector;
+
+ this._mesh._normals[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.normals = true;
+ });
+ }
+ else if (fieldName == "texCoord")
+ {
+ texCoordNode = this._cf.texCoord.node;
+ if (x3dom.isa(texCoordNode, x3dom.nodeTypes.MultiTextureCoordinate)) {
+ if (texCoordNode._cf.texCoord.nodes.length)
+ texCoordNode = texCoordNode._cf.texCoord.nodes[0];
+ }
+ pnts = texCoordNode._vf.point;
+
+ this._mesh._texCoords[0] = pnts.toGL();
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.texcoords = true;
+ });
+ }
+ else if (fieldName == "coordIndex")
+ {
+ needNormals = !this._cf.normal.node && this._vf.normalUpdateMode.toLowerCase() != 'none';
+
+ indexes = this._vf.coordIndex;
+ t = 0;
+ n = indexes.length;
+
+ this._mesh._indices[0] = [];
+
+ for (i = 0; i < n; ++i) {
+ if (indexes[i] == -1) {
+ t = 0;
+ }
+ else {
+ switch (t) {
+ case 0: p0 = +indexes[i]; t = 1; break;
+ case 1: p1 = +indexes[i]; t = 2; break;
+ case 2: p2 = +indexes[i]; t = 3; this._mesh._indices[0].push(p0, p1, p2); break;
+ case 3: p1 = p2; p2 = +indexes[i]; this._mesh._indices[0].push(p0, p1, p2); break;
+ }
+ }
+ }
+
+ if (needNormals) {
+ // index update usually also requires update of vertex normals
+ this._mesh.calcNormals(this._vf.creaseAngle, this._vf.ccw);
+ }
+
+ Array.forEach(this._parentNodes, function (node) {
+ node._dirty.indexes = true;
+ if (needNormals)
+ node._dirty.normals = true;
+ });
+ }
+ }
+ }
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### X3DTexture3DNode ### */
+x3dom.registerNodeType(
+ "X3DTexture3DNode",
+ "Texturing3D",
+ defineClass(x3dom.nodeTypes.X3DTextureNode,
+
+ /**
+ * Constructor for X3DTexture3DNode
+ * @constructs x3dom.nodeTypes.X3DTexture3DNode
+ * @x3d 3.3
+ * @component Texturing3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc This abstract node type is the base type for all node types that specify 3D sources for texture images.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.X3DTexture3DNode.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ComposedTexture3D ### */
+x3dom.registerNodeType(
+ "ComposedTexture3D",
+ "Texturing3D",
+ defineClass(x3dom.nodeTypes.X3DTexture3DNode,
+
+ /**
+ * Constructor for ComposedTexture3D
+ * @constructs x3dom.nodeTypes.ComposedTexture3D
+ * @x3d 3.3
+ * @component Texturing3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTexture3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ComposedTexture3D node defines a 3D image-based texture map as a collection of 2D texture sources at various depths and parameters controlling tiling repetition of the texture onto geometry.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ComposedTexture3D.superClass.call(this, ctx);
+
+
+ /**
+ * The texture values are interpreted with the first image being at depth 0 and each following image representing an increasing depth value in the R direction.
+ * A user shall provide 2^n source textures in this array. The individual source textures will ignore their repeat field values.
+ * @var {x3dom.fields.MFNode} texture
+ * @memberof x3dom.nodeTypes.ComposedTexture3D
+ * @initvalue x3dom.nodeTypes.X3DTexture3DNode
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFNode('texture', x3dom.nodeTypes.X3DTexture3DNode);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### ImageTexture3D ### */
+x3dom.registerNodeType(
+ "ImageTexture3D",
+ "Texturing3D",
+ defineClass(x3dom.nodeTypes.X3DTexture3DNode,
+
+ /**
+ * Constructor for ImageTexture3D
+ * @constructs x3dom.nodeTypes.ImageTexture3D
+ * @x3d 3.3
+ * @component Texturing3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTexture3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The ImageTexture3D node defines a texture map by specifying a single image file that contains complete 3D data and general parameters for mapping texels to geometry.
+ * The texture is read from the URL specified by the url field. When the url field contains no values ([]), texturing is disabled.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.ImageTexture3D.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### PixelTexture3D ### */
+x3dom.registerNodeType(
+ "PixelTexture3D",
+ "Texturing3D",
+ defineClass(x3dom.nodeTypes.X3DTexture3DNode,
+
+ /**
+ * Constructor for PixelTexture3D
+ * @constructs x3dom.nodeTypes.PixelTexture3D
+ * @x3d 3.3
+ * @component Texturing3D
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DTexture3DNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The PixelTexture3D node defines a 3D image-based texture map as an explicit array of pixel values (image field) and parameters controlling tiling repetition of the texture onto geometry.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.PixelTexture3D.superClass.call(this, ctx);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TextureCoordinate3D ### */
+x3dom.registerNodeType(
+ "TextureCoordinate3D",
+ "Texturing3D",
+ defineClass(x3dom.nodeTypes.X3DTextureCoordinateNode,
+
+ /**
+ * Constructor for TextureCoordinate3D
+ * @constructs x3dom.nodeTypes.TextureCoordinate3D
+ * @x3d 3.3
+ * @component Texturing3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureCoordinateNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The TextureCoordinate3D node is a geometry property node that specifies a set of 3D texture coordinates used by vertex-based geometry nodes (e.g., IndexedFaceSet and ElevationGrid) to map 3D textures to vertices.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TextureCoordinate3D.superClass.call(this, ctx);
+
+
+ /**
+ * Specifies the array of texture coordinates.
+ * @var {x3dom.fields.MFVec3f} point
+ * @memberof x3dom.nodeTypes.TextureCoordinate3D
+ * @initvalue []
+ * @field x3d
+ * @instance
+ */
+ this.addField_MFVec3f(ctx, 'point', []);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TextureTransform3D ### */
+x3dom.registerNodeType(
+ "TextureTransform3D",
+ "Texturing3D",
+ defineClass(x3dom.nodeTypes.X3DTextureTransformNode,
+
+ /**
+ * Constructor for TextureTransform3D
+ * @constructs x3dom.nodeTypes.TextureTransform3D
+ * @x3d 3.3
+ * @component Texturing3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureTransformNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * The TextureTransform3D node specifies a 3D transformation that is applied to texture coordinates.
+ * This node affects the way texture coordinates are applied to the geometric surface. The transformation consists of (in order):
+ * a translation; a rotation about the centre point; and a non-uniform scale about the centre point.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TextureTransform3D.superClass.call(this, ctx);
+
+
+ /**
+ * The center field specifies a translation offset in texture coordinate space about which the rotation and scale fields are applied.
+ * @var {x3dom.fields.SFVec3f} center
+ * @memberof x3dom.nodeTypes.TextureTransform3D
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'center', 0, 0, 0);
+
+ /**
+ * The rotation field specifies a rotation in angle base units of the texture coordinates about the center point after the scale has been applied.
+ * A positive rotation value makes the texture coordinates rotate counterclockwise about the centre, thereby rotating the appearance of the texture itself clockwise.
+ * @var {x3dom.fields.SFRotation} rotation
+ * @memberof x3dom.nodeTypes.TextureTransform3D
+ * @initvalue 0,0,1,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'rotation', 0, 0, 1, 0);
+
+ /**
+ * The scale field specifies a scaling factor in S and T of the texture coordinates about the center point.
+ * @var {x3dom.fields.SFVec3f} scale
+ * @memberof x3dom.nodeTypes.TextureTransform3D
+ * @initvalue 1,1,1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'scale', 1, 1, 1);
+
+ /**
+ * The translation field specifies a translation of the texture coordinates.
+ * @var {x3dom.fields.SFVec3f} translation
+ * @memberof x3dom.nodeTypes.TextureTransform3D
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'translation', 0, 0, 0);
+
+ /**
+ *
+ * @var {x3dom.fields.SFRotation} scaleOrientation
+ * @memberof x3dom.nodeTypes.TextureTransform3D
+ * @initvalue 0,0,1,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'scaleOrientation', 0, 0, 1, 0);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/* ### TextureTransformMatrix3D ### */
+x3dom.registerNodeType(
+ "TextureTransformMatrix3D",
+ "Texturing3D",
+ defineClass(x3dom.nodeTypes.X3DTextureTransformNode,
+
+ /**
+ * Constructor for TextureTransformMatrix3D
+ * @constructs x3dom.nodeTypes.TextureTransformMatrix3D
+ * @x3d 3.3
+ * @component Texturing3D
+ * @status full
+ * @extends x3dom.nodeTypes.X3DTextureTransformNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The TextureTransform3D node specifies a 3D transformation that is applied to texture coordinates.
+ * This node affects the way texture coordinates are applied to the geometric surface.
+ * The transformation consists of a transformation matrix.
+ */
+ function (ctx) {
+ x3dom.nodeTypes.TextureTransformMatrix3D.superClass.call(this, ctx);
+
+
+ /**
+ * The matrix field specifies a generalized, unfiltered 4×4 transformation matrix that can be used to modify the texture. Any set of values is permitted.
+ * @var {x3dom.fields.SFMatrix4f} matrix
+ * @memberof x3dom.nodeTypes.TextureTransformMatrix3D
+ * @initvalue 1,0,0,0
+ * @field x3dom
+ * @instance
+ */
+ this.addField_SFMatrix4f(ctx, 'matrix',
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/**
+ * The abstract pointing device sensor node class serves as a base class for all pointing device sensors.
+ * Pointing device sensors catch pointing device events from all sibling nodes.
+ */
+
+x3dom.registerNodeType(
+ "X3DPointingDeviceSensorNode",
+ "PointingDeviceSensor",
+ defineClass(x3dom.nodeTypes.X3DSensorNode,
+
+ /**
+ * Constructor for X3DPointingDeviceSensorNode
+ * @constructs x3dom.nodeTypes.X3DPointingDeviceSensorNode
+ * @x3d 3.3
+ * @component PointingDeviceSensor
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc An abstract base class for all pointing device sensor nodes.
+ */
+ function (ctx)
+ {
+ x3dom.nodeTypes.X3DPointingDeviceSensorNode.superClass.call(this, ctx);
+
+ //---------------------------------------
+ // FIELDS
+ //---------------------------------------
+
+ //route-able output fields
+ //this.addField_SFBool(ctx, 'isOver', false);
+
+
+ //---------------------------------------
+ // PROPERTIES
+ //---------------------------------------
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Function that gets called if the pointing device has been pressed over a sibling node of this sensor
+ * @param {DOMEvent} event - the pointer event
+ * @private
+ */
+ pointerPressedOverSibling: function(event)
+ {
+ if (this._vf.enabled)
+ {
+ this._vf.isActive = true;
+ this.postMessage('isActive', true);
+ }
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Function that gets called if the pointing device has been moved,
+ * after it has been pressed over a sibling of this node
+ * @param {DOMEvent} event - the pointer event
+ * @private
+ */
+ pointerMoved: function(event)
+ {
+
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Function that gets called if the pointing device has entered a sibling of this node.
+ * @param {DOMEvent} event - the pointer event
+ */
+ pointerMovedOver: function(event)
+ {
+ if (this._vf.enabled)
+ {
+ this.postMessage('isOver', true);
+ }
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Function that gets called if the pointing device has left a sibling of this node.
+ * @param {DOMEvent} event - the pointer event
+ */
+ pointerMovedOut: function(event)
+ {
+ if (this._vf.enabled)
+ {
+ this.postMessage('isOver', false);
+ }
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Function that gets called if the pointing device has been released,
+ * after it has been pressed over a sibling of this node
+ * @private
+ */
+ pointerReleased: function()
+ {
+ if (this._vf.enabled)
+ {
+ this._vf.isActive = false;
+ this.postMessage('isActive', false);
+ }
+ }
+
+ //----------------------------------------------------------------------------------------------------------------------
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/**
+ * The abstract drag sensor node class serves as a base class for all drag-style pointing device sensors.
+ */
+
+x3dom.registerNodeType(
+ "X3DDragSensorNode",
+ "PointingDeviceSensor",
+ defineClass(x3dom.nodeTypes.X3DPointingDeviceSensorNode,
+
+ /**
+ * Constructor for X3DDragSensorNode
+ * @constructs x3dom.nodeTypes.X3DDragSensorNode
+ * @x3d 3.3
+ * @component PointingDeviceSensor
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DPointingDeviceSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc An abstract base class for all sensors that are processing drag gestures of the pointer.
+ */
+ function (ctx)
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.superClass.call(this, ctx);
+
+ //---------------------------------------
+ // FIELDS
+ //---------------------------------------
+
+ /**
+ * Determines whether offset values from previous drag gestures are remembered / accumulated.
+ * @var {x3dom.fields.SFBool} autoOffset
+ * @memberof x3dom.nodeTypes.X3DDragSensorNode
+ * @initvalue true
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFBool(ctx, 'autoOffset', true);
+
+ //route-able output fields
+ //this.addField_SFVec3f(ctx, 'trackPoint_changed', 0, 0, 0);
+
+
+ //---------------------------------------
+ // PROPERTIES
+ //---------------------------------------
+
+ //TODO: revise if those are still needed
+ /**
+ * Last mouse position in x direction.
+ * @var {Double} _lastX
+ * @private
+ */
+ this._lastX = -1;
+
+ /**
+ * Last mouse position in y direction.
+ * @var {Double} _lastY
+ * @private
+ */
+ this._lastY = -1;
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DPointingDeviceSensorNode._pointerPressedOverSibling
+ * @param {DOMEvent} event - the pointer event
+ * @private
+ */
+ pointerPressedOverSibling: function(event)
+ {
+ x3dom.nodeTypes.X3DPointingDeviceSensorNode.prototype.pointerPressedOverSibling.call(this, event);
+
+ this._lastX = event.layerX;
+ this._lastY = event.layerY;
+
+ this._startDragging(event.viewarea, event.layerX, event.layerX, event.worldX, event.worldY, event.worldZ);
+ },
+
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DPointingDeviceSensorNode._pointerMoved
+ * @param {DOMEvent] event - the pointer event
+ * @private
+ */
+ pointerMoved: function(event)
+ {
+ x3dom.nodeTypes.X3DPointingDeviceSensorNode.prototype.pointerMoved.call(this, event);
+
+ if (this._vf.isActive && this._vf.enabled)
+ {
+ this._process2DDrag(event.layerX,
+ event.layerY,
+ event.layerX-this._lastX,
+ event.layerY-this._lastY);
+ }
+ },
+
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DPointingDeviceSensorNode._pointerReleased
+ * @private
+ */
+ pointerReleased: function()
+ {
+ x3dom.nodeTypes.X3DPointingDeviceSensorNode.prototype.pointerReleased.call(this);
+
+ this._stopDragging();
+ },
+
+ //----------------------------------------------------------------------------------------------------------
+
+ //----------------------------------------------------------------------------------------------------------
+ // PRIVATE FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * Function that is called as soon as a drag action is initiated.
+ * @param {x3dom.Viewarea} viewarea - the viewarea which initiated the drag operation
+ * @param {Double} x - 2D pointer x coordinate at the time of the dragging initiation
+ * @param {Double} y - 2D pointer y coordinate at the time of the dragging initiation
+ * @param {Double} wx - 3D world x pick coordinate on the sensor geometry at the time of the dragging initiation
+ * @param {Double} wy - 3D world x pick coordinate on the sensor geometry at the time of the dragging initiation
+ * @param {Double} wz - 3D world z pick coordinate on the sensor geometry at the time of the dragging initiation
+ * @private
+ */
+ _startDragging: function(viewarea, x, y, wx, wy, wz)
+ {
+
+ },
+
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * Processes a 2D drag action, using the given 2D delta values.
+ * @param {Double} x - 2D pointer x coordinate at the time of the dragging initiation
+ * @param {Double} y - 2D pointer y coordinate at the time of the dragging initiation
+ * @param {Double} dx - delta of x, with respect to the last time the function was invoked
+ * @param {Double} dy - delta of Y, with respect to the last time the function was invoked
+ * @private
+ */
+ _process2DDrag: function(x, y, dx, dy)
+ {
+
+ },
+
+ //----------------------------------------------------------------------------------------------------------
+
+ /**
+ * Function that is called as soon as a drag action is initiated.
+ * @private
+ */
+ _stopDragging: function()
+ {
+
+ }
+
+ //----------------------------------------------------------------------------------------------------------
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+x3dom.registerNodeType(
+ "X3DTouchSensorNode",
+ "PointingDeviceSensor",
+ defineClass(x3dom.nodeTypes.X3DPointingDeviceSensorNode,
+
+ /**
+ * Constructor for X3DTouchSensorNode
+ * @constructs x3dom.nodeTypes.X3DTouchSensorNode
+ * @x3d 3.3
+ * @component PointingDeviceSensor
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DPointingDeviceSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc An abstract base class for all sensors that process touch events.
+ */
+ function (ctx)
+ {
+ x3dom.nodeTypes.X3DTouchSensorNode.superClass.call(this, ctx);
+
+ //---------------------------------------
+ // FIELDS
+ //---------------------------------------
+
+ //route-able output fields
+ //this.addField_SFTime(ctx, 'touchTime', 0);
+
+
+ //---------------------------------------
+ // PROPERTIES
+ //---------------------------------------
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+x3dom.registerNodeType(
+ "TouchSensor",
+ "PointingDeviceSensor",
+ defineClass(x3dom.nodeTypes.X3DTouchSensorNode,
+
+ /**
+ * Constructor for TouchSensor
+ * @constructs x3dom.nodeTypes.TouchSensor
+ * @x3d 3.3
+ * @component PointingDeviceSensor
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDragSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc TouchSensor tracks location and state of the pointing device, and detects when user points at
+ * geometry. Hint: X3DOM, running in an HTML environment, you actually don't need this node, as you can
+ * simply use HTML events (like onclick) on your nodes. However, this node is implemented to complete the
+ * pointing device sensor component, and it may be useful to ensure compatibility with older X3D scene content.
+ */
+ function (ctx)
+ {
+ x3dom.nodeTypes.TouchSensor.superClass.call(this, ctx);
+
+ //---------------------------------------
+ // FIELDS
+ //---------------------------------------
+
+ //route-able output fields
+ //this.addField_SFVec3f(ctx, 'hitNormal_changed', 0 0 0);
+ //this.addField_SFVec3f(ctx, 'hitPoint_changed', 0 0 0);
+ //this.addField_SFVec2f(ctx, 'hitTexCoord_changed', 0 0);
+
+
+ //---------------------------------------
+ // PROPERTIES
+ //---------------------------------------
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+
+ }
+ )
+);
+
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+/**
+ * The plane sensor node translates drag gestures, performed with a pointing device like a mouse,
+ * into 3D transformations.
+ */
+
+
+x3dom.registerNodeType(
+ "PlaneSensor",
+ "PointingDeviceSensor",
+ defineClass(x3dom.nodeTypes.X3DDragSensorNode,
+
+ /**
+ * Constructor for PlaneSensor
+ * @constructs x3dom.nodeTypes.PlaneSensor
+ * @x3d 3.3
+ * @component PointingDeviceSensor
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDragSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc PlaneSensor converts pointing device motion into 2D translation, parallel to the local Z=0 plane.
+ * Hint: You can constrain translation output to one axis by setting the respective minPosition and maxPosition
+ * members to equal values for that axis.
+ */
+ function (ctx)
+ {
+ x3dom.nodeTypes.PlaneSensor.superClass.call(this, ctx);
+
+ //---------------------------------------
+ // FIELDS
+ //---------------------------------------
+ /**
+ * The local sensor coordinate system is created by additionally applying the axisRotation field value to
+ * the local coordinate system of the sensor node.
+ * @var {x3dom.fields.SFRotation} axisRotation
+ * @memberof x3dom.nodeTypes.PlaneSensor
+ * @initvalue 0,0,1,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'axisRotation', 0, 0, 1, 0);
+
+
+ /**
+ * The minPosition and maxPosition fields allow to constrain the 2D output of the plane sensor, along each
+ * 2D component. If the value of a component in maxPosition is smaller than the value of a component in
+ * minPosition, output is not constrained along the corresponding direction.
+ * @var {x3dom.fields.SFVec2f} minPosition
+ * @memberof x3dom.nodeTypes.PlaneSensor
+ * @initvalue 0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'minPosition', 0, 0);
+
+
+ /**
+ * The minPosition and maxPosition fields allow to constrain the 2D output of the plane sensor, along each
+ * 2D component. If the value of a component in maxPosition is smaller than the value of a component in
+ * minPosition, output is not constrained along the corresponding direction.
+ * @var {x3dom.fields.SFVec2f} maxPosition
+ * @memberof x3dom.nodeTypes.PlaneSensor
+ * @initvalue -1,-1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec2f(ctx, 'maxPosition', -1, -1);
+
+
+ /**
+ * Offset value that is incorporated into the translation output of the sensor.
+ * This value is automatically updated if the value of the autoOffset field is 'true'.
+ * @var {x3dom.fields.SFVec3f} offset
+ * @memberof x3dom.nodeTypes.PlaneSensor
+ * @initvalue 0,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFVec3f(ctx, 'offset', 0, 0, 0);
+
+ //route-able output fields
+ //this.addField_SFVec3f(ctx, 'translation_changed', 0, 0, 0);
+
+
+ //---------------------------------------
+ // PROPERTIES
+ //---------------------------------------
+
+ /**
+ *
+ * @type {x3dom.fields.Quaternion}
+ * @private
+ */
+ //TODO: update on change
+ this._rotationMatrix = this._vf.axisRotation.toMatrix();
+
+ /**
+ * World-To-Local matrix for this node, including the axisRotation of the sensor
+ */
+ this._worldToLocalMatrix = null;
+
+
+ /**
+ * Initial intersection point with the sensor's plane, at the time the sensor was activated
+ * @type {x3dom.fields.SFVec3f}
+ * @private
+ */
+ this._initialPlaneIntersection = null;
+
+ /**
+ * Plane normal, computed on drag start and used during dragging to compute plane intersections
+ * @type {x3dom.fields.SFVec3f}
+ * @private
+ */
+ this._planeNormal = null;
+
+ /**
+ * Current viewarea that is used for dragging, needed for ray setup to compute the plane intersection
+ *
+ * @type {x3dom.Viewarea}
+ * @private
+ */
+ this._viewArea = null;
+
+ /**
+ * Current translation that is produced by this drag sensor
+ * @type {x3dom.fields.SFVec3f}
+ * @private
+ */
+ this._currentTranslation = new x3dom.fields.SFVec3f(0.0, 0.0, 0.0);
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * This function returns the parent transformation of this node, combined with its current axisRotation
+ * @overrides x3dom.nodeTypes.X3DPointingDeviceSensorNode.getCurrentTransform
+ */
+ getCurrentTransform: function ()
+ {
+ var parentTransform = x3dom.nodeTypes.X3DDragSensorNode.prototype.getCurrentTransform.call(this);
+
+ return parentTransform.mult(this._rotationMatrix);
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+ // PRIVATE FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode.prototype._startDragging
+ * @private
+ */
+ _startDragging: function(viewarea, x, y, wx, wy, wz)
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._startDragging.call(this, viewarea, x, y, wx, wy, wz);
+
+ this._viewArea = viewarea;
+
+ this._currentTranslation = new x3dom.fields.SFVec3f(0.0, 0.0, 0.0).add(this._vf.offset);
+
+ //TODO: handle multi-path nodes
+
+ //get model matrix for this node, combined with the axis rotation
+ this._worldToLocalMatrix = this.getCurrentTransform().inverse();
+
+ //remember initial point of intersection with the plane, transform it to local sensor coordinates
+ this._initialPlaneIntersection = this._worldToLocalMatrix.multMatrixPnt(new x3dom.fields.SFVec3f(wx, wy, wz));
+
+ //compute plane normal in local coordinates
+ this._planeNormal = new x3dom.fields.SFVec3f(0.0, 0.0, 1.0);
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode._process2DDrag
+ * @private
+ */
+ _process2DDrag: function(x, y, dx, dy)
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._process2DDrag.call(this, x, y, dx, dy);
+
+ var intersectionPoint;
+ var minPos, maxPos;
+
+ if (this._initialPlaneIntersection)
+ {
+ //compute point of intersection with the plane
+ var viewRay = this._viewArea.calcViewRay(x, y);
+
+ //transform the world coordinates, used for the ray, to local sensor coordinates
+ viewRay.pos = this._worldToLocalMatrix.multMatrixPnt(viewRay.pos);
+ viewRay.dir = this._worldToLocalMatrix.multMatrixVec(viewRay.dir.normalize());
+
+ intersectionPoint = viewRay.intersectPlane(this._initialPlaneIntersection, this._planeNormal);
+
+ //allow interaction from both sides of the plane
+ if (!intersectionPoint)
+ {
+ intersectionPoint = viewRay.intersectPlane(this._initialPlaneIntersection, this._planeNormal.negate());
+ }
+
+ if (intersectionPoint)
+ {
+ //compute difference between new point of intersection and initial point
+ this._currentTranslation = intersectionPoint.subtract(this._initialPlaneIntersection);
+ this._currentTranslation = this._currentTranslation.add(this._vf.offset);
+
+ //clamp translation components, if desired
+ minPos = this._vf.minPosition;
+ maxPos = this._vf.maxPosition;
+
+ if (minPos.x <= maxPos.x)
+ {
+ this._currentTranslation.x = Math.min(this._currentTranslation.x, maxPos.x);
+ this._currentTranslation.x = Math.max(this._currentTranslation.x, minPos.x);
+ }
+ if (minPos.y <= maxPos.y)
+ {
+ this._currentTranslation.y = Math.min(this._currentTranslation.y, maxPos.y);
+ this._currentTranslation.y = Math.max(this._currentTranslation.y, minPos.y);
+ }
+
+ //output translation_changed event
+ this.postMessage('translation_changed', x3dom.fields.SFVec3f.copy(this._currentTranslation));
+ }
+ }
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode._stopDragging
+ * @private
+ */
+ _stopDragging: function()
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._stopDragging.call(this);
+
+ if (this._vf.autoOffset)
+ {
+ this._vf.offset = x3dom.fields.SFVec3f.copy(this._currentTranslation);
+ this.postMessage('offset_changed', this._vf.offset);
+ }
+ }
+
+ //----------------------------------------------------------------------------------------------------------------------
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+ /*
+ * Based on code provided by Fraunhofer IGD.
+ * (C)2014 Toshiba Corporation, Japan.
+ * Dual licensed under the MIT and GPL.
+ */
+
+x3dom.registerNodeType(
+ "SphereSensor",
+ "PointingDeviceSensor",
+ defineClass(x3dom.nodeTypes.X3DDragSensorNode,
+
+ /**
+ * Constructor for SphereSensor
+ * @constructs x3dom.nodeTypes.SphereSensor
+ * @x3d 3.3
+ * @component PointingDeviceSensor
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDragSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc SphereSensor converts pointing device motion into a spherical rotation around the origin of the
+ * local coordinate system.
+ */
+ function (ctx)
+ {
+ x3dom.nodeTypes.SphereSensor.superClass.call(this, ctx);
+
+ //---------------------------------------
+ // FIELDS
+ //---------------------------------------
+ /**
+ * Offset value that is incorporated into the rotation output of the sensor.
+ * This value is automatically updated if the value of the autoOffset field is 'true'.
+ * @var {x3dom.fields.SFRotation} offset
+ * @memberof x3dom.nodeTypes.SphereSensor
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'offset', 0, 1, 0, 0);
+
+ //route-able output fields
+ //this.addField_SFVec3f(ctx, 'rotation_changed', 0, 0, 0);
+
+
+ //---------------------------------------
+ // PROPERTIES
+ //---------------------------------------
+
+ /**
+ * Current rotation that is produced by this sphere sensor
+ * @type {x3dom.fields.Quaternion}
+ * @private
+ */
+ this._currentRotation = null;
+
+ /**
+ * Rotation matrix, derived from the current value of the offset field
+ * @type {x3dom.fields.SFMatrix4f}
+ * @private
+ */
+ this._rotationMatrix = this._vf.offset.toMatrix();
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * This function returns the parent transformation of this node, combined with its current rotation
+ * @overrides x3dom.nodeTypes.X3DPointingDeviceSensorNode.getCurrentTransform
+ */
+ getCurrentTransform: function ()
+ {
+ var parentTransform = x3dom.nodeTypes.X3DDragSensorNode.prototype.getCurrentTransform.call(this);
+
+ return parentTransform.mult(this._rotationMatrix);
+ },
+
+
+ //----------------------------------------------------------------------------------------------------------------------
+ // PRIVATE FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode.prototype._startDragging
+ * @private
+ */
+ _startDragging: function(viewarea, x, y, wx, wy, wz)
+ {
+ //console.log(viewarea, x, y, wx, wy, wz);
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._startDragging.call(this, viewarea, x, y, wx, wy, wz);
+
+ this._currentRotation = new x3dom.fields.Quaternion();
+
+ this._viewArea = viewarea;
+
+ // origin of sphere in local coordinates
+ this._localOrigin = new x3dom.fields.SFVec3f(0.0, 0.0, 0.0);
+
+ this._inverseToWorldMatrix = this.getCurrentTransform().inverse();
+
+ // compute initial point of intersection on the sphere sensor's geometry, in local sphere sensor's coordinate system
+ var firstIntersection = this._inverseToWorldMatrix.multMatrixPnt(new x3dom.fields.SFVec3f(wx, wy, wz));
+
+ this._initialSphereIntersectionVector = firstIntersection.subtract(this._localOrigin);
+
+ this._sphereRadius = this._initialSphereIntersectionVector.length();
+
+ this._initialSphereIntersectionVector = this._initialSphereIntersectionVector.normalize();
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode._process2DDrag
+ * @private
+ */
+ _process2DDrag: function(x, y, dx, dy)
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._process2DDrag.call(this, x, y, dx, dy);
+
+ // We have to compute hit point on virtual sphere's geometry
+ var viewRay = this._viewArea.calcViewRay(x, y);
+ viewRay.pos = this._inverseToWorldMatrix.multMatrixPnt(viewRay.pos);
+ viewRay.dir = this._inverseToWorldMatrix.multMatrixVec(viewRay.dir);
+
+ /*
+ * S := Ray Origin = viewRay.pos
+ * V := Ray Direction = viewRay.dir
+ * O := Sphere Center = this._localOrigin
+ * r := Sphere Radius = this._sphereRadius
+ * alpha := Ray parameter
+ *
+ * If the view ray intersects the virtual sphere centred at O
+ * at (S + alpha*V), it must satisfy the following equation:
+ * | S + alpha*V - O | = r
+ * dot_prod((S + alpha*V - O),(S + alpha*V - O)) = r*r
+ * or,
+ * alpha*alpha*V.V + alpha*2*(V.(S-O)) + (S.S -2O.S + O.O) - r*r = 0
+ * or,
+ * A*alpha*alpha + B*alpha + C = 0
+ */
+
+ var A = viewRay.dir.dot(viewRay.dir);
+ var B = 2.0*(viewRay.dir.dot(viewRay.pos.subtract(this._localOrigin)));
+ var C = viewRay.pos.dot(viewRay.pos) - 2.0*this._localOrigin.dot(viewRay.pos) +
+ this._localOrigin.dot(this._localOrigin) - this._sphereRadius*this._sphereRadius;
+
+ var determinant = (B*B) - (4.0*A*C);
+ var alpha_1;
+ var alpha_2;
+
+ // if the roots are real i.e. the ray intersects the sphere, the determinant must be greater
+ // than or equal to zero
+ if(determinant >= 0.0) {
+ alpha_1 = (-B + Math.sqrt(determinant)) / (2.0*A);
+ alpha_2 = (-B - Math.sqrt(determinant)) / (2.0*A);
+
+ // pick the closer of the two points
+ alpha_1 = Math.min(alpha_1, alpha_2);
+
+ // if the closer intersection point has alpha < 0, then we are inside the sphere and must not do anything
+ if(alpha_1 >= 1.0) {
+ //TODO: output trackPoint_changed event
+ var hitPoint = viewRay.pos.add(viewRay.dir.multiply(alpha_1));
+
+ var vecToHitPoint = hitPoint.subtract(this._localOrigin).normalize();
+
+ this._currentRotation = x3dom.fields.Quaternion.rotateFromTo(this._initialSphereIntersectionVector, vecToHitPoint);
+
+ this._currentRotation = this._currentRotation.multiply(this._vf.offset);
+
+ // output rotationChanged_event, given in local sphere sensor coordinates
+ this.postMessage('rotation_changed', this._currentRotation);
+ }
+ }
+ else {
+ // do nothing, because no intersection
+ }
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode._stopDragging
+ * @private
+ */
+ _stopDragging: function()
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._stopDragging.call(this);
+
+ if (this._vf.autoOffset)
+ {
+ this._vf.offset = this._currentRotation;
+ this.postMessage('offset_changed', this._vf.offset);
+ }
+
+ this._currentRotation = new x3dom.fields.Quaternion();
+ }
+
+ //----------------------------------------------------------------------------------------------------------------------
+ }
+ )
+);
+/** @namespace x3dom.nodeTypes */
+/*
+ * X3DOM JavaScript Library
+ * http://www.x3dom.org
+ *
+ * (C)2009 Fraunhofer IGD, Darmstadt, Germany
+ * Dual licensed under the MIT and GPL
+ */
+
+x3dom.registerNodeType(
+ "CylinderSensor",
+ "PointingDeviceSensor",
+ defineClass(x3dom.nodeTypes.X3DDragSensorNode,
+
+ /**
+ * Constructor for CylinderSensor
+ * @constructs x3dom.nodeTypes.CylinderSensor
+ * @x3d 3.3
+ * @component PointingDeviceSensor
+ * @status experimental
+ * @extends x3dom.nodeTypes.X3DDragSensorNode
+ * @param {Object} [ctx=null] - context object, containing initial settings like namespace
+ * @classdesc The CylinderSensor node converts pointer motion (for example, from a mouse) into rotation values,
+ * using an invisible cylinder of infinite height, aligned with local Y-axis.
+ */
+ function (ctx)
+ {
+ x3dom.nodeTypes.CylinderSensor.superClass.call(this, ctx);
+
+ //---------------------------------------
+ // FIELDS
+ //---------------------------------------
+ /**
+ * Offset value, in radians, that is incorporated into the rotation output of the sensor.
+ * This value is automatically updated if the value of the autoOffset field is 'true'.
+ * @var {x3dom.fields.SFFloat} offset
+ * @memberof x3dom.nodeTypes.CylinderSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'offset', 0);
+
+
+ /**
+ * The local sensor coordinate system is created by additionally applying the axisRotation field value to
+ * the local coordinate system of the sensor node.
+ * @var {x3dom.fields.SFRotation} axisRotation
+ * @memberof x3dom.nodeTypes.CylinderSensor
+ * @initvalue 0,1,0,0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFRotation(ctx, 'axisRotation', 0, 1, 0, 0);
+
+
+ /**
+ * Specifies whether the virtual cylinder's lateral surface or end-cap disks of virtual-geometry sensor are
+ * used for manipulation: If the vertical acute angle between the vector from the viewer to the point of
+ * intersection with the sensor geometry and the local Y axis of the cylinder is greater than or equal to
+ * the value of this field, the sensor uses a virtual cylinder to compute rotation output.
+ * Otherwise, if the angle is smaller than the value of this field, the sensor uses a virtual disk instead.
+ * This value of this field is specified in radians.
+ *
+ * ATTENTION: The value of this field is currently ignored.
+ * The cylinder sensor will always operate in cylinder mode.
+ *
+ * @var {x3dom.fields.SFFloat} axisRotation
+ * @memberof x3dom.nodeTypes.CylinderSensor
+ * @initvalue pi/2
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'diskAngle', 0.262); //this is the official default value, PI/12
+
+
+ /**
+ * The minAngle and maxAngle fields, given in radians, allow to constrain the rotation output of the
+ * cylinder sensor.
+ * If the value of maxAngle is smaller than the value of minAngle, output is not constrained.
+ * @var {x3dom.fields.SFFloat} axisRotation
+ * @memberof x3dom.nodeTypes.CylinderSensor
+ * @initvalue 0
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'minAngle', 0);
+
+
+ /**
+ * The minAngle and maxAngle fields, given in radians, allow to constrain the rotation output of the
+ * cylinder sensor.
+ * If the value of maxAngle is smaller than the value of minAngle, output is not constrained.
+ * @var {x3dom.fields.SFFloat} axisRotation
+ * @memberof x3dom.nodeTypes.CylinderSensor
+ * @initvalue -1
+ * @field x3d
+ * @instance
+ */
+ this.addField_SFFloat(ctx, 'maxAngle', -1);
+
+ //route-able output fields
+ //this.addField_SFRotation(ctx, 'rotation_changed', 0, 0, 1, 0);
+
+
+ //---------------------------------------
+ // PROPERTIES
+ //---------------------------------------
+
+ /**
+ * Rotation matrix, derived from the current value of the axisRotation field
+ * @type {x3dom.fields.SFMatrix4f}
+ * @private
+ */
+ //TODO: updates
+ this._rotationMatrix = this._vf.axisRotation.toMatrix();
+
+ /**
+ * Current value of the matrix that transforms world coordinates to local sensor coordinates
+ * @type {x3dom.fields.SFMatrix4f}
+ * @private
+ */
+ this._inverseToWorldMatrix = null;
+
+ /**
+ * Vector from the virtual local y-Axis to the initial intersection point with the virtual cylinder,
+ * at the time the sensor was activated
+ * @type {x3dom.fields.SFVec3f}
+ * @private
+ */
+ this._initialCylinderIntersectionVector = null;
+
+ /**
+ * Current viewarea that is used for dragging, needed for ray setup to compute the cylinder intersection
+ *
+ * @type {x3dom.Viewarea}
+ * @private
+ */
+ this._viewArea = null;
+
+ /**
+ * Current radius of the virtual cylinder.
+ * @type {number}
+ * @private
+ */
+ this._cylinderRadius = 0.0;
+
+ /**
+ * A line that specifies the current local, virtual y-Axis of this sensor, given in world coordinates.
+ * @type {x3dom.fields.Line}
+ * @private
+ */
+ this._yAxisLine = null;
+
+ /**
+ * Specifies whether we are currently using cylinder behavior or disk behavior.
+ * @type {boolean}
+ * @private
+ */
+ this._cylinderMode = true;
+
+ /**
+ * Current rotation that is produced by this cylinder sensor
+ * @type {x3dom.fields.Quaternion}
+ * @private
+ */
+ this._currentRotationAngle = 0.0;
+ },
+ {
+ //----------------------------------------------------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * This function returns the parent transformation of this node, combined with its current axisRotation
+ * @overrides x3dom.nodeTypes.X3DPointingDeviceSensorNode.getCurrentTransform
+ */
+ getCurrentTransform: function ()
+ {
+ var parentTransform = x3dom.nodeTypes.X3DDragSensorNode.prototype.getCurrentTransform.call(this);
+
+ return parentTransform.mult(this._rotationMatrix);
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+ // PRIVATE FUNCTIONS
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode.prototype._startDragging
+ * @private
+ */
+ _startDragging: function(viewarea, x, y, wx, wy, wz)
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._startDragging.call(this, viewarea, x, y, wx, wy, wz);
+
+ this._currentRotation = new x3dom.fields.Quaternion();
+
+ this._viewArea = viewarea;
+
+ //y axis line, in local sensor coordinates
+ this._yAxisLine = new x3dom.fields.Line(new x3dom.fields.SFVec3f(0.0, 0.0, 0.0),
+ new x3dom.fields.SFVec3f(0.0, 1.0, 0.0));
+
+ this._inverseToWorldMatrix = this.getCurrentTransform().inverse();
+
+ //compute initial cylinder intersection point, in local sensor coordinates
+ var firstIntersection = this._inverseToWorldMatrix.multMatrixPnt(new x3dom.fields.SFVec3f(wx, wy, wz));
+
+ //TODO: add disk mode
+
+ //compute distance between point of intersection and y-axis
+
+ var closestPointOnYAxis = this._yAxisLine.closestPoint(firstIntersection);
+
+ this._initialCylinderIntersectionVector = firstIntersection.subtract(closestPointOnYAxis);
+
+ this._cylinderRadius = this._initialCylinderIntersectionVector.length();
+
+ this._initialCylinderIntersectionVector = this._initialCylinderIntersectionVector.normalize();
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode._process2DDrag
+ * @private
+ */
+ _process2DDrag: function(x, y, dx, dy)
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._process2DDrag.call(this, x, y, dx, dy);
+
+ //cylinder mode
+ if (this._cylinderMode)
+ {
+ //compute hit point on virtual cylinder geometry
+ var viewRay = this._viewArea.calcViewRay(x, y);
+
+ viewRay.pos = this._inverseToWorldMatrix.multMatrixPnt(viewRay.pos);
+ viewRay.dir = this._inverseToWorldMatrix.multMatrixVec(viewRay.dir);
+
+ //0. assume the following equation:
+ // At the point of intersection, the distance between the ray of sight and the cylinder equals
+ // the cylinder radius r.
+ // This means a ray parameter alpha must be found, so that the minimum distance between the point on
+ // the ray and the cylinder axis equals r:
+ // | ((S + alpha*V) - O) - Y*<(S + alpha*V) - O, Y> | = r
+ // with:
+ // | X | = length of vector X
+ // <X1, X2> = dot product of vectors X1, X2
+ // and variables
+ // alpha := Ray Parameter (should be found)
+ // S := Ray Origin
+ // V := Ray Direction
+ // O := Local Y-Axis Anchor Point
+ // Y := Local Y-Axis Direction
+
+ //1. bring equation into the following form:
+ // | alpha * A - B | = r
+ var A = viewRay.dir.subtract(this._yAxisLine.dir.multiply(viewRay.dir.dot(this._yAxisLine.dir)));
+ var B = viewRay.pos.subtract(this._yAxisLine.pos).add(this._yAxisLine.dir.multiply(
+ this._yAxisLine.dir.dot(this._yAxisLine.pos.subtract(viewRay.pos))));
+
+ //2. solve quadratic formula (0, 1 or 2 solutions are possible)
+ var p = 2 * A.dot(B) / A.dot(A);
+ var q = (B.dot(B) - this._cylinderRadius*this._cylinderRadius) / A.dot(A);
+
+ var sqrt_part = p*p*0.25 - q;
+
+ var alpha_1;
+ var alpha_2;
+
+ //is the cylinder hit?
+ if (sqrt_part >= 0)
+ {
+ sqrt_part = Math.sqrt(sqrt_part);
+ alpha_1 = -p*0.5 + sqrt_part;
+ alpha_2 = -p*0.5 - sqrt_part;
+
+ //if we are inside the cylinder, do nothing, otherwise pick the closest point of intersection
+ alpha_1 = Math.min(alpha_1, alpha_2);
+
+ if (alpha_1 > 0.0)
+ {
+ //TODO: output trackPoint_changed event
+ var hitPoint = viewRay.pos.add(viewRay.dir.multiply(alpha_1));
+
+ var closestPointOnYAxis = this._yAxisLine.closestPoint(hitPoint);
+
+ var vecToHitPoint = hitPoint.subtract(closestPointOnYAxis).normalize();
+
+ this._currentRotation = x3dom.fields.Quaternion.rotateFromTo(this._initialCylinderIntersectionVector, vecToHitPoint);
+
+ var offsetQuat = x3dom.fields.Quaternion.axisAngle(this._yAxisLine.dir, this._vf.offset);
+
+ this._currentRotation = this._currentRotation.multiply(offsetQuat);
+
+ //output rotationChanged_event, given in local sensor coordinates
+ this.postMessage('rotation_changed', this._currentRotation);
+ }
+ }
+ }
+ //disk mode
+ else
+ {
+ //TODO: implement
+ }
+ },
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @overrides x3dom.nodeTypes.X3DDragSensorNode._stopDragging
+ * @private
+ */
+ _stopDragging: function()
+ {
+ x3dom.nodeTypes.X3DDragSensorNode.prototype._stopDragging.call(this);
+
+ if (this._vf.autoOffset)
+ {
+ this._vf.offset = this._currentRotation.angle();
+ this.postMessage('offset_changed', this._vf.offset);
+ }
+ }
+
+ //----------------------------------------------------------------------------------------------------------------------
+ }
+ )
+);
+
+x3dom.versionInfo = {
+ version: '1.6.2',
+ revision: '8f5655cec1951042e852ee9def292c9e0194186b',
+ date: 'Sat Dec 20 00:03:52 2014 +0100'
+};
+
+
+x3dom.versionInfo = {
+ version: '1.6.2',
+ revision: '8f5655cec1951042e852ee9def292c9e0194186b',
+ date: 'Sat Dec 20 00:03:52 2014 +0100'
+};
+
diff --git a/debian/patches/100_spelling.patch b/debian/patches/100_spelling.patch
new file mode 100644
index 0000000..eb52570
--- /dev/null
+++ b/debian/patches/100_spelling.patch
@@ -0,0 +1,660 @@
+Description: correct some typos
+Author: Jörg Frings-Fürst <debian@jff-webhosting.net>
+Last-Update: 2015-09-30
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: trunk/spectro/dispcal.c
+===================================================================
+--- trunk.orig/spectro/dispcal.c
++++ trunk/spectro/dispcal.c
+@@ -1937,7 +1937,7 @@ int main(int argc, char *argv[]) {
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+- if (na == NULL) usage(0,"Paramater expected following -W");
++ if (na == NULL) usage(0,"Parameter expected following -W");
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+@@ -1960,13 +1960,13 @@ int main(int argc, char *argv[]) {
+ /* Black point correction amount */
+ } else if (argv[fa][1] == 'k') {
+ fa = nfa;
+- if (na == NULL) usage(0,"Paramater expected following -k");
++ if (na == NULL) usage(0,"Parameter expected following -k");
+ bkcorrect = atof(na);
+ if (bkcorrect < 0.0 || bkcorrect > 1.0) usage(0,"-k parameter must be between 0.0 and 1.0");
+ /* Neutral blend rate (power) */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+- if (na == NULL) usage(0,"Paramater expected following -A");
++ if (na == NULL) usage(0,"Parameter expected following -A");
+ x.nbrate = atof(na);
+ if (x.nbrate < 0.05 || x.nbrate > 20.0) usage(0,"-A parameter must be between 0.05 and 20.0");
+ /* Black brightness */
+@@ -1999,7 +1999,7 @@ int main(int argc, char *argv[]) {
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+- if (na == NULL) usage(0,"Paramater expected following -c");
++ if (na == NULL) usage(0,"Parameter expected following -c");
+ comport = atoi(na);
+ if (comport < 1 || comport > 50) usage(0,"-c parameter %d out of range",comport);
+
+@@ -3063,7 +3063,7 @@ int main(int argc, char *argv[]) {
+ /* Black level adjustment */
+ /* Due to the possibility of the channel offsets not being even, */
+ /* we use the largest of the XYZ values after they have been */
+- /* scaled to be even acording to the white XYZ balance. */
++ /* scaled to be even according to the white XYZ balance. */
+ /* It's safer to set the black level a bit low, and then the */
+ /* calibration curves can bump the low ones up. */
+ if (c == '1') {
+Index: trunk/spectro/spotread.c
+===================================================================
+--- trunk.orig/spectro/spotread.c
++++ trunk/spectro/spotread.c
+@@ -483,7 +483,7 @@ int main(int argc, char *argv[]) {
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+- if (na == NULL) usage("Paramater expected following -c");
++ if (na == NULL) usage("Parameter expected following -c");
+ {
+ comport = atoi(na);
+ if (comport < 1 || comport > 40) usage("-c parameter %d out of range",comport);
+@@ -492,7 +492,7 @@ int main(int argc, char *argv[]) {
+ /* Display type */
+ } else if (argv[fa][1] == 'y') {
+ fa = nfa;
+- if (na == NULL) usage("Paramater expected following -y");
++ if (na == NULL) usage("Parameter expected following -y");
+ dtype = na[0];
+
+ #ifndef SALONEINSTLIB
+@@ -500,7 +500,7 @@ int main(int argc, char *argv[]) {
+ } else if (argv[fa][1] == 'I') {
+
+ fa = nfa;
+- if (na == NULL) usage("Paramater expected following -I");
++ if (na == NULL) usage("Parameter expected following -I");
+ if (strcmp(na, "A") == 0
+ || strcmp(na, "M0") == 0) {
+ tillum_set = spec = 1;
+@@ -539,7 +539,7 @@ int main(int argc, char *argv[]) {
+ /* Spectral Illuminant type for XYZ computation */
+ } else if (argv[fa][1] == 'i') {
+ fa = nfa;
+- if (na == NULL) usage("Paramater expected following -i");
++ if (na == NULL) usage("Parameter expected following -i");
+ if (strcmp(na, "A") == 0) {
+ illum_set = spec = 1;
+ illum = icxIT_A;
+@@ -579,7 +579,7 @@ int main(int argc, char *argv[]) {
+ /* Spectral Observer type */
+ } else if (argv[fa][1] == 'Q') {
+ fa = nfa;
+- if (na == NULL) usage("Paramater expected following -Q");
++ if (na == NULL) usage("Parameter expected following -Q");
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ obType = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+@@ -657,7 +657,7 @@ int main(int argc, char *argv[]) {
+ /* Filter configuration */
+ } else if (argv[fa][1] == 'F') {
+ fa = nfa;
+- if (na == NULL) usage("Paramater expected following -F");
++ if (na == NULL) usage("Parameter expected following -F");
+ if (na[0] == 'n' || na[0] == 'N')
+ fe = inst_opt_filter_none;
+ else if (na[0] == 'p' || na[0] == 'P')
+@@ -672,7 +672,7 @@ int main(int argc, char *argv[]) {
+ /* Extra filter compensation file */
+ } else if (argv[fa][1] == 'E') {
+ fa = nfa;
+- if (na == NULL) usage("Paramater expected following -E");
++ if (na == NULL) usage("Parameter expected following -E");
+ strncpy(filtername,na,MAXNAMEL-1); filtername[MAXNAMEL-1] = '\000';
+
+ /* Show Yxy */
+Index: trunk/spectro/colorhug.c
+===================================================================
+--- trunk.orig/spectro/colorhug.c
++++ trunk/spectro/colorhug.c
+@@ -212,7 +212,7 @@ colorhug_command(colorhug *p,
+
+ a1logd(p->log,8,"colorhug_command: Read %d bytes and %d read\n",xrbytes,rbytes);
+ if (rbytes >= 2) {
+- a1logd(p->log,6,"colorhug_command: recieved cmd '%s' error '%s' args '%s'\n",
++ a1logd(p->log,6,"colorhug_command: received cmd '%s' error '%s' args '%s'\n",
+ inst_desc(buf[1]),
+ colorhug_interp_error((inst *) p, buf[0]),
+ icoms_tohex(buf, rbytes - 2));
+Index: trunk/spectro/dispwin.c
+===================================================================
+--- trunk.orig/spectro/dispwin.c
++++ trunk/spectro/dispwin.c
+@@ -2734,7 +2734,7 @@ int dispwin_install_profile(dispwin *p,
+
+ /* Un-Install a display profile */
+ /* Return nz if failed, */
+-/* 1 if not sucessfully deleted */
++/* 1 if not successfully deleted */
+ /* 2 if profile not found */
+ int dispwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
+ debugr2((errout,"dispwin_uninstall_profile '%s'\n", fname));
+@@ -5128,7 +5128,7 @@ int ddebug /* >0 to print debug sta
+ p->native = native &= ~2;
+ }
+
+- debugr("new_dispwin: return sucessfully\n");
++ debugr("new_dispwin: return successfully\n");
+ return p;
+ }
+
+Index: trunk/spectro/dtp51.c
+===================================================================
+--- trunk.orig/spectro/dtp51.c
++++ trunk/spectro/dtp51.c
+@@ -679,7 +679,7 @@ dtp51_interp_error(inst *pp, int ec) {
+ case DTP51_INVALID_STEP:
+ return "Invalid step";
+ case DTP51_NO_DATA_AVAILABLE:
+- return "No data availble";
++ return "No data avaialble";
+ case DTP51_LAMP_MARGINAL:
+ return "Lamp marginal";
+ case DTP51_LAMP_FAILURE:
+Index: trunk/spectro/dtp92.c
+===================================================================
+--- trunk.orig/spectro/dtp92.c
++++ trunk/spectro/dtp92.c
+@@ -928,7 +928,7 @@ dtp92_interp_error(inst *pp, int ec) {
+ case DTP92_NO_DATA_AVAILABLE:
+ return "No data available";
+ case DTP92_MISSING_PARAMETER:
+- return "Paramter is missing";
++ return "Parameter is missing";
+ case DTP92_CALIBRATION_DENIED:
+ return "Invalid calibration enable code";
+ case DTP92_NEEDS_OFFSET_CAL:
+Index: trunk/spectro/hidio.c
+===================================================================
+--- trunk.orig/spectro/hidio.c
++++ trunk/spectro/hidio.c
+@@ -739,7 +739,7 @@ icoms_hid_read(icoms *p,
+ {
+ unsigned char *rbuf2;
+
+- /* Create a copy of the data recieved with one more byte */
++ /* Create a copy of the data received with one more byte */
+ if ((rbuf2 = malloc(bsize + 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: malloc failed\n");
+ return ICOM_SYS;
+Index: trunk/spectro/huey.c
+===================================================================
+--- trunk.orig/spectro/huey.c
++++ trunk/spectro/huey.c
+@@ -81,7 +81,7 @@ static int icoms2huey_err(int se, int to
+ /* i1Display command codes */
+ /* B = byte (8bit), S = short (16bit), W = word (32bit), A = string */
+ /* U = unused byte, - = no arguments/results */
+-/* The is a 7 byte command buffer and 6 response recieve buffer. */
++/* The is a 7 byte command buffer and 6 response receive buffer. */
+ /* :2 means the read is from a second 8 byte ep x81 read. */
+ /* cbuf[-] is command byte */
+ /* rbuf[-2] is continuation byte */
+Index: trunk/spectro/i1pro_imp.c
+===================================================================
+--- trunk.orig/spectro/i1pro_imp.c
++++ trunk/spectro/i1pro_imp.c
+@@ -3768,7 +3768,7 @@ i1pro_code i1pro_restore_refspot_cal(i1p
+ return I1PRO_OK;
+ }
+
+- /* We've sucessfully restored the dark calibration */
++ /* We've successfully restored the dark calibration */
+ s->dark_valid = 1;
+ s->ddate = m->caldate;
+
+@@ -3813,7 +3813,7 @@ i1pro_code i1pro_restore_refspot_cal(i1p
+ return I1PRO_OK;
+ }
+
+- /* We've sucessfully restored the calibration */
++ /* We've successfully restored the calibration */
+ s->cal_valid = 1;
+ s->cfdate = m->caldate;
+
+Index: trunk/spectro/madvrwin.c
+===================================================================
+--- trunk.orig/spectro/madvrwin.c
++++ trunk/spectro/madvrwin.c
+@@ -593,7 +593,7 @@ int ii = 0;
+ }
+ #endif
+
+- debugr("new_madvrwin: return sucessfully\n");
++ debugr("new_madvrwin: return successfully\n");
+
+ return p;
+ }
+Index: trunk/spectro/ss.c
+===================================================================
+--- trunk.orig/spectro/ss.c
++++ trunk/spectro/ss.c
+@@ -1787,7 +1787,7 @@ ss_interp_error(inst *pp, int ec) {
+ case ss_et_BadHexEncoding:
+ return "Message received from instrument has bad Hex encoding";
+ case ss_et_RecBufferOverun:
+- return "Message received from instrument would overflow recieve buffer";
++ return "Message received from instrument would overflow receive buffer";
+ default:
+ return "Unknown error code";
+ }
+Index: trunk/spectro/ss_imp.c
+===================================================================
+--- trunk.orig/spectro/ss_imp.c
++++ trunk/spectro/ss_imp.c
+@@ -216,7 +216,7 @@ static int h2b(ss *p, char c) {
+ return 0;
+ }
+
+-/* Return the first enum from the recieve buffer without removing it. */
++/* Return the first enum from the receive buffer without removing it. */
+ int ss_peek_ans(ss *p) {
+ int rv;
+
+Index: trunk/spectro/webwin.c
+===================================================================
+--- trunk.orig/spectro/webwin.c
++++ trunk/spectro/webwin.c
+@@ -396,7 +396,7 @@ int ddebug /* >0 to print debug sta
+ msec_sleep(50);
+ }
+
+- debugr("new_webwin: return sucessfully\n");
++ debugr("new_webwin: return successfully\n");
+
+ return p;
+ }
+Index: trunk/xicc/cv.c
+===================================================================
+--- trunk.orig/xicc/cv.c
++++ trunk/xicc/cv.c
+@@ -101,7 +101,7 @@ main(int argc, char *argv[]) {
+
+ printf("There are %d parameters:\n",np); fflush(stdout);
+ for (i = 0; i < np; i++) {
+- printf("Paramter %d = %f\n",i, params[i]); fflush(stdout);
++ printf("Parameter %d = %f\n",i, params[i]); fflush(stdout);
+ }
+
+ /* Display the result */
+Index: trunk/spectro/ss_imp.h
+===================================================================
+--- trunk.orig/spectro/ss_imp.h
++++ trunk/spectro/ss_imp.h
+@@ -720,7 +720,7 @@ void ss_add_string(struct _ss *p, char *
+ /* - - - - - - - - - - - - - - - - - - - - - */
+ /* ANSWER: */
+
+-/* Return the first enum from the recieve buffer without removing it. */
++/* Return the first enum from the receive buffer without removing it. */
+ int ss_peek_ans(struct _ss *p);
+
+ /* Remove a Spectrolino answer enum from the revieve buffer, */
+Index: trunk/imdi/cctiff.c
+===================================================================
+--- trunk.orig/imdi/cctiff.c
++++ trunk/imdi/cctiff.c
+@@ -36,7 +36,7 @@
+ Add flag to ignore inkname mismatches.
+
+
+- Should add support for transfering any extra alpha
++ Should add support for transferring any extra alpha
+ planes from input to output, rather than simply ignoring them.
+
+
+@@ -1953,11 +1953,11 @@ main(int argc, char *argv[]) {
+
+ if (wh != NULL) {
+ printf("Output TIFF file '%s'\n",out_name);
+- printf("Ouput raster file ICC colorspace is %s\n",icm2str(icmColorSpaceSignature,su.outs));
++ printf("Output raster file ICC colorspace is %s\n",icm2str(icmColorSpaceSignature,su.outs));
+ printf("Output TIFF file photometric is %s\n",Photometric2str(wphotometric));
+ } else {
+ printf("Output JPEG file '%s'\n",out_name);
+- printf("Ouput raster file ICC colorspace is %s\n",icm2str(icmColorSpaceSignature,su.outs));
++ printf("Output raster file ICC colorspace is %s\n",icm2str(icmColorSpaceSignature,su.outs));
+ printf("Output JPEG file colorspace is %s\n",JPEG_cspace2str(wj.jpeg_color_space));
+ if (wdesc != NULL)
+ printf("Output raster file description: '%s'\n",wdesc);
+Index: trunk/imdi/imdi.h
+===================================================================
+--- trunk.orig/imdi/imdi.h
++++ trunk/imdi/imdi.h
+@@ -38,7 +38,7 @@ struct _imdi {
+
+ /* Note that once an imdi is created, multiple can call interp() without */
+ /* interfering with each other, allowing parallel execution. */
+- void (*interp)(struct _imdi *s, void **outp, int outst, /* Ouput pointers and stride */
++ void (*interp)(struct _imdi *s, void **outp, int outst, /* Output pointers and stride */
+ void **inp, int inst, /* Input pointers and stride */
+ unsigned int npixels); /* Number of pixels */
+
+Index: trunk/spectro/munki_imp.c
+===================================================================
+--- trunk.orig/spectro/munki_imp.c
++++ trunk/spectro/munki_imp.c
+@@ -6393,7 +6393,7 @@ munki_code munki_create_hr(munki *p, int
+ int i, j, jj, k, cx, sx;
+ munki_fc coeff[40][16]; /* Existing filter cooefficients */
+ int nwav1; /* Number of filters */
+- double wl_short1, wl_long1; /* Ouput wavelength of first and last filters */
++ double wl_short1, wl_long1; /* Output wavelength of first and last filters */
+ double wl_step1;
+ munki_xp xp[41]; /* Crossover points each side of filter */
+ munki_code ev = MUNKI_OK;
+Index: trunk/target/printtarg.c
+===================================================================
+--- trunk.orig/target/printtarg.c
++++ trunk/target/printtarg.c
+@@ -2209,7 +2209,7 @@ int *p_npat /* Return number of patche
+
+
+ } else {
+- error("Unsupported intrument type");
++ error("Unsupported instrument type");
+ }
+
+ /* Compute page limits */
+@@ -2953,7 +2953,7 @@ char *argv[];
+ double sscale = 1.0; /* Spacer size scale */
+ int rand = 1;
+ int qbits = 0; /* Quantization bits */
+- int oft = 0; /* Ouput File type, 0 = PS, 1 = EPS , 2 = TIFF */
++ int oft = 0; /* Output File type, 0 = PS, 1 = EPS , 2 = TIFF */
+ int nocups = 0; /* Supress CUPS PS/EPS job ticket */
+ depth2d tiffdpth = bpc8_2d; /* TIFF pixel depth */
+ double tiffres = 100.0; /* TIFF resolution in DPI */
+Index: trunk/gamut/nearsmth.c
+===================================================================
+--- trunk.orig/gamut/nearsmth.c
++++ trunk/gamut/nearsmth.c
+@@ -261,7 +261,7 @@ double dxratio /* Depth expansion ratio
+ double va, vr = 0.0, vl, vd, vv = 0.0;
+
+ /* Absolute, Delta E^2 between test point and destination closest */
+- /* aodv is already positioned acording to the LCh weights, */
++ /* aodv is already positioned according to the LCh weights, */
+ /* so weight as per average of these */
+ a_o = w->a.o;
+ va = wdesq(dtp, aodv, a_o, a_o, a_o, SUM_POW);
+@@ -3598,7 +3598,7 @@ static void create_influence_plot(nearsm
+ swdiag = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ swdiag->fit_rspl(swdiag, RSPL_NOFLAGS, fpnts, nmpts, NULL, NULL, gres, NULL, NULL, 1.0, avgdev, NULL);
+
+- /* Now create a plot of the sci_gam with the vertexes colored acording to the */
++ /* Now create a plot of the sci_gam with the vertexes colored according to the */
+ /* diagnostic map. */
+ if ((wrl = new_vrml("sci_gam_wt", 1, vrml_lab)) == NULL) {
+ fprintf(stderr,"gamut map: new_vrml failed for '%s%s'\n","sci_gam_wt",vrm_ext());
+Index: trunk/gamut/nearsmth.h
+===================================================================
+--- trunk.orig/gamut/nearsmth.h
++++ trunk/gamut/nearsmth.h
+@@ -274,7 +274,7 @@ gammapweights *src1, double wgt1,
+ gammapweights *src2, double wgt2
+ );
+
+-/* Tweak weights acording to extra cmy cusp flags or rel override */
++/* Tweak weights according to extra cmy cusp flags or rel override */
+ void tweak_weights(gammapweights out[14], int dst_cmymap, int rel_oride);
+
+ #endif /* NEARSMTH_H */
+Index: trunk/imdi/cctiffo.c
+===================================================================
+--- trunk.orig/imdi/cctiffo.c
++++ trunk/imdi/cctiffo.c
+@@ -307,7 +307,7 @@ int pmtc
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+- sprintf(buf,"Unknonw Tag %d",pmtc);
++ sprintf(buf,"Unknown Tag %d",pmtc);
+ return buf;
+ }
+
+Index: trunk/imdi/greytiff.c
+===================================================================
+--- trunk.orig/imdi/greytiff.c
++++ trunk/imdi/greytiff.c
+@@ -132,7 +132,7 @@ int pmtc
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+- sprintf(buf,"Unknonw Tag %d",pmtc);
++ sprintf(buf,"Unknown Tag %d",pmtc);
+ return buf;
+ }
+
+Index: trunk/link/collink.c
+===================================================================
+--- trunk.orig/link/collink.c
++++ trunk/link/collink.c
+@@ -1138,7 +1138,7 @@ void devip_devop(void *cntx, double *out
+ }
+ /* We've got the input profile PCS' at this point. */
+
+- /* If we're transfering the K value from the input profile to the */
++ /* If we're transferring the K value from the input profile to the */
+ /* output, copy it into locus[], which will be given to the inverse */
+ /* lookup function, else the inverse lookup will generate a K using */
+ /* the curve parameters. */
+@@ -1270,7 +1270,7 @@ void devip_devop(void *cntx, double *out
+ if (p->nhack == 2) {
+ /* Ideally we would create a 4D PCSK -> PCSK gamut mapping */
+ /* to smoothly and accurately cope with the changing source */
+- /* and destination gamuts acording to their degree of "K onlyness". */
++ /* and destination gamuts according to their degree of "K onlyness". */
+ /* In practice we're going to simply interpolated between */
+ /* two extremes: unrestricted gamut and K only black gamut. */
+ double map0[3], map1[3];
+Index: trunk/profile/printcal.c
+===================================================================
+--- trunk.orig/profile/printcal.c
++++ trunk/profile/printcal.c
+@@ -1294,7 +1294,7 @@ int main(int argc, char *argv[]) {
+ icmXYZ2Lab(&wht, wp->Lab, wp->XYZ);
+ }
+
+- /* Sort the channel acording to device value */
++ /* Sort the channel according to device value */
+ /* For a consistent result for identical device values, */
+ /* secondary sort by inverse CIE value */
+ //#define HEAP_COMPARE(A,B) ((A).dev < (B).dev)
+Index: trunk/spectro/dispsup.c
+===================================================================
+--- trunk.orig/spectro/dispsup.c
++++ trunk/spectro/dispsup.c
+@@ -707,7 +707,7 @@ static int disprd_read_imp(
+ scb->serno = p->serno++;
+ scb->msec = msec_time();
+
+- a1logd(p->log,1, "got reading %f %f %f, transfering to col\n",
++ a1logd(p->log,1, "got reading %f %f %f, transferring to col\n",
+ val.XYZ[0], val.XYZ[1], val.XYZ[2]);
+
+ scb->mtype = val.mtype;
+Index: trunk/gamut/gammap.c
+===================================================================
+--- trunk.orig/gamut/gammap.c
++++ trunk/gamut/gammap.c
+@@ -775,7 +775,7 @@ gammap *new_gammap(
+ #endif
+ if (gmi->bph == gmm_clipBP) {
+
+- /* Extend the target black point to accomodate the */
++ /* Extend the target black point to accommodate the */
+ /* bent or clipped destination space L* range */
+ if (fabp[0] < dr_cs_bp[0]) {
+ t = (fabp[0] - dr_cs_wp[0])/(dr_cs_bp[0] - dr_cs_wp[0]);
+Index: trunk/profile/profout.c
+===================================================================
+--- trunk.orig/profile/profout.c
++++ trunk/profile/profout.c
+@@ -1048,7 +1048,7 @@ make_output_icc(
+ if (iccver < icmVersion2_4) {
+ iccver = icmVersion2_4; /* Need 2.4.0 for Display intents */
+ if (verb)
+- fprintf(verbo,"Bumped ICC version to 2.4.0 to accomodate multiple Display intents\n");
++ fprintf(verbo,"Bumped ICC version to 2.4.0 to accommodate multiple Display intents\n");
+ }
+ }
+ if (wr_icco->set_version(wr_icco, iccver) != 0)
+Index: trunk/render/thscreen.c
+===================================================================
+--- trunk.orig/render/thscreen.c
++++ trunk/render/thscreen.c
+@@ -636,7 +636,7 @@ thscreen *new_thscreen(
+ mrang = 65535.0/(t->oelev - 1.0);
+ DBG(("new_thscreen() raw modulation rande = %f\n",mrang));
+
+- /* Modify the modulation range to accomodate any level overlap */
++ /* Modify the modulation range to accommodate any level overlap */
+ if (olap > 0.0 && t->oelev > 2) {
+ mrang = ((t->oelev - 2.0) * olap * mrang + 65535.0)/(t->oelev - 1.0);
+ DBG(("new_thscreen() modulation adjusted for overlap = %f\n",mrang));
+Index: trunk/xicc/xspect.c
+===================================================================
+--- trunk.orig/xicc/xspect.c
++++ trunk/xicc/xspect.c
+@@ -4440,7 +4440,7 @@ void xspect_plot10(xspect *sp, int n) {
+ /* Given an emission spectrum, set the UV output to the given level. */
+ /* The shape of the UV is taken from FWA1_stim, and the level is */
+ /* with respect to the Y of the input spectrum. */
+-/* The output range is extended to accomodate the UV wavelengths */
++/* The output range is extended to accommodate the UV wavelengths */
+ void xsp_setUV(xspect *out, xspect *in, double uvlevel) {
+ int i, xs, xe;
+ double ww, avg;
+Index: trunk/spectro/ccxxmake.c
+===================================================================
+--- trunk.orig/spectro/ccxxmake.c
++++ trunk/spectro/ccxxmake.c
+@@ -395,7 +395,7 @@ int main(int argc, char *argv[]) {
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+- if (na == NULL) usage(0,"Paramater expected following -c");
++ if (na == NULL) usage(0,"Parameter expected following -c");
+ comno = atoi(na);
+ if (comno < 1 || comno > 40) usage(0,"-c parameter %d out of range",comno);
+
+@@ -495,7 +495,7 @@ int main(int argc, char *argv[]) {
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+- if (na == NULL) usage(0,"Paramater expected following -W");
++ if (na == NULL) usage(0,"Parameter expected following -W");
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+@@ -584,7 +584,7 @@ int main(int argc, char *argv[]) {
+ strcat(outname, doccss ? ".ccss" : ".ccmx");
+
+ if (fakeseq && doccss)
+- error("Fake CCSS test not implemeted");
++ error("Fake CCSS test not implemented");
+
+ printf("\n");
+
+Index: trunk/spectro/dispread.c
+===================================================================
+--- trunk.orig/spectro/dispread.c
++++ trunk/spectro/dispread.c
+@@ -413,7 +413,7 @@ int main(int argc, char *argv[]) {
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+- if (na == NULL) usage(0,"Paramater expected following -c");
++ if (na == NULL) usage(0,"Parameter expected following -c");
+ comport = atoi(na);
+ if (comport < 1 || comport > 50) usage(0,"-c parameter %d out of range",comport);
+
+Index: trunk/spectro/fakeread.c
+===================================================================
+--- trunk.orig/spectro/fakeread.c
++++ trunk/spectro/fakeread.c
+@@ -814,7 +814,7 @@ int main(int argc, char *argv[])
+
+ /* We're assuming that the input space has a perfect black point... */
+
+- /* Lookup the ouput black point in XYZ PCS. We're assuming monotonicity.. */
++ /* Lookup the output black point in XYZ PCS. We're assuming monotonicity.. */
+ bp[0] = bp[1] = bp[2] = 0.0;
+ oluo->lookup(oluo, bp, bp);
+
+@@ -827,7 +827,7 @@ int main(int argc, char *argv[])
+ bt1886 == 1 ? egamma : tgamma, bt1886 == 1 ? 1 : 0);
+
+ if (verb)
+- printf("Gamma Curve: Using ouput black offset proportion %f\n",outoprop);
++ printf("Gamma Curve: Using output black offset proportion %f\n",outoprop);
+
+ if (bt1886 == 1) { /* Using effective gamma */
+ if (verb)
+Index: trunk/profile/invprofcheck.c
+===================================================================
+--- trunk.orig/profile/invprofcheck.c
++++ trunk/profile/invprofcheck.c
+@@ -99,7 +99,7 @@ void usage(void) {
+ fprintf(stderr," -k Show CIEDE2000 delta E values\n");
+ fprintf(stderr," -w create %s visualisation (profile%s)\n",vrml_format(),vrml_ext());
+ fprintf(stderr," -x Use %s axes\n",vrml_format());
+- fprintf(stderr," -e Color vectors acording to delta E\n");
++ fprintf(stderr," -e Color vectors according to delta E\n");
+ fprintf(stderr," profile.icm Profile to check\n");
+ exit(1);
+ }
+Index: trunk/profile/profcheck.c
+===================================================================
+--- trunk.orig/profile/profcheck.c
++++ trunk/profile/profcheck.c
+@@ -59,7 +59,7 @@ usage(void) {
+ fprintf(stderr," -w create %s visualisation (iccprofile%s)\n",vrml_format(),vrml_ext());
+ fprintf(stderr," -x Use %s axes\n",vrml_format());
+ fprintf(stderr," -m Make %s lines a minimum of 0.5\n",vrml_format());
+- fprintf(stderr," -e Color vectors acording to delta E\n");
++ fprintf(stderr," -e Color vectors according to delta E\n");
+ fprintf(stderr," -h Plot a histogram of delta E's\n");
+ fprintf(stderr," -s Sort output by delta E\n");
+ fprintf(stderr," -P N.NN Create a pruned .ti3 with points less or equal to N.NN delta E\n");
+Index: trunk/spectro/ccwin.c
+===================================================================
+--- trunk.orig/spectro/ccwin.c
++++ trunk/spectro/ccwin.c
+@@ -827,7 +827,7 @@ int ddebug /* >0 to print debug sta
+ return NULL;
+ }
+
+- debugr2((errout,"new_ccwin: return sucessfully\n"));
++ debugr2((errout,"new_ccwin: return successfully\n"));
+
+ return p;
+ }
+Index: trunk/profile/colverify.c
+===================================================================
+--- trunk.orig/profile/colverify.c
++++ trunk/profile/colverify.c
+@@ -68,7 +68,7 @@ usage(void) {
+ fprintf(stderr," -D Use D50 100.0 as L*a*b* white reference\n");
+ fprintf(stderr," -c Show CIE94 delta E values\n");
+ fprintf(stderr," -k Show CIEDE2000 delta E values\n");
+- fprintf(stderr," -h [hist.txt] Plot a histogram of delta E's [Optionaly save points to .txt]\n");
++ fprintf(stderr," -h [hist.txt] Plot a histogram of delta E's [Optionally save points to .txt]\n");
+ fprintf(stderr," -s Sort patch values by error\n");
+ fprintf(stderr," -w create PCS %s vector visualisation (measured%s)\n",vrml_format(),vrml_ext());
+ fprintf(stderr," -W create PCS %s marker visualisation (measured%s)\n",vrml_format(),vrml_ext());
diff --git a/debian/patches/110_dispwin_segfault.patch b/debian/patches/110_dispwin_segfault.patch
new file mode 100644
index 0000000..2b1e684
--- /dev/null
+++ b/debian/patches/110_dispwin_segfault.patch
@@ -0,0 +1,20 @@
+Description: Add check for NULL pointer
+Author: Jörg Frings-Fürst <debian@jff-webhsoting.net>
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=700253
+Forwarded: http://www.freelists.org/post/argyllcms/dispwin-bad-command-line-option-makes-dispwin-segfault
+Reviewed-by:
+Last-Update: 2015-08-23
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: trunk/spectro/dispwin.c
+===================================================================
+--- trunk.orig/spectro/dispwin.c
++++ trunk/spectro/dispwin.c
+@@ -5553,6 +5553,7 @@ main(int argc, char *argv[]) {
+
+ /* Display number */
+ else if (argv[fa][1] == 'd') {
++ if(na == NULL) usage(0, "-d parameter missing");
+ if (strncmp(na,"web",3) == 0
+ || strncmp(na,"WEB",3) == 0) {
+ webdisp = 8080;
diff --git a/debian/patches/120_usb-db_new.patch b/debian/patches/120_usb-db_new.patch
new file mode 100644
index 0000000..f826509
--- /dev/null
+++ b/debian/patches/120_usb-db_new.patch
@@ -0,0 +1,19 @@
+Description: Use hwdb builtin, instead of the obsolete usb-db in the udev rules.
+Author: Dmitrijs Ledkovs <dmitrij.ledkov@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1200185
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=762887
+Last-Update: 2014-09-26
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: trunk/usb/55-Argyll.rules
+===================================================================
+--- trunk.orig/usb/55-Argyll.rules 2014-09-25 11:10:12.000000000 +0200
++++ trunk/usb/55-Argyll.rules 2014-09-26 14:08:21.067295380 +0200
+@@ -85,6 +85,6 @@
+ ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}!="*?", MODE="660", GROUP="plugdev"
+
+ # Set ID_VENDOR and ID_MODEL acording to VID and PID
+-TEST=="/lib/udev/usb-db", IMPORT{program}="usb-db %p"
++IMPORT{builtin}="hwdb --subsystem=usb"
+
+ LABEL="argyll_rules_end"
diff --git a/debian/patches/15_jam.patch b/debian/patches/15_jam.patch
new file mode 100644
index 0000000..251f61f
--- /dev/null
+++ b/debian/patches/15_jam.patch
@@ -0,0 +1,143 @@
+Description: Add multiarch support to jam files
+Author: Jörg Frings Fürst <debian@jff-webhosting.net>
+Forwarded: http://www.freelists.org/post/argyllcms/Some-buildsystem-issues
+Last-Update: 2015-08-23
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: trunk/Jambase
+===================================================================
+--- trunk.orig/Jambase
++++ trunk/Jambase
+@@ -941,7 +941,7 @@ else if $(UNIX)
+
+ # UNIX defaults
+
+- CCFLAGS ?= -DUNIX -D_THREAD_SAFE -pipe ;
++ CCFLAGS ?= $(CPPFLAGS) -g -DUNIX -D_THREAD_SAFE -pipe ;
+ CCOPTFLAG ?= -O2 ;
+ CCDEBUGFLAG ?= -g ;
+ CCPROFFLAG ?= ;
+@@ -951,7 +951,7 @@ else if $(UNIX)
+ CHGRP ?= chgrp ;
+ CHOWN ?= chown ;
+ LEX ?= lex ;
+- LINKFLAGS ?= ;
++ LINKFLAGS ?= $(LDFLAGS) ;
+ LINKOPTFLAG ?= -O ; # Affects creating .so's
+ LINKSTRIPFLAG ?= -s ;
+ LINKDEBUGFLAG ?= ;
+@@ -1037,7 +1037,7 @@ else if $(UNIX)
+ RMDIR ?= $(RM) ;
+ RSH ?= rsh ;
+ SED ?= sed ;
+- SHELLHEADER ?= "#!/bin/sh" ;
++ SHELLHEADER ?= "#!/bin/bash" ;
+ SHELLMODE ?= 755 ;
+ SLASH ?= / ;
+ STDHDRS ?= /usr/include ;
+Index: trunk/Jamtop
+===================================================================
+--- trunk.orig/Jamtop
++++ trunk/Jamtop
+@@ -23,6 +23,7 @@ ANCHORED_PATH_VARS = DESTDIR ;
+ # Should we also allow CFLAGS, CXXFLAGS, CPPFLAGS & LDFLAGS env. variables
+ # to have effect ?
+
++BUILD_SHARED_LIB = 1 ;
+
+ # Tell standalone libraries that they are part of Argyll:
+ DEFINES += ARGYLLCMS ;
+@@ -139,17 +140,82 @@ rule CheckForLibrary {
+ }
+
+ if ! $(BUILTIN_$(UCASE)) && $(UNIX) {
+- if [ GLOB /usr/include$(subd) : $(lcase).h $(lcase)lib.h ]
+- || [ GLOB /usr/local/include$(subd) : $(lcase).h $(lcase)lib.h ]
+- || [ GLOB /usr/include/x86_64-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
+- || [ GLOB /usr/include/i386-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ] {
+- if [ GLOB /usr/lib : lib$(lcase).so ] || [ GLOB /usr/lib : lib$(lcase).a ]
+- || [ GLOB /usr/local/lib : lib$(lcase).so ] || [ GLOB /usr/local/lib : lib$(lcase).a ]
+- || [ GLOB /usr/lib64 : lib$(lcase).so ] || [ GLOB /usr/lib64 : lib$(lcase).a ]
+- || [ GLOB /usr/lib/x86_64-linux-gnu : lib$(lcase).so ]
+- || [ GLOB /usr/lib/x86_64-linux-gnu : lib$(lcase).a ]
+- || [ GLOB /usr/lib/i386-linux-gnu : lib$(lcase).so ]
+- || [ GLOB /usr/lib/i386-linux-gnu : lib$(lcase).a ] {
++ if [ GLOB /usr/include$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/local/include$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/x86_64-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/i386-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/alpha-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/aarch64-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/arm-linux-gnueabi$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/arm-linux-gnueabihf$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/hppa-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/i386-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/x86_64-kfreebsd-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/i386-kfreebsd-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/m68k-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/mips-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/mipsel-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/mips64el-linux-gnuabi64$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/powerpc-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/powerpc-linux-gnuspe$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/powerpc64-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/powerpc64le-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/s390x-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/sh4-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/sparc-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/sparc64-linux-gnu$(subd) : $(lcase).h $(lcase)lib.h ]
++ || [ GLOB /usr/include/x86_64-linux-gnux32$(subd) : $(lcase).h $(lcase)lib.h ] {
++ if [ GLOB /usr/lib : lib$(lcase).so ] || [ GLOB /usr/lib : lib$(lcase).a ]
++ || [ GLOB /usr/local/lib : lib$(lcase).so ]
++ || [ GLOB /usr/local/lib : lib$(lcase).a ]
++ || [ GLOB /usr/lib64 : lib$(lcase).so ]
++ || [ GLOB /usr/lib64 : lib$(lcase).a ]
++ || [ GLOB /usr/lib/x86_64-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/x86_64-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/i386-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/i386-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/alpha-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/alpha-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/aarch64-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/aarch64-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/arm-linux-gnueabi : lib$(lcase).so ]
++ || [ GLOB /usr/lib/arm-linux-gnueabi : lib$(lcase).a ]
++ || [ GLOB /usr/lib/arm-linux-gnueabihf : lib$(lcase).so ]
++ || [ GLOB /usr/lib/arm-linux-gnueabihf : lib$(lcase).a ]
++ || [ GLOB /usr/lib/hppa-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/hppa-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/i386-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/i386-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/x86_64-kfreebsd-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/x86_64-kfreebsd-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/i386-kfreebsd-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/i386-kfreebsd-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/m68k-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/m68k-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/mips-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/mips-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/mipsel-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/mipsel-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/mips64el-linux-gnuabi64 : lib$(lcase).so ]
++ || [ GLOB /usr/lib/mips64el-linux-gnuabi64 : lib$(lcase).a ]
++ || [ GLOB /usr/lib/powerpc-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/powerpc-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/powerpc-linux-gnuspe : lib$(lcase).so ]
++ || [ GLOB /usr/lib/powerpc-linux-gnuspe : lib$(lcase).a ]
++ || [ GLOB /usr/lib/powerpc64-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/powerpc64-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/powerpc64le-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/powerpc64le-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/s390x-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/s390x-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/sh4-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/sh4-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/sparc-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/sparc-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/sparc64-linux-gnu : lib$(lcase).so ]
++ || [ GLOB /usr/lib/sparc64-linux-gnu : lib$(lcase).a ]
++ || [ GLOB /usr/lib/x86_64-linux-gnux32 : lib$(lcase).so ]
++ || [ GLOB /usr/lib/x86_64-linux-gnux32 : lib$(lcase).a ] {
+ echo "Using system $(UCASE) library" ;
+ $(UCASE)LIB = ;
+ $(UCASE)INC = ;
diff --git a/debian/patches/20_hurd_PATH_MAX.patch b/debian/patches/20_hurd_PATH_MAX.patch
new file mode 100644
index 0000000..0079adb
--- /dev/null
+++ b/debian/patches/20_hurd_PATH_MAX.patch
@@ -0,0 +1,81 @@
+Description: Add on hurdi386 missing PATH_MAX
+Author: Jörg Frings-Fürst <debian@jff-webhosting.net>
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=762774
+Last-Update: 2014-09-25
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: trunk/numlib/numsup.c
+===================================================================
+--- trunk.orig/numlib/numsup.c
++++ trunk/numlib/numsup.c
+@@ -40,6 +40,10 @@
+
+ /* Globals */
+
++#ifndef PATH_MAX
++#define PATH_MAX 4096
++#endif
++
+ char *exe_path = "\000"; /* Directory executable resides in ('/' dir separator) */
+ //char *error_program = "Unknown"; /* Name to report as responsible for an error */
+
+Index: trunk/spectro/mongoose.c
+===================================================================
+--- trunk.orig/spectro/mongoose.c
++++ trunk/spectro/mongoose.c
+@@ -46,6 +46,10 @@
+ added to /usr/lib/firewalld/services
+ */
+
++#ifndef PATH_MAX
++#define PATH_MAX 4096
++#endif
++
+ #if defined(_WIN32)
+ #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
+ #else
+Index: trunk/spectro/usbio_lx.c
+===================================================================
+--- trunk.orig/spectro/usbio_lx.c
++++ trunk/spectro/usbio_lx.c
+@@ -33,6 +33,10 @@
+ #define poll_x poll
+ #endif
+
++#ifndef PATH_MAX
++#define PATH_MAX 4096
++#endif
++
+ /* USB descriptors are little endian */
+
+ /* Take a word sized return buffer, and convert it to an unsigned int */
+Index: trunk/spectro/usbio_nt.c
+===================================================================
+--- trunk.orig/spectro/usbio_nt.c
++++ trunk/spectro/usbio_nt.c
+@@ -31,6 +31,10 @@
+ #define LIBUSBW1_PATH_MAX 512
+ #define LIBUSBW1_DEFAULT_TIMEOUT 5000
+
++#ifndef PATH_MAX
++#define PATH_MAX 4096
++#endif
++
+ /* USB descriptors are little endian */
+
+ /* Take a word sized return buffer, and convert it to an unsigned int */
+Index: trunk/spectro/hidio.c
+===================================================================
+--- trunk.orig/spectro/hidio.c
++++ trunk/spectro/hidio.c
+@@ -100,6 +100,10 @@
+ #endif
+ #endif
+
++#ifndef PATH_MAX
++#define PATH_MAX 4096
++#endif
++
+ #if defined(NT)
+
+ /* Declartions to enable HID access without using the DDK */
diff --git a/debian/patches/25_kfreebsd.patch b/debian/patches/25_kfreebsd.patch
new file mode 100644
index 0000000..2b4b622
--- /dev/null
+++ b/debian/patches/25_kfreebsd.patch
@@ -0,0 +1,55 @@
+From: Steven Chamberlain <steven@pyro.eu.org>
+Subject: use FreeBSD USB I/O code on GNU/kFreeBSD
+
+Use the FreeBSD USB I/O code not just on __FreeBSD__ itself,
+but on any system having __FreeBSD_kernel__ (such as GNU/kFreeBSD).
+
+--- a/spectro/usbio.c
++++ b/spectro/usbio.c
+@@ -94,7 +94,7 @@
+ # include "usbio_ox.c"
+ # endif
+ # if defined(UNIX_X11)
+-# if defined(__FreeBSD__)
++# if defined(__FreeBSD_kernel__)
+ # include "usbio_bsd.c"
+ # else
+ # include "usbio_lx.c"
+--- a/spectro/usbio_bsd.c
++++ b/spectro/usbio_bsd.c
+@@ -37,7 +37,7 @@
+ #include <fcntl.h>
+ #include <glob.h>
+ #include <sys/ioctl.h>
+-#if defined(__FreeBSD__)
++#if defined(__FreeBSD_kernel__)
+ # include <dev/usb/usb_ioctl.h> /* Not sure what's going on with FreeBSD... */
+ #else
+ # include <dev/usb/usb.h> /* The usual include for BSD */
+@@ -59,7 +59,7 @@
+ ) {
+ int i, j;
+ char *paths[] = {
+-#if defined(__FreeBSD__)
++#if defined(__FreeBSD_kernel__)
+ "/dev/usb/[0-9]*.*.0", /* FreeBSD >= 8 */
+ "/dev/ugen[0-9]*", /* FreeBSD < 8, but no .E */
+ #else
+@@ -94,7 +94,7 @@
+ /* For all the nodes found by the glob */
+ for (i = 0; i < g.gl_pathc; i++) {
+
+-#if defined(__FreeBSD__)
++#if defined(__FreeBSD_kernel__)
+ /* Skip anything with an end point number */
+ if (j == 1 && strchr(g.gl_pathv[i], '.') != NULL)
+ continue;
+@@ -141,7 +141,7 @@
+
+ /* Create the base device path */
+ dpath = g.gl_pathv[i];
+-#if defined(__FreeBSD__)
++#if defined(__FreeBSD_kernel__)
+ if (j == 0) { /* Remove .0 */
+ if ((cp = strrchr(dpath, '.')) != NULL
+ && cp[1] == '0' && cp[2] == '\000')
diff --git a/debian/patches/30_gcc5.patch b/debian/patches/30_gcc5.patch
new file mode 100644
index 0000000..2806745
--- /dev/null
+++ b/debian/patches/30_gcc5.patch
@@ -0,0 +1,20 @@
+Description: Fix FTBFS with GCC 5
+Author: James Cowgill <james410@cowgill.org.uk>
+Bug-Debian: https://bugs.debian.org/777779
+Forwarded: no
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/icc/icc.h
++++ b/icc/icc.h
+@@ -100,7 +100,11 @@
+ #define CF64PREC "LL" /* Constant precision specifier */
+
+ #ifndef ATTRIBUTE_NORETURN
++#ifdef _MSC_VER
+ # define ATTRIBUTE_NORETURN __declspec(noreturn)
++#else
++# define ATTRIBUTE_NORETURN __attribute__((noreturn))
++#endif
+ #endif
+
+ #else /* !__STDC_VERSION__ */
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..8f5d038
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,7 @@
+110_dispwin_segfault.patch
+100_spelling.patch
+15_jam.patch
+20_hurd_PATH_MAX.patch
+#120_usb-db_new.patch
+#25_kfreebsd.patch
+30_gcc5.patch
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..50d805e
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,122 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+export DH_OPTIONS
+
+NO_PROC=$(shell cat /proc/cpuinfo | grep processor | wc -l)
+
+JAMCMDLINE = -q -fJambase -j$(NO_PROC) -sPREFIX=/usr -sDESTDIR=$(CURDIR)/debian/tmp -sREFSUBDIR=share/color/argyll/ref
+CHDATE=$(shell dpkg-parsechangelog -S Date)
+CRDATE=$(shell date --utc -d "$(CHDATE)" "+%a %b %d %T %Y")
+
+#
+# Test for gcc-5 support
+#
+#export CC=gcc-5
+#export CXX=g++-5
+
+
+%:
+ dh $@
+
+override_dh_auto_build:
+ gcc --version
+ jam $(JAMCMDLINE) all
+
+override_dh_auto_install:
+ jam $(JAMCMDLINE) dirs
+ jam $(JAMCMDLINE) install
+ rm $(CURDIR)/debian/tmp/usr/bin/License.txt
+ #
+ # Make build results reproducible.
+ #
+ sed -i 's/CREATED.*/CREATED $(CRDATE)/' $(CURDIR)/debian/tmp/usr/share/color/argyll/ref/RefMediumGamut.gam
+ sed -i 's/CREATED.*/CREATED $(CRDATE)/' $(CURDIR)/debian/tmp/usr/share/color/argyll/ref/linear.cal
+ sed -i 's/CREATED.*/CREATED $(CRDATE)/' $(CURDIR)/debian/tmp/usr/share/color/argyll/ref/strange.cal
+
+override_dh_installdocs:
+ dh_installdocs
+ rm -f $(CURDIR)/debian/argyll-doc/usr/share/doc/argyll-doc/License.txt
+ rm -f $(CURDIR)/debian/argyll-doc/usr/share/doc/argyll-doc/License2.txt
+ rm -f $(CURDIR)/debian/argyll-doc/usr/share/doc/argyll-doc/License3.txt
+ rm -f $(CURDIR)/debian/argyll-doc/usr/share/doc/argyll-doc/DocLicense.txt
+ rm -f $(CURDIR)/debian/argyll-doc/usr/share/doc/argyll-doc/afiles
+
+override_dh_installchangelogs:
+ dh_installchangelogs log.txt
+
+override_dh_strip:
+ dh_strip --dbg-package=argyll-dbg
+
+override_dh_builddeb:
+ dh_builddeb
+
+override_dh_compress:
+ dh_compress -X.html
+
+build-manpages:
+ help2man -N --no-discard-stderr --name="Apply device calibration to an ICC profile." debian/tmp/usr/bin/applycal > debian/man/applycal.1
+ help2man -N --no-discard-stderr --name="Dump an ICC file in human readable form." debian/tmp/usr/bin/iccdump > debian/man/iccdump.1
+ help2man -N --no-discard-stderr --name="Translate colors through an ICC profile." debian/tmp/usr/bin/icclu > debian/man/icclu.1
+ help2man -N --no-discard-stderr --name="Average or merge values in .ti3 like files." debian/tmp/usr/bin/average > debian/man/average.1
+ help2man -N --no-discard-stderr --name="Convert Colorblind raw device profile data to Argyll data." debian/tmp/usr/bin/cb2ti3 > debian/man/cb2ti3.1
+ help2man -N --no-discard-stderr --name="Color Correct a TIFF file using any sequence of ICC profiles or Calibrations." debian/tmp/usr/bin/cctiff > debian/man/cctiff.1
+ help2man -N --no-discard-stderr --name="Create CCMX or CCSS." debian/tmp/usr/bin/ccxxmake > debian/man/ccxxmake.1
+ help2man -N --no-discard-stderr --name="Read Target Test Chart." debian/tmp/usr/bin/chartread > debian/man/chartread.1
+ help2man -N --no-discard-stderr --name="Link ICC profiles." debian/tmp/usr/bin/collink > debian/man/collink.1
+ help2man -N --no-discard-stderr --name="Create ICC profile." debian/tmp/usr/bin/colprof > debian/man/colprof.1
+ help2man -N --no-discard-stderr --name="Verify CIE values." debian/tmp/usr/bin/colverify > debian/man/colverify.1
+ help2man -N --no-discard-stderr --name="Calibrate a Display." debian/tmp/usr/bin/dispcal > debian/man/dispcal.1
+ help2man -N --no-discard-stderr --name="Read a Display." debian/tmp/usr/bin/dispread > debian/man/dispread.1
+ help2man -N --no-discard-stderr --name="Test display patch window, Set Video LUTs, Install profiles." debian/tmp/usr/bin/dispwin > debian/man/dispwin.1
+ help2man -N --no-discard-stderr --name="Extract an ICC profile from a TIFF file." debian/tmp/usr/bin/extracticc > debian/man/extracticc.1
+ help2man -N --no-discard-stderr --name="Extract a text tag from an ICC profile." debian/tmp/usr/bin/extractttag > debian/man/extractttag.1
+ help2man -N --no-discard-stderr --name="Create a fake CMY data file from a CMYK profile." debian/tmp/usr/bin/fakeCMY > debian/man/fakeCMY.1
+ help2man -N --no-discard-stderr --name="Fake test chart reader - lookup values in ICC/MPP profile." debian/tmp/usr/bin/fakeread > debian/man/fakeread.1
+ help2man -N --no-discard-stderr --name="Convert a TIFF file to monochrome using an ICC device profile." debian/tmp/usr/bin/greytiff > debian/man/greytiff.1
+ help2man -N --no-discard-stderr --name="Dump an ICC file in human readable form." debian/tmp/usr/bin/iccdump > debian/man/iccdump.1
+ help2man -N --no-discard-stderr --name="Create Lab/Jab gamut plot." debian/tmp/usr/bin/iccgamut > debian/man/iccgamut.1
+ help2man -N --no-discard-stderr --name="Measure an illuminant." debian/tmp/usr/bin/illumread > debian/man/illumread.1
+ help2man -N --no-discard-stderr --name="Check fwd to bwd relative transfer of an ICC file." debian/tmp/usr/bin/invprofcheck > debian/man/invprofcheck.1
+ help2man -N --no-discard-stderr --name="Convert Kodak raw printer profile data to Argyll print data." debian/tmp/usr/bin/kodak2ti3 > debian/man/kodak2ti3.1
+ help2man -N --no-discard-stderr --name="Check Model Printer Profile." debian/tmp/usr/bin/mppcheck > debian/man/mppcheck.1
+ help2man -N --no-discard-stderr --name="Translate colors through an MPP profile." debian/tmp/usr/bin/mpplu > debian/man/mpplu.1
+ help2man -N --no-discard-stderr --name="Create Model Printer Profile." debian/tmp/usr/bin/mppprof > debian/man/mppprof.1
+ help2man -N --no-discard-stderr --name="List information about the FILEs." debian/tmp/usr/bin/oeminst > debian/man/oeminst.1
+ help2man -N --no-discard-stderr --name="Create printer calibration." debian/tmp/usr/bin/printcal > debian/man/printcal.1
+ help2man -N --no-discard-stderr --name="Generate Target PostScrip file." debian/tmp/usr/bin/printtarg > debian/man/printtarg.1
+ help2man -N --no-discard-stderr --name="Check accuracy of ICC profile." debian/tmp/usr/bin/profcheck > debian/man/profcheck.1
+ help2man -N --no-discard-stderr --name="Create abstract correction profile given table of absolute CIE correction values." debian/tmp/usr/bin/refine > debian/man/refine.1
+ help2man -N --no-discard-stderr --name="Invert AtoB1 to make BtoA1 for CMYK profiles." debian/tmp/usr/bin/revfix > debian/man/revfix.1
+ help2man -N --no-discard-stderr --name="Scanin." debian/tmp/usr/bin/scanin > debian/man/scanin.1
+ help2man -N --no-discard-stderr --name="Convert spectral .ti3 file." debian/tmp/usr/bin/spec2cie > debian/man/spec2cie.1
+ help2man -N --no-discard-stderr --name="Plot spectrum and calculate CCT and VCT." debian/tmp/usr/bin/specplot > debian/man/specplot.1
+ help2man -N --no-discard-stderr --name="Split a .ti3 into two." debian/tmp/usr/bin/splitti3 > debian/man/splitti3.1
+ help2man -N --no-discard-stderr --name="Read Print Spot values." debian/tmp/usr/bin/spotread > debian/man/spotread.1
+ help2man -N --no-discard-stderr --name="Create a synthetic calibration file." debian/tmp/usr/bin/synthcal > debian/man/synthcal.1
+ help2man -N --no-discard-stderr --name="Synthetic device model test chart reader." debian/tmp/usr/bin/synthread > debian/man/synthread.1
+ help2man -N --no-discard-stderr --name="Generate Target deviceb test chart color values." debian/tmp/usr/bin/targen > debian/man/targen.1
+ help2man -N --no-discard-stderr --name="Create VRML image of the gamut surface of a TIFF." debian/tmp/usr/bin/tiffgamut > debian/man/tiffgamut.1
+ help2man -N --no-discard-stderr --name="Create test images, default hex RGB surface and wedge." debian/tmp/usr/bin/timage > debian/man/timage.1
+ help2man -N --no-discard-stderr --name="Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data." debian/tmp/usr/bin/txt2ti3 > debian/man/txt2ti3.1
+ help2man -N --no-discard-stderr --name="View gamuts." debian/tmp/usr/bin/viewgam > debian/man/viewgam.1
+ help2man -N --no-discard-stderr --name="Translate colors through an xicc." debian/tmp/usr/bin/xicclu > debian/man/xicclu.1
+ help2man -N --no-discard-stderr --name="Convert LightSpace raw RGB device profile data to Argyll CGATS dat" debian/tmp/usr/bin/ls2ti3 > debian/man/ls2ti3.1
+
+VERSION = $(shell head -n1 debian/changelog | sed -e 's/.*(//;s/+.*).*//;s/\+/\-/')
+
+get-orig-source:
+ wget http://www.argyllcms.com/Argyll_V${VERSION}_src.zip -O ../Argyll_V${VERSION}_src.zip
+ unzip ../Argyll_V${VERSION}_src.zip -d ../
+ mv ../Argyll_V${VERSION} ../argyll_${VERSION}
+ rm -f ../argyll_${VERSION}/yajl/yajl_test.exe ../argyll_${VERSION}/yajl/yajl_test.obj
+ rm -fr ../argyll_${VERSION}/usb/bin
+ rm -fr ../argyll_${VERSION}/jpeg
+ rm -fr ../argyll_${VERSION}/tiff
+ rm -fr ../argyll_${VERSION}/zlib
+ rm -fr ../argyll_${VERSION}/png
+ chmod -R -x+X ../argyll_${VERSION}/*
+ tar cJf ../argyll_${VERSION}+repack.orig.tar.xz ../argyll_${VERSION}
+ rm -fr ../argyll_${VERSION} ../Argyll_V${VERSION}_src.zip
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/tools/buildman.sh b/debian/tools/buildman.sh
new file mode 100644
index 0000000..fee4393
--- /dev/null
+++ b/debian/tools/buildman.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+cd ../../
+
+quilt push -a
+
+debian/rules override_dh_auto_build
+debian/rules override_dh_auto_install
+debian/rules build-manpages
+debian/rules override_dh_auto_clean
+
+quilt pop -a
+
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..fddab5e
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,5 @@
+version=3
+
+#opts="dversionmangle=s/\+repack\d+$//" http://www.argyllcms.com/downloadsrc.html Argyll_V(.*)_src\.zip
+opts=dversionmangle=s/\+repack(.*)// \
+http://www.argyllcms.com/downloadsrc.html Argyll_V(.*)_src\.zip
diff --git a/doc/ArgyllDoc.html b/doc/ArgyllDoc.html
index a2b2ed5..6dda431 100644
--- a/doc/ArgyllDoc.html
+++ b/doc/ArgyllDoc.html
@@ -1,63 +1,63 @@
-<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- <meta name="description" content="Root of Argyll CMS documentation">
- <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
- [Netscape]">
- <title>Argyll Documentation Top</title>
- </head>
- <body>
- <h1> Argyll CMS documentation index (V1.8.3)<br>
- </h1>
- Date:&nbsp;&nbsp; 26th October 2015<br>
- Author: Graeme Gill
- <h2><u><a name="Intro"></a>Introduction</u></h2>
- ArgyllCMS is an ICC compatible color management system, available as
- Open Source. It supports accurate ICC profile creation for scanners,
- cameras and film recorders, and calibration and profiling of
- displays and RGB &amp; CMYK printers. Device Link can be created
- with a wide variety of advanced options, including specialized Video
- calibration standards&nbsp; and 3dLuts. Spectral sample data is
- supported, allowing a selection of illuminants observer types, and
- paper fluorescent whitener additive compensation. Profiles can also
- incorporate source specific gamut mappings for perceptual and
- saturation intents. Gamut mapping and profile linking uses the
- CIECAM02 appearance model, a unique gamut mapping algorithm, and a
- wide selection of rendering intents. It also includes code for the
- fastest portable 8 bit raster color conversion engine available
- anywhere, as well as support for fast, fully accurate 16 bit
- conversion. Device color gamuts can also be viewed and compared with
- a modern Web browser using X3DOM . Comprehensive documentation is
- provided for each major tool, and a general guide to using the tools
- for typical color management tasks is also available. A mailing list
- provides support for more advanced usage.<br>
- <p>This is Version 1.8.3, a bug fix update to V1.8.2. The first
- public release of icclib was in November 1998, and of Argyll was
- in October 2000. Code development commenced in 1995. See <a
- href="ChangesSummary.html">Changes Summary</a> for an overview
- of changes since the last release. Changes between revisions is
- detailed in the <b>log.txt</b> file that accompanies the source
- code. </p>
- <p>The latest source code is available from <a
- href="http://www.argyllcms.com/">here</a>.<br>
- </p>
- <p><font color="#cc0000"><span style="font-weight: bold;">Please
- note that instruments are being driven by ArgyllCMS drivers,
- and that any problems or queries regarding instrument<br>
- operation </span><span style="font-weight: bold;">should
- first be directed to the Argyll's author(s) or the Argyll
- mailing list, and not to any</span> <span style="font-weight:
- bold;">other party.</span></font> </p>
- <p> </p>
- <h2><a href="ColorManagement.html">An Introduction to Color
- Management</a></h2>
- <p>A great introduction for non technical people is Steve Upton's <a
- href="http://www.colorwiki.com/wiki/The_Color_of_Toast">The
- Color of Toast</a>.<br>
- </p>
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ <meta name="description" content="Root of Argyll CMS documentation">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Documentation Top</title>
+ </head>
+ <body>
+ <h1> Argyll CMS documentation index (V1.8.2)<br>
+ </h1>
+ Date:&nbsp;&nbsp; 7th September 2015<br>
+ Author: Graeme Gill
+ <h2><u><a name="Intro"></a>Introduction</u></h2>
+ ArgyllCMS is an ICC compatible color management system, available as
+ Open Source. It supports accurate ICC profile creation for scanners,
+ cameras and film recorders, and calibration and profiling of
+ displays and RGB &amp; CMYK printers. Device Link can be created
+ with a wide variety of advanced options, including specialized Video
+ calibration standards&nbsp; and 3dLuts. Spectral sample data is
+ supported, allowing a selection of illuminants observer types, and
+ paper fluorescent whitener additive compensation. Profiles can also
+ incorporate source specific gamut mappings for perceptual and
+ saturation intents. Gamut mapping and profile linking uses the
+ CIECAM02 appearance model, a unique gamut mapping algorithm, and a
+ wide selection of rendering intents. It also includes code for the
+ fastest portable 8 bit raster color conversion engine available
+ anywhere, as well as support for fast, fully accurate 16 bit
+ conversion. Device color gamuts can also be viewed and compared with
+ a modern Web browser using X3DOM . Comprehensive documentation is
+ provided for each major tool, and a general guide to using the tools
+ for typical color management tasks is also available. A mailing list
+ provides support for more advanced usage.<br>
+ <p>This is Version 1.8.2, a bug fix update to V1.8.1. The first
+ public release of icclib was in November 1998, and of Argyll was
+ in October 2000. Code development commenced in 1995. See <a
+ href="ChangesSummary.html">Changes Summary</a> for an overview
+ of changes since the last release. Changes between revisions is
+ detailed in the <b>log.txt</b> file that accompanies the source
+ code. </p>
+ <p>The latest source code is available from <a
+ href="http://www.argyllcms.com/">here</a>.<br>
+ </p>
+ <p><font color="#cc0000"><span style="font-weight: bold;">Please
+ note that instruments are being driven by ArgyllCMS drivers,
+ and that any problems or queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should
+ first be directed to the Argyll's author(s) or the Argyll
+ mailing list, and not to any</span> <span style="font-weight:
+ bold;">other party.</span></font> </p>
+ <p> </p>
+ <h2><a href="ColorManagement.html">An Introduction to Color
+ Management</a></h2>
+ <p>A great introduction for non technical people is Steve Upton's <a
+ href="http://www.colorwiki.com/wiki/The_Color_of_Toast">The
+ Color of Toast</a>.<br>
+ </p>
I present here a more technical but <a href="ColorManagement.html">concise
@@ -106,54 +106,52 @@
-
-
-
- discussion</a> of what color management is, and why we need it,
- together with a brief overview of the ICC profile format.<br>
- <br>
- <h2 style="text-decoration: underline;">Operating Environments</h2>
- <h2> </h2>
- <p>Argyll is known to compile and run in at least the following
- environments: </p>
- 1) MSWindows XP system using Microsoft VC++ 6.0 compiler<br>
- 2) MSWindows XP system using Microsoft VC++ 8.0 Express compiler +
- Platform SDK Feb. 2003<br>
- 3) MSWindows XP system using Microsoft VC++ 9.0 Express compiler +
- Platform SDK Feb. 2003<br>
- 4) MSWindows XP system using Microsoft VC++ 10.0 Express compiler +
- Platform SDK Feb. 2003<br>
- 5) MSWindows XP system using Microsoft VC++ 11.0 Express compiler<br>
- 6) MSWindows XP system using the MingW port of the GCC compiler<br>
- 7) Linux on Fedora Core 8, 32 bit using gcc <br>
- 8) Linux on Fedora Core 8, 64 bit using gcc<br>
- 9) Apple OS X 10.3 PPC using GCC<br>
- 10) Apple OS X 10.4, 10.5, 10.6 Intel using GCC<br>
- 11) Apple OS X10.7 Intel using&nbsp; Clang<br>
- <br>
- Additionally it is also known to run on:<br>
- <br>
- &nbsp;MSWindows 2000, Vista &amp; Windows 7 32 bit.<br>
- &nbsp;MSWindows Vista 64bit, Windows 7, 8, 8.1 64 bit.<br>
- &nbsp;Linux Ubuntu 7.10<br>
- &nbsp;Linux Kubuntu 7.10<br>
- &nbsp;Linux Mandriva 2008.0<br>
- &nbsp;Linux OpenSuSE 10.3<br>
- &nbsp;Linux Whitebox 4.2/2<br>
- <p>but may well compile and run correctly in many more than this,
- including OS X 10.8, 10.9 and 10.10 &amp; MSWin 10. </p>
- This is a <span style="font-weight: bold;">command line terminal</span>
- only environment. Those unfamiliar with command line environments
- should consult an appropriate tutorial for their environment if they
- are interested in using this software. See the listing of <a
- href="#cltutes">tutorials</a> below.<span style="font-weight:
- bold;"></span><br>
- <br>
- The following color measuring instruments are directly supported:<br>
- <br>
- JETI:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#specbos">specbos 1211
+
+ discussion</a> of what color management is, and why we need it,
+ together with a brief overview of the ICC profile format.<br>
+ <br>
+ <h2 style="text-decoration: underline;">Operating Environments</h2>
+ <h2> </h2>
+ <p>Argyll is known to compile and run in at least the following
+ environments: </p>
+ 1) MSWindows XP system using Microsoft VC++ 6.0 compiler<br>
+ 2) MSWindows XP system using Microsoft VC++ 8.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 3) MSWindows XP system using Microsoft VC++ 9.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 4) MSWindows XP system using Microsoft VC++ 10.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 5) MSWindows XP system using Microsoft VC++ 11.0 Express compiler<br>
+ 6) MSWindows XP system using the MingW port of the GCC compiler<br>
+ 7) Linux on Fedora Core 8, 32 bit using gcc <br>
+ 8) Linux on Fedora Core 8, 64 bit using gcc<br>
+ 9) Apple OS X 10.3 PPC using GCC<br>
+ 10) Apple OS X 10.4, 10.5, 10.6 Intel using GCC<br>
+ 11) Apple OS X10.7 Intel using&nbsp; Clang<br>
+ <br>
+ Additionally it is also known to run on:<br>
+ <br>
+ &nbsp;MSWindows 2000, Vista &amp; Windows 7 32 bit.<br>
+ &nbsp;MSWindows Vista 64bit, Windows 7, 8, 8.1 64 bit.<br>
+ &nbsp;Linux Ubuntu 7.10<br>
+ &nbsp;Linux Kubuntu 7.10<br>
+ &nbsp;Linux Mandriva 2008.0<br>
+ &nbsp;Linux OpenSuSE 10.3<br>
+ &nbsp;Linux Whitebox 4.2/2<br>
+ <p>but may well compile and run correctly in many more than this,
+ including OS X 10.8, 10.8 and 10.10. </p>
+ This is a <span style="font-weight: bold;">command line terminal</span>
+ only environment. Those unfamiliar with command line environments
+ should consult an appropriate tutorial for their environment if they
+ are interested in using this software. See the listing of <a
+ href="#cltutes">tutorials</a> below.<span style="font-weight:
+ bold;"></span><br>
+ <br>
+ The following color measuring instruments are directly supported:<br>
+ <br>
+ JETI:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#specbos">specbos 1211
&amp; 1201</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -207,13 +205,11 @@
-
-
-
- - Tele-Spectro-Radiometer<br>
- <br>
- Image Engineering:<br>
- <br>
+
+ - Tele-Spectro-Radiometer<br>
+ <br>
+ Image Engineering:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#ex1">EX1</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -267,13 +263,11 @@
-
-
-
- - Tele-Spectro-Radiometer<br>
- <br>
- Klein:<br>
- <br>
+
+ - Tele-Spectro-Radiometer<br>
+ <br>
+ Klein:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#k10a">K10-A</a>&nbsp;&nbsp;
@@ -304,16 +298,14 @@
-
-
-
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
- the K-1, K-8 and&nbsp; K-10.<br>
- <br>
- X-Rite:<br>
+
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
+ the K-1, K-8 and&nbsp; K-10.<br>
+ <br>
+ X-Rite:<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP20">DTP20 "Pulse"</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -409,11 +401,9 @@
-
-
-
- - "swipe" type reflective spectrometer, that can be used untethered.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP22">DTP22 Digital
+
+ - "swipe" type reflective spectrometer, that can be used untethered.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP22">DTP22 Digital
Swatchbook</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -508,10 +498,8 @@
-
-
-
- - spot type reflective spectrometer.<br>
+
+ - spot type reflective spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -606,12 +594,10 @@
-
-
-
- - spot and strip reading reflective spectrometer.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41T</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+
+ - spot and strip reading reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41T</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -706,10 +692,8 @@
-
-
-
- - spot and strip reading reflective/transmissive spectrometer.<br>
+
+ - spot and strip reading reflective/transmissive spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#dtp51">DTP51</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -804,10 +788,8 @@
-
-
-
- - strip reading reflective colorimeter.<br>
+
+ - strip reading reflective colorimeter.<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP92">DTP92</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -902,71 +884,69 @@
-
-
-
- - CRT display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP94">DTP94</a> <font
- size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro"- display
- colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorMunki"><span
- style="text-decoration: underline;">ColorMunki</span></a> Design
- or Photo&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
- spot and "swipe" reflective/emissive spectrometer (UV cut only).<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d"><span
- style="text-decoration: underline;">ColorMunki</span></a> Create
- or Smile&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter. (Similar to an Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Lenovo W</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -
- built in laptop Huey display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d3">Eye-One Display
- 3</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - Xrite i1 DisplayPro and ColorMunki
- Display <br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
- i1Display Pro, NEC SpectraSensor Pro,<br>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
- DreamColor&nbsp; i1d3 are also reported to work.]<br>
- &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
- "swipe" reflective/emissive spectrometer.<br>
- <br>
- Gretag-Macbeth (now X-Rite):<br>
- &nbsp; &nbsp; <a href="instruments.html#sl">Spectrolino</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
- reflective/emissive spectrometer.<br>
- &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScan</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
- reflective/emissive, XY table reflective spectrometer&nbsp; .<br>
- &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScanT</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
- reflective/emissive/transmissive, XY table reflective spectrometer.<br>
- &nbsp; &nbsp; <a href="instruments.html#i1p">Eye-One Pro</a> "EFI
- ES-1000" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe"
- reflective/emissive spectrometer.<br>
- &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive
- spectrometer.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">Eye-One Display 1
- or 2&nbsp; or LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
- display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
- APS</a>&nbsp;
+
+ - CRT display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP94">DTP94</a> <font
+ size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro"- display
+ colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorMunki"><span
+ style="text-decoration: underline;">ColorMunki</span></a> Design
+ or Photo&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
+ spot and "swipe" reflective/emissive spectrometer (UV cut only).<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d"><span
+ style="text-decoration: underline;">ColorMunki</span></a> Create
+ or Smile&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter. (Similar to an Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Lenovo W</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -
+ built in laptop Huey display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d3">Eye-One Display
+ 3</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - Xrite i1 DisplayPro and ColorMunki
+ Display <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
+ i1Display Pro, NEC SpectraSensor Pro,<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
+ DreamColor&nbsp; i1d3 are also reported to work.]<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
+ "swipe" reflective/emissive spectrometer.<br>
+ <br>
+ Gretag-Macbeth (now X-Rite):<br>
+ &nbsp; &nbsp; <a href="instruments.html#sl">Spectrolino</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScan</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive, XY table reflective spectrometer&nbsp; .<br>
+ &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScanT</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive/transmissive, XY table reflective spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p">Eye-One Pro</a> "EFI
+ ES-1000" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe"
+ reflective/emissive spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive
+ spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">Eye-One Display 1
+ or 2&nbsp; or LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
+ display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
+ APS</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1061,11 +1041,9 @@
-
-
-
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">CalMAN X2</a>
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">CalMAN X2</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1160,20 +1138,18 @@
-
-
-
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Huey</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
- <br>
- Sequel imaging (Now X-Rite):<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#mox">MonacoOPTIX</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter (Treated as an Eye-One Display 1)<br>
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Huey</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ <br>
+ Sequel imaging (Now X-Rite):<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#mox">MonacoOPTIX</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter (Treated as an Eye-One Display 1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1268,12 +1244,10 @@
-
-
-
- [The Sequel Chroma 4 may also work.]<br>
- <br>
- Lacie Blue
+
+ [The Sequel Chroma 4 may also work.]<br>
+ <br>
+ Lacie Blue
Eye:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1368,17 +1342,15 @@
-
-
-
- - see <a href="instruments.html#i1d">Eye-One Display</a><br>
- <br>
- DataColor ColorVision:<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd2">Spyder 2</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> firmware)<br>
+
+ - see <a href="instruments.html#i1d">Eye-One Display</a><br>
+ <br>
+ DataColor ColorVision:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd2">Spyder 2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> firmware)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1473,30 +1445,28 @@
-
-
-
- [The Spyder 1 has also been reported as working, but this has not
- been confirmed.]<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd3">Spyder 3</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd4">Spyder 4</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd5">Spyder 5</a>
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- <br>
- Other:<br>
- &nbsp;&nbsp;&nbsp; <span class="titre"><a
+
+ [The Spyder 1 has also been reported as working, but this has not
+ been confirmed.]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd3">Spyder 3</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd4">Spyder 4</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd5">Spyder 5</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ <br>
+ Other:<br>
+ &nbsp;&nbsp;&nbsp; <span class="titre"><a
href="instruments.html#HCFR">Colorimètre HCFR</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1591,10 +1561,8 @@
-
-
-
- - display colorimeter</span><br>
+
+ - display colorimeter</span><br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorHug">ColorHug</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1674,57 +1642,53 @@
-
-
-
- - display colorimeter<br>
+
+ - display colorimeter<br>
&nbsp;&nbsp;&nbsp; <a href="instruments.html#SMCube">Palette/SwatchMate
-
-
-
- Cube</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
- reflective colorimeter<br>
- <span style="font-weight: bold;"></span><span class="titre"><br>
- See </span><a href="instruments.html">Operation of particular
- instruments</a> for more instrument specific detail.<br>
- <br>
- Other instruments can be supported indirectly, since patch result
- files created by other packages can be imported into Argyll.<br>
- <br>
- Please <span style="font-weight: bold;">note</span> the <big><b><a
- href="Installing.html">installation instructions</a></b></big>
- for each platform - they contain important information for getting
- your instruments working.<br>
- <p>If you've decided to buy a color instrument because Argyll
- supports it, please let the dealer and manufacturer know that "<span
- style="font-weight: bold;">You bought it because Argyll CMS
- supports it</span>" - thanks.<br>
- </p>
- <p><span style="font-weight: bold;">Please note that instruments are
- being driven by ArgyllCMS drivers, and that any problems or
- queries regarding instrument<br>
- operation </span><span style="font-weight: bold;">should be
- directed to the Argyll's author(s) or the Argyll mailing list,
- and not to any</span> <span style="font-weight: bold;">other
- party.</span> </p>
- <p>There is a <a href="ccmxs.html">list of contributed</a> <span
- style="font-weight: bold;">ccmx</span> (Colorimeter Correction
- Matrix) files for some display/colorimeter combinations.</p>
- <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
- name="Copyright"></a>Copyright, Licensing &amp; Trade Mark:</span><br>
- </h2>
- <p>Most of the source code and provided executable files are
- copyrighted works, licensed under the <span style="font-weight:
- bold;">Affero GNU Version 3 license</span>, and therefore they
- (or works derived from them) can't be copied, sold or made
- available to users interacting with them remotely through a
- computer network, without providing the source code. Nothing other
- than your agreement and compliance with the Affero GNU License
- grants you permission to use, modify or distribute ArgyllCMS
- source code, executables or its derivative works. You could be
- sued for copyright infringement if you use or distribute ArgyllCMS
+
+ Cube</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
+ reflective colorimeter<br>
+ <span style="font-weight: bold;"></span><span class="titre"><br>
+ See </span><a href="instruments.html">Operation of particular
+ instruments</a> for more instrument specific detail.<br>
+ <br>
+ Other instruments can be supported indirectly, since patch result
+ files created by other packages can be imported into Argyll.<br>
+ <br>
+ Please <span style="font-weight: bold;">note</span> the <big><b><a
+ href="Installing.html">installation instructions</a></b></big>
+ for each platform - they contain important information for getting
+ your instruments working.<br>
+ <p>If you've decided to buy a color instrument because Argyll
+ supports it, please let the dealer and manufacturer know that "<span
+ style="font-weight: bold;">You bought it because Argyll CMS
+ supports it</span>" - thanks.<br>
+ </p>
+ <p><span style="font-weight: bold;">Please note that instruments are
+ being driven by ArgyllCMS drivers, and that any problems or
+ queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should be
+ directed to the Argyll's author(s) or the Argyll mailing list,
+ and not to any</span> <span style="font-weight: bold;">other
+ party.</span> </p>
+ <p>There is a <a href="ccmxs.html">list of contributed</a> <span
+ style="font-weight: bold;">ccmx</span> (Colorimeter Correction
+ Matrix) files for some display/colorimeter combinations.</p>
+ <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
+ name="Copyright"></a>Copyright and Licensing:</span><br>
+ </h2>
+ <p>Most of the source code and provided executable files are
+ copyrighted works, licensed under the <span style="font-weight:
+ bold;">Affero GNU Version 3 license</span>, and therefore they
+ (or works derived from them) can't be copied, sold or made
+ available to users interacting with them remotely through a
+ computer network, without providing the source code. Nothing other
+ than your agreement and compliance with the Affero GNU License
+ grants you permission to use, modify or distribute ArgyllCMS
+ source code, executables or its derivative works. You could be
+ sued for copyright infringement if you use or distribute ArgyllCMS
without a valid license. The <span style="font-weight: bold;">Affero
@@ -1746,64 +1710,62 @@
-
-
-
- GNU</span> license <span style="font-weight: bold;">prohibits</span>
- extending these tools<span style="font-weight: bold;"></span>
- (i.e. by combining them with other programs or scripts that make
- use of, depend on, or work with the ArgyllCMS code) and
- distributing them, unless all the elements of the extensions are
- also made available under a GPL compatible license. It is
- permissible to provide ArgyllCMS tools with other non GPL
- components if the elements of the package are not related, such
- that the packaging is mere aggregation. For all the gory details,
- please read the accompanying <a href="License.txt">license</a>. </p>
- Note that unlike many commercial ICC profiling tools, the profiles
- created using ArgyllCMS, are not subject to any claims or
- restrictions of ArgyllCMS's author(s), but are assumed to be the
- copyright property of the person who gathers the characterization
- data, and causes the profiles to be created.
- <p>The ArgyllCMS is Copyright 1995 - 2015 Graeme W. Gill, and is
- made available under the terms of the Affero GNU General Public
- License Version 3, as detailed in the <a href="License.txt">License.txt</a>
- file. Documentation is licensed under the terms of the GNU Free
- Documentation License, Version 1.3. The author asserts his moral
- rights over this material in relationship to the attribution and
- integrity of these works. In particular, if these works are
- modified in a way that materially changes their functionality,
- then the modified works should be renamed in a way that clearly
- distinguishes them from "Argyll" or "ArgyllCMS" so that the
- effects of such changes do not reflect on the original works
- integrity or the original authors reputation. A subset of files
- (those that are related to the color instrument drivers, and are
- collected together into the instlib.zip archive by the
- spectro/instlib.ksh script + xicc/ccmx.h and xicc/ccmx.c) are
- licensed under the General Public License Version 2 or later, as
- detailed in the <a href="License2.txt">License2.txt</a> file.<br>
- </p>
- <p>Portions of the ColorHug instrument library
- (spectro/colorhug.[ch]) are Copyright 2011, Richard Hughes, and is
- licensed under the General Public License Version 2 or later, as
- detailed in the <a href="License2.txt">License2.txt</a> file.</p>
- <p>The tool spectro/spec2cie.c is Copyright 2005 Gerhard Fuernkranz,
- and is made available under the terms of the GNU General Public
- License Version 2 or later, and is licensed here under the Version
- 3 license, as detailed in the <a href="License3.txt">License3.txt</a>
- file.<br>
- </p>
- <p>The Win32 USB library libusb-win32 kernel drivers are included in
- this distribution in the usb/driver and usb/bin directories, and
- are copyright Stephan Meyer and Travis Robinson, and are licensed
- under the GNU Version 2 or later (the drivers, services,
- installer). See&nbsp; usb/driver/License.txt,
- libusbw/COPYING_LGPL.txt and libusbw/COPYING_GPL.txt for details.
- Additional terms noted on the <a
- href="http://sourceforge.net/apps/trac/libusb-win32/wiki">website</a>
- are "This license combination explicitly allows the use of this
- library in commercial, non-Open-Source applications."<br>
- </p>
- <p>The icc library in<span style="font-weight: bold;"> icc</span>/,
+
+ GNU</span> license <span style="font-weight: bold;">prohibits</span>
+ extending these tools<span style="font-weight: bold;"></span>
+ (i.e. by combining them with other programs or scripts that make
+ use of, depend on, or work with the ArgyllCMS code) and
+ distributing them, unless all the elements of the extensions are
+ also made available under a GPL compatible license. It is
+ permissible to provide ArgyllCMS tools with other non GPL
+ components if the elements of the package are not related, such
+ that the packaging is mere aggregation. For all the gory details,
+ please read the accompanying <a href="License.txt">license</a>. </p>
+ Note that unlike many commercial ICC profiling tools, the profiles
+ created using ArgyllCMS, are not subject to any claims or
+ restrictions of ArgyllCMS's author(s), but are assumed to be the
+ copyright property of the person who gathers the characterization
+ data, and causes the profiles to be created.
+ <p>The ArgyllCMS is Copyright 1995 - 2015 Graeme W. Gill, and is
+ made available under the terms of the Affero GNU General Public
+ License Version 3, as detailed in the <a href="License.txt">License.txt</a>
+ file. Documentation is licensed under the terms of the GNU Free
+ Documentation License, Version 1.3. The author asserts his moral
+ rights over this material in relationship to the attribution and
+ integrity of these works. In particular, if these works are
+ modified in a way that materially changes their functionality,
+ then the modified works should be renamed in a way that clearly
+ distinguishes them from "Argyll" or "ArgyllCMS" so that the
+ effects of such changes do not reflect on the original works
+ integrity or the original authors reputation. A subset of files
+ (those that are related to the color instrument drivers, and are
+ collected together into the instlib.zip archive by the
+ spectro/instlib.ksh script + xicc/ccmx.h and xicc/ccmx.c) are
+ licensed under the General Public License Version 2 or later, as
+ detailed in the <a href="License2.txt">License2.txt</a> file.<br>
+ </p>
+ <p>Portions of the ColorHug instrument library
+ (spectro/colorhug.[ch]) are Copyright 2011, Richard Hughes, and is
+ licensed under the General Public License Version 2 or later, as
+ detailed in the <a href="License2.txt">License2.txt</a> file.</p>
+ <p>The tool spectro/spec2cie.c is Copyright 2005 Gerhard Fuernkranz,
+ and is made available under the terms of the GNU General Public
+ License Version 2 or later, and is licensed here under the Version
+ 3 license, as detailed in the <a href="License3.txt">License3.txt</a>
+ file.<br>
+ </p>
+ <p>The Win32 USB library libusb-win32 kernel drivers are included in
+ this distribution in the usb/driver and usb/bin directories, and
+ are copyright Stephan Meyer and Travis Robinson, and are licensed
+ under the GNU Version 2 or later (the drivers, services,
+ installer). See&nbsp; usb/driver/License.txt,
+ libusbw/COPYING_LGPL.txt and libusbw/COPYING_GPL.txt for details.
+ Additional terms noted on the <a
+ href="http://sourceforge.net/apps/trac/libusb-win32/wiki">website</a>
+ are "This license combination explicitly allows the use of this
+ library in commercial, non-Open-Source applications."<br>
+ </p>
+ <p>The icc library in<span style="font-weight: bold;"> icc</span>/,
the CGATS library in <span style="font-weight: bold;">cgats</span>/,
@@ -1898,9 +1860,7 @@
-
-
-
+
the jcnf library in <span style="font-weight: bold;">jcnf</span>/,
@@ -1994,94 +1954,84 @@
-
-
-
- the files <span style="font-weight: bold;">spectro/xdg_bds.*</span>,
- <span style="font-weight: bold;">spectro/aglob.*</span> and the
- ucmm library in <span style="font-weight: bold;">ucmm</span>/ are
- Copyright 1995 - 2015 Graeme W. Gill, and available according to
- the "MIT" license granted in the icc/License.txt and
- cgats/License.txt files, and the licenses at the top of
- ucmm/ucmm.c and jcnf/jcnf.c.<br>
- </p>
- <p>The yajl library in <span style="font-weight: bold;">jcnf/yajl</span>
- is Copyright (c) 2007-2014, Lloyd Hilaiel &lt;me@lloyd.io&gt; and
- is used under an ISC License granted in the yajl/COPYING files.
- The yajl library has been repackaged and modified slightly to adds
- some features and for packaging and build convenience.<br>
- </p>
- <p> The TIFF library included in this distribution for convenience,
- has its own copyright and license detailed in tiff/COPYRIGHT (an
- "MIT"/"BSD" like license).<br>
- </p>
- <p>The Independent JPEG Group's JPEG library included in this
- distribution for convenience, has its own copyright and license
- detailed in jpg/README (an "MIT"/"BSD" like license). Executables
- that include JPEG format support are based in part on the work of
- the Independent JPEG Group. </p>
- <p>xicc/iccjpeg.h and xicc/iccjpeg.c are from <a
- href="http://www.littlecms.com/">lcms</a> and they are Copyright
- (c) 1998-2010 Marti Maria Saguer and is licensed under an
- "MIT"/"BSD" like license. See the top of the iccjpeg.c file for
- the detailed copyright and licensing conditions.<br>
- </p>
- <p>The mongoose web server software is Copyright (c) 2004-2011
- Sergey Lyubka, and is licensed under an "MIT" license.<br>
- </p>
- <p>The axTLS library is Copyright (c) 2008, Cameron Rich, and the
- license is detailed in ccast/axTLS/LICENSE file (an "MIT"/"BSD"
- like license).<br>
- It is not used for any security sensitive purpose, but is used
- purely to communicate with the ChromeCast.<br>
- </p>
- <p>The <a href="http://www.x3dom.org/">X3DOM</a> x3dom.css and
- x3dom.js files are Copyright (C) 2009 X3DOM and licensed dual
- "MIT" and "GPL" license. See plot/X3DOM_LICENSE.txt.<br>
- </p>
- <p>"<b>ArgyllCMS</b>" is a trade mark. It is permissible to refer to
- copies or derivatives of this software as being the same as
- ArgyllCMS if they are materially&nbsp; unchanged, and retain all
- the functionality provided by the software made available at
- www.argyllcms.com. Modified versions of this software that are
- materially changed or have missing functionality must be clearly
- marked as such, so as not to to be confused with ArgyllCMS.<br>
- </p>
- <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
- name="ProjType"></a>What sort of project is this ? (re:
- contributions)<br>
- </span></h2>
- This is essentially my private project, that I've made available
- under GNU licensing conditions. Because I license my code under
- other licenses as well, there is a limit to what I will accept in
- the way of code contributions back into this project. For me to
- accept contributions into the distribution, it either has to a
- non-core (side) project, or has to be offered to me with copyright
- conditions that are compatible with my other uses (i.e.. a "BSD"
- like license, or assigning or licensing the copyright to me), or has
- to be so trivial (say a one line bug fix), that it can't be the
- subject of copyright. <br>
- <br>
- Of course there is nothing to stop someone setting up a real free
- software, community project based on the GNU licensed code made
- available here, that would be able to take GNU licensed
- contributions from everyone and would essentially be a "fork" of
- this code base.<br>
- <br>
- <h1><u><a href="Compiling.html">Compiling</a></u></h1>
- How to <a href="Compiling.html">build the software</a> from the
- source if you want to.<br>
- <span style="font-weight: bold;">Note</span> that you don't need to
- do this if you are using one of the binary installations.<br>
- <h1 style="color: rgb(51, 204, 0);"><u><a href="Installing.html">Installing</a></u></h1>
- Important notes on <a href="Installing.html">installing the binary
- software</a> on various platforms.<br>
- <br>
- <h2 style="color: rgb(51, 0, 51);"><u><u><a name="GUIs"></a>Graphic
- User Interfaces<br>
- </u></u></h2>
- ArgyllCMS does not directly support a graphic user interface, but
- several people have written <span style="font-weight: bold;">GUI</span>
+
+ the files <span style="font-weight: bold;">spectro/xdg_bds.*</span>,
+ <span style="font-weight: bold;">spectro/aglob.*</span> and the
+ ucmm library in <span style="font-weight: bold;">ucmm</span>/ are
+ Copyright 1995 - 2015 Graeme W. Gill, and available according to
+ the "MIT" license granted in the icc/License.txt and
+ cgats/License.txt files, and the licenses at the top of
+ ucmm/ucmm.c and jcnf/jcnf.c.<br>
+ </p>
+ <p>The yajl library in <span style="font-weight: bold;">jcnf/yajl</span>
+ is Copyright (c) 2007-2014, Lloyd Hilaiel &lt;me@lloyd.io&gt; and
+ is used under an ISC License granted in the yajl/COPYING files.
+ The yajl library has been repackaged and modified slightly to adds
+ some features and for packaging and build convenience.<br>
+ </p>
+ <p> The TIFF library included in this distribution for convenience,
+ has its own copyright and license detailed in tiff/COPYRIGHT (an
+ "MIT"/"BSD" like license).<br>
+ </p>
+ <p>The Independent JPEG Group's JPEG library included in this
+ distribution for convenience, has its own copyright and license
+ detailed in jpg/README (an "MIT"/"BSD" like license). Executables
+ that include JPEG format support are based in part on the work of
+ the Independent JPEG Group. </p>
+ <p>xicc/iccjpeg.h and xicc/iccjpeg.c are from <a
+ href="http://www.littlecms.com/">lcms</a> and they are Copyright
+ (c) 1998-2010 Marti Maria Saguer and is licensed under an
+ "MIT"/"BSD" like license. See the top of the iccjpeg.c file for
+ the detailed copyright and licensing conditions.<br>
+ </p>
+ <p>The mongoose web server software is Copyright (c) 2004-2011
+ Sergey Lyubka, and is licensed under an "MIT" license.<br>
+ </p>
+ <p>The axTLS library is Copyright (c) 2008, Cameron Rich, and the
+ license is detailed in ccast/axTLS/LICENSE file (an "MIT"/"BSD"
+ like license).<br>
+ It is not used for any security sensitive purpose, but is used
+ purely to communicate with the ChromeCast.<br>
+ </p>
+ <p>The <a href="http://www.x3dom.org/">X3DOM</a> x3dom.css and
+ x3dom.js files are Copyright (C) 2009 X3DOM and licensed dual
+ "MIT" and "GPL" license. See plot/X3DOM_LICENSE.txt.<br>
+ </p>
+ <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
+ name="ProjType"></a>What sort of project is this ? (re:
+ contributions)<br>
+ </span></h2>
+ This is essentially my private project, that I've made available
+ under GNU licensing conditions. Because I license my code under
+ other licenses as well, there is a limit to what I will accept in
+ the way of code contributions back into this project. For me to
+ accept contributions into the distribution, it either has to a
+ non-core (side) project, or has to be offered to me with copyright
+ conditions that are compatible with my other uses (i.e.. a "BSD"
+ like license, or assigning or licensing the copyright to me), or has
+ to be so trivial (say a one line bug fix), that it can't be the
+ subject of copyright. <br>
+ <br>
+ Of course there is nothing to stop someone setting up a real free
+ software, community project based on the GNU licensed code made
+ available here, that would be able to take GNU licensed
+ contributions from everyone and would essentially be a "fork" of
+ this code base.<br>
+ <br>
+ <h1><u><a href="Compiling.html">Compiling</a></u></h1>
+ How to <a href="Compiling.html">build the software</a> from the
+ source if you want to.<br>
+ <span style="font-weight: bold;">Note</span> that you don't need to
+ do this if you are using one of the binary installations.<br>
+ <h1 style="color: rgb(51, 204, 0);"><u><a href="Installing.html">Installing</a></u></h1>
+ Important notes on <a href="Installing.html">installing the binary
+ software</a> on various platforms.<br>
+ <br>
+ <h2 style="color: rgb(51, 0, 51);"><u><u><a name="GUIs"></a>Graphic
+ User Interfaces<br>
+ </u></u></h2>
+ ArgyllCMS does not directly support a graphic user interface, but
+ several people have written <span style="font-weight: bold;">GUI</span>
based front ends for it. A popular <span style="font-weight: bold;"></span>front
end
that
@@ -2181,20 +2131,18 @@ calibration
-
-
-
- and profiling is <a href="http://hoech.net/dispcalGUI/">dispcalGUI</a>
- by Florian Höch. Others can be found with a suitable <a
-href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;aq=f&amp;aqi=g1&amp;aql=&amp;oq=">search</a>.<br>
- <h2 style="color: rgb(51, 0, 51);"><u><a name="CmdLine"></a>Main
- Tools and the command line<br>
- </u></h2>
- These are all command line ("DOS" shell) tools, and each tool
- require appropriate options to be set, followed by filename
- arguments. Sometimes the filenames will have to include the usual
- extensions, sometimes they are implicit. To get a brief listing of
- the possible arguments and <span style="font-weight: bold;">usage</span>
+
+ and profiling is <a href="http://hoech.net/dispcalGUI/">dispcalGUI</a>
+ by Florian Höch. Others can be found with a suitable <a
+href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;aq=f&amp;aqi=g1&amp;aql=&amp;oq=">search</a>.<br>
+ <h2 style="color: rgb(51, 0, 51);"><u><a name="CmdLine"></a>Main
+ Tools and the command line<br>
+ </u></h2>
+ These are all command line ("DOS" shell) tools, and each tool
+ require appropriate options to be set, followed by filename
+ arguments. Sometimes the filenames will have to include the usual
+ extensions, sometimes they are implicit. To get a brief listing of
+ the possible arguments and <span style="font-weight: bold;">usage</span>
of any of the tools, run it with just an "-?" argument, i.e. <b>targen
@@ -2287,25 +2235,23 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
-
-
-
- -? </b>(or some other unrecognized flag, if the "?" character is
- treated specially in your shell, i.e. try "--" on OS X zsh).<br>
- <br>
- Note that in general the arguments consist of possible flags or
- options followed by file name arguments. All arguments need to be
- separated by whitespace.&nbsp; (If you need to specify a string with
- embedded white space, double quote the string). A flag consists of a
- dash attached to a single letter, the letter identifying the flag,
- and is usually case sensitive. An option is a flag that has an
- associated parameter or parameters. The parameter can be separated
- from the flag by white space, or may come directly after the flag.
- So if a tool has a usage that looks like this:<br>
- <br>
- &nbsp; tool -?<br>
- &nbsp; usage: tool [options] infile outfile<br>
- &nbsp;&nbsp;
+
+ -? </b>(or some other unrecognized flag, if the "?" character is
+ treated specially in your shell, i.e. try "--" on OS X zsh).<br>
+ <br>
+ Note that in general the arguments consist of possible flags or
+ options followed by file name arguments. All arguments need to be
+ separated by whitespace.&nbsp; (If you need to specify a string with
+ embedded white space, double quote the string). A flag consists of a
+ dash attached to a single letter, the letter identifying the flag,
+ and is usually case sensitive. An option is a flag that has an
+ associated parameter or parameters. The parameter can be separated
+ from the flag by white space, or may come directly after the flag.
+ So if a tool has a usage that looks like this:<br>
+ <br>
+ &nbsp; tool -?<br>
+ &nbsp; usage: tool [options] infile outfile<br>
+ &nbsp;&nbsp;
-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2400,11 +2346,9 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
-
-
-
- Verbose mode<br>
- &nbsp;&nbsp; -d
+
+ Verbose mode<br>
+ &nbsp;&nbsp; -d
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2499,11 +2443,9 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
-
-
-
- Choose a depth 0-4<br>
- &nbsp;&nbsp; -r
+
+ Choose a depth 0-4<br>
+ &nbsp;&nbsp; -r
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2598,14 +2540,12 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
-
-
-
- Use a random depth<br>
- &nbsp;&nbsp; -f
- [nn]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Use full range. nn optional range 0 - 100.<br>
- &nbsp;&nbsp; -M
+
+ Use a random depth<br>
+ &nbsp;&nbsp; -f
+ [nn]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Use full range. nn optional range 0 - 100.<br>
+ &nbsp;&nbsp; -M
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2700,11 +2640,9 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
-
-
-
- Manual<br>
- &nbsp;&nbsp; infile
+
+ Manual<br>
+ &nbsp;&nbsp; infile
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2799,162 +2737,160 @@ href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;a
-
-
-
- Input file<br>
- &nbsp;&nbsp; outfile
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Output file<br>
- <br>
- then there are&nbsp; 5 flags/options, and two filename arguments.
- Notice that square braces [] denote optional items. The first
- flag/option is a flag. The second is an option that has a numerical
- argument in the range 0 to 4. The third is a flag. the fourth is an
- option with an optional argument. The fourth is a flag.&nbsp; The
- flags and options can generally be in any order, but must be before
- the file name arguments. (For a few special tools you actually
- specify a sequence of flags and files where the flags apply just to
- the following file.) So example invocations may look like:<br>
- <br>
- &nbsp; tool -v testin testout<br>
- &nbsp; tool -d3 -M testin1 testout2<br>
- &nbsp; tool -f infile outfile<br>
- &nbsp; tool -f 45 infile outfile<br>
- &nbsp; tool -d 3 -f67 infile outfile<br>
- <p>In order to make use of the tools, it is necessary to keep track
- of where various files are, and what they are called. There are
- many possible ways of doing this. One way is to put each source
- profile and all its associated files (test charts, spectrometer
- values etc.) in one set of directories for each source profile
- type. Similarly the device profiles could be stored in a hierarchy
- of directories ordered by device type, media, resolution, device
- mode etc. Naturally you will want to set your $PATH so that you
- can run the tools from whichever directory you are in, as well as
- specify any necessary directory paths for file arguments so that
- the tools are able to open them.<br>
- </p>
- <p>Note that there are two ways the Argyll tools deal with filename
- extensions. In one you supply the extension (ie. you supply the
- whole file name), so the extension is up to you. In the other
- (used where one name is used for input and output files, or where
- there are multiple output files), the program adds the extension.
- In the documentation this should be indicated by calling it a
- "base name".<br>
- </p>
- <p><a name="cltutes"></a>For more information on using a command
- line environments, consult an appropriate tutorial:</p>
- <p>MS Windows :<br>
- &nbsp;&nbsp; &lt;<a
- href="http://www.bleepingcomputer.com/tutorials/tutorial76.html">http://www.bleepingcomputer.com/tutorials/tutorial76.html</a>&gt;<br>
- &nbsp;&nbsp; &lt;<a
- href="http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1">http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1</a>&gt;<br>
- &nbsp;&nbsp; &lt;<a
- href="http://www.voidspace.org.uk/python/articles/command_line.shtml">http://www.voidspace.org.uk/python/articles/command_line.shtml</a>&gt;<br>
- <br>
- &nbsp;&nbsp;&nbsp; To find more: &lt;<a
-href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial&gt;</a><br>
- <br>
- OS X:<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.osxfaq.com/Tutorials/LearningCenter/">http://www.osxfaq.com/Tutorials/LearningCenter/</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.atomiclearning.com/macosxterminalx.shtml">http://www.atomiclearning.com/macosxterminalx.shtml</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html">http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html</a>&gt;<br>
- <br>
- &nbsp;&nbsp;&nbsp; To find more: &lt;<a
- href="http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial">http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial</a>&gt;<br>
- <br>
- Linux:<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.linuxcommand.org/index.php">http://www.linuxcommand.org/index.php</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.tuxfiles.org/linuxhelp/shell.html">http://www.tuxfiles.org/linuxhelp/shell.html</a>&gt;<br>
- &nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.ee.surrey.ac.uk/Teaching/Unix/">http://www.ee.surrey.ac.uk/Teaching/Unix/</a>&gt;<br>
- <br>
- &nbsp;&nbsp;&nbsp; To find more: &lt;<a
- href="http://www.google.com/search?q=linux+command+line+shell+tutorial">http://www.google.com/search?q=linux+command+line+shell+tutorial</a>&gt;</p>
- <p><br>
- <span style="font-weight: bold;">Note</span> that since OS X is
- based on UNIX, there is much in common between the OS X and Linux
- command line environments, and many of the UNIX tutorials may be
- useful:<br>
- </p>
- <p>&nbsp;&nbsp;&nbsp; &lt;<a
- href="http://www.rain.org/%7Emkummel/unix.html">http://www.rain.org/~mkummel/unix.html</a>&gt;<br>
- <br>
- </p>
- <h2><u><a href="Scenarios.html">Tutorial: Typical usage scenarios
- and examples</a></u></h2>
- A <a href="Scenarios.html">guided tour</a> of the major tools,
- applied to typical CMS jobs, such as calibrating displays, creating
- device profiles, calibrating printers, linking profiles, and
- converting color spaces of raster files. <br>
- <br>
- Although it is is a couple of years old now, this <a
- href="http://www.argyllcms.com/doc2/FCMS2010_ArgyllTute.pdf">tutorial</a>
- may also be of interest.<br>
- &nbsp; <br>
- <h3 style="color: rgb(0, 0, 0);"><u><a name="Topics"></a>Topical
- Discussions</u></h3>
- Discussions about particular topics:<br>
- <br>
- <a href="FWA.html">About Fluorescent Whitening Agent compensation</a><br>
- <br>
- <a href="instruments.html">Operation of particular instruments</a><br>
- <br>
- <a href="iccgamutmapping.html">About ICC profiles and Gamut Mapping</a><br>
- <br>
- <a href="monitorcontrols.html">About display monitor settings and
- targets</a><br>
- <br>
- <a href="gamma.html">About display "Gamma"</a><br>
- <br>
- <a href="calvschar.html">What's the difference between Calibration
- and Characterization ?</a><br>
- <br>
- <a href="WideGamutColmters.html">Why doesn't my Colorimeter work
- well on my Wide Gamut display ?</a><br>
- <span style="font-family: monospace;"></span><br>
- <a href="CrushedDisplyBlacks.html">My blacks get crushed on my
- display - why ? How do I fix it ?</a><br>
- <br>
- <a href="i1proDriver.html">How can I have confidence in the i1pro
- Driver ?</a><br>
- <br>
- <a href="i1proHiRes.html">Does the i1pro High Resolution mode
- improve accuracy ?</a><br>
- <br>
- <a href="evalInputTargets.html">Evaluating input targets</a><br>
- <br>
- <a href="ArgyllCMS_arts_tag.html">ArgyllCMS's Absolute to media
- Relative Transform Space matrix ('arts') ICC tag</a><br>
- <br>
- <h2><b><u><font><b><u><font size="+2"><a name="Flow"></a>Flow
- diagram of Major Tools:</font></u></b></font></u></b></h2>
- <br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a
- href="ArgyllFlow.jpg"><img alt="Thumbnail of Flow Diagram"
- src="ArgyllFlowThumb.jpg" style="border: 2px solid ; width:
- 150px; height: 202px;"></a><br>
- <br>
- <h2><b><u><font size="+2"><a name="CatList"></a>Main Tools by
- category:</font></u></b></h2>
- <h3>Calibrating devices<br>
- </h3>
- <small><a style="font-family: monospace;" href="dispcal.html">dispcal</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></small>Adjust,
- calibrate and profile a display<small><big>.<br>
- </big></small><small><a style="font-family: monospace;"
- href="printcal.html">printcal</a><span style="font-family:
- monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create a
- printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
- <h3>Creating test targets for profiling or print calibration<br>
- </h3>
- <small><a style="font-family: monospace;" href="targen.html">targen</a><span
+
+ Input file<br>
+ &nbsp;&nbsp; outfile
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Output file<br>
+ <br>
+ then there are&nbsp; 5 flags/options, and two filename arguments.
+ Notice that square braces [] denote optional items. The first
+ flag/option is a flag. The second is an option that has a numerical
+ argument in the range 0 to 4. The third is a flag. the fourth is an
+ option with an optional argument. The fourth is a flag.&nbsp; The
+ flags and options can generally be in any order, but must be before
+ the file name arguments. (For a few special tools you actually
+ specify a sequence of flags and files where the flags apply just to
+ the following file.) So example invocations may look like:<br>
+ <br>
+ &nbsp; tool -v testin testout<br>
+ &nbsp; tool -d3 -M testin1 testout2<br>
+ &nbsp; tool -f infile outfile<br>
+ &nbsp; tool -f 45 infile outfile<br>
+ &nbsp; tool -d 3 -f67 infile outfile<br>
+ <p>In order to make use of the tools, it is necessary to keep track
+ of where various files are, and what they are called. There are
+ many possible ways of doing this. One way is to put each source
+ profile and all its associated files (test charts, spectrometer
+ values etc.) in one set of directories for each source profile
+ type. Similarly the device profiles could be stored in a hierarchy
+ of directories ordered by device type, media, resolution, device
+ mode etc. Naturally you will want to set your $PATH so that you
+ can run the tools from whichever directory you are in, as well as
+ specify any necessary directory paths for file arguments so that
+ the tools are able to open them.<br>
+ </p>
+ <p>Note that there are two ways the Argyll tools deal with filename
+ extensions. In one you supply the extension (ie. you supply the
+ whole file name), so the extension is up to you. In the other
+ (used where one name is used for input and output files, or where
+ there are multiple output files), the program adds the extension.
+ In the documentation this should be indicated by calling it a
+ "base name".<br>
+ </p>
+ <p><a name="cltutes"></a>For more information on using a command
+ line environments, consult an appropriate tutorial:</p>
+ <p>MS Windows :<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.bleepingcomputer.com/tutorials/tutorial76.html">http://www.bleepingcomputer.com/tutorials/tutorial76.html</a>&gt;<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1">http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1</a>&gt;<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.voidspace.org.uk/python/articles/command_line.shtml">http://www.voidspace.org.uk/python/articles/command_line.shtml</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial&gt;</a><br>
+ <br>
+ OS X:<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.osxfaq.com/Tutorials/LearningCenter/">http://www.osxfaq.com/Tutorials/LearningCenter/</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.atomiclearning.com/macosxterminalx.shtml">http://www.atomiclearning.com/macosxterminalx.shtml</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html">http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+ href="http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial">http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial</a>&gt;<br>
+ <br>
+ Linux:<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.linuxcommand.org/index.php">http://www.linuxcommand.org/index.php</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.tuxfiles.org/linuxhelp/shell.html">http://www.tuxfiles.org/linuxhelp/shell.html</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.ee.surrey.ac.uk/Teaching/Unix/">http://www.ee.surrey.ac.uk/Teaching/Unix/</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+ href="http://www.google.com/search?q=linux+command+line+shell+tutorial">http://www.google.com/search?q=linux+command+line+shell+tutorial</a>&gt;</p>
+ <p><br>
+ <span style="font-weight: bold;">Note</span> that since OS X is
+ based on UNIX, there is much in common between the OS X and Linux
+ command line environments, and many of the UNIX tutorials may be
+ useful:<br>
+ </p>
+ <p>&nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.rain.org/%7Emkummel/unix.html">http://www.rain.org/~mkummel/unix.html</a>&gt;<br>
+ <br>
+ </p>
+ <h2><u><a href="Scenarios.html">Tutorial: Typical usage scenarios
+ and examples</a></u></h2>
+ A <a href="Scenarios.html">guided tour</a> of the major tools,
+ applied to typical CMS jobs, such as calibrating displays, creating
+ device profiles, calibrating printers, linking profiles, and
+ converting color spaces of raster files. <br>
+ <br>
+ Although it is is a couple of years old now, this <a
+ href="http://www.argyllcms.com/doc2/FCMS2010_ArgyllTute.pdf">tutorial</a>
+ may also be of interest.<br>
+ &nbsp; <br>
+ <h3 style="color: rgb(0, 0, 0);"><u><a name="Topics"></a>Topical
+ Discussions</u></h3>
+ Discussions about particular topics:<br>
+ <br>
+ <a href="FWA.html">About Fluorescent Whitening Agent compensation</a><br>
+ <br>
+ <a href="instruments.html">Operation of particular instruments</a><br>
+ <br>
+ <a href="iccgamutmapping.html">About ICC profiles and Gamut Mapping</a><br>
+ <br>
+ <a href="monitorcontrols.html">About display monitor settings and
+ targets</a><br>
+ <br>
+ <a href="gamma.html">About display "Gamma"</a><br>
+ <br>
+ <a href="calvschar.html">What's the difference between Calibration
+ and Characterization ?</a><br>
+ <br>
+ <a href="WideGamutColmters.html">Why doesn't my Colorimeter work
+ well on my Wide Gamut display ?</a><br>
+ <span style="font-family: monospace;"></span><br>
+ <a href="CrushedDisplyBlacks.html">My blacks get crushed on my
+ display - why ? How do I fix it ?</a><br>
+ <br>
+ <a href="i1proDriver.html">How can I have confidence in the i1pro
+ Driver ?</a><br>
+ <br>
+ <a href="i1proHiRes.html">Does the i1pro High Resolution mode
+ improve accuracy ?</a><br>
+ <br>
+ <a href="evalInputTargets.html">Evaluating input targets</a><br>
+ <br>
+ <a href="ArgyllCMS_arts_tag.html">ArgyllCMS's Absolute to media
+ Relative Transform Space matrix ('arts') ICC tag</a><br>
+ <br>
+ <h2><b><u><font><b><u><font size="+2"><a name="Flow"></a>Flow
+ diagram of Major Tools:</font></u></b></font></u></b></h2>
+ <br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a
+ href="ArgyllFlow.jpg"><img alt="Thumbnail of Flow Diagram"
+ src="ArgyllFlowThumb.jpg" style="border: 2px solid ; width:
+ 150px; height: 202px;"></a><br>
+ <br>
+ <h2><b><u><font size="+2"><a name="CatList"></a>Main Tools by
+ category:</font></u></b></h2>
+ <h3>Calibrating devices<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="dispcal.html">dispcal</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></small>Adjust,
+ calibrate and profile a display<small><big>.<br>
+ </big></small><small><a style="font-family: monospace;"
+ href="printcal.html">printcal</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create a
+ printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
+ <h3>Creating test targets for profiling or print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="targen.html">targen</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3049,12 +2985,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span><big>Generate a profiling test target values .ti1 file. </big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
+
+ </span><big>Generate a profiling test target values .ti1 file. </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Create
@@ -3149,12 +3083,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- film recorder TIFF files from Argyll .ti1 file. </big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
+
+ film recorder TIFF files from Argyll .ti1 file. </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Create
@@ -3249,14 +3181,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a PS, EPS or TIFF file containing test patch values, ready for
- printing.</big></small>
- <h3>Obtaining test results for profiling or print calibration<br>
- </h3>
- <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
+
+ a PS, EPS or TIFF file containing test patch values, ready for
+ printing.</big></small>
+ <h3>Obtaining test results for profiling or print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Read
@@ -3351,13 +3281,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a test chart using an instrument to create a .ti3 data file.</big><span
- style="font-family: monospace;"> </span><br style="font-family:
- monospace;">
- <a style="font-family: monospace;" href="dispread.html">dispread</a><span
+
+ a test chart using an instrument to create a .ti3 data file.</big><span
+ style="font-family: monospace;"> </span><br style="font-family:
+ monospace;">
+ <a style="font-family: monospace;" href="dispread.html">dispread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Test
@@ -3452,12 +3380,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- and read colorimetric values from a display </big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="filmread.html">filmread</a><span
+
+ and read colorimetric values from a display </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="filmread.html">filmread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Read
@@ -3552,12 +3478,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- film colorimetric values using a SpectroScanT (Deprecated ?)</big><br
- style="font-family: monospace;">
- <a style="font-family: monospace;" href="scanin.html">scanin</a><span
+
+ film colorimetric values using a SpectroScanT (Deprecated ?)</big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="scanin.html">scanin</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3652,17 +3576,15 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span><big>Convert a TIFF&nbsp; image of a test chart into .ti3
- device values. <br>
- </big></small><small><a style="font-family: monospace;"
- href="illumread.html">illumread</a><span style="font-family:
- monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use an
- instrument to measure an illuminant spectrum, and estimate its UV
- content.<br style="font-family: monospace;">
- <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
+
+ </span><big>Convert a TIFF&nbsp; image of a test chart into .ti3
+ device values. <br>
+ </big></small><small><a style="font-family: monospace;"
+ href="illumread.html">illumread</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use an
+ instrument to measure an illuminant spectrum, and estimate its UV
+ content.<br style="font-family: monospace;">
+ <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake
@@ -3757,16 +3679,14 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- the reading of a device using an ICC or MPP profile. <br>
- </big></small><small><a style="font-family: monospace;"
- href="synthread.html">synthread</a><span style="font-family:
- monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake the
- reading of a device using a synthetic device model. </big></small><br
- style="font-family: monospace;">
- <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
+
+ the reading of a device using an ICC or MPP profile. <br>
+ </big></small><small><a style="font-family: monospace;"
+ href="synthread.html">synthread</a><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake the
+ reading of a device using a synthetic device model. </big></small><br
+ style="font-family: monospace;">
+ <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3861,13 +3781,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span><big>Convert Colorblind format CMY/RGB test chart into
- Argyll .ti3 CGATS format. </big><br style="font-family:
- monospace;">
- <a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
+
+ </span><big>Convert Colorblind format CMY/RGB test chart into
+ Argyll .ti3 CGATS format. </big><br style="font-family:
+ monospace;">
+ <a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Convert
@@ -3962,12 +3880,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
- format. </big><br style="font-family: monospace;">
- <a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
+
+ Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
+ format. </big><br style="font-family: monospace;">
+ <a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4062,14 +3978,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span><big>Convert Gretag/Logo/X-Rite/Barbieri or other format
- RGB or CMYK test chart results into Argyll .ti3 CGATS format. </big></small><br
- style="font-family: monospace;">
- <small><big><small><a style="font-family: monospace;"
- href="ls2ti3.html">ls2ti3</a><span style="font-family:
+
+ </span><big>Convert Gretag/Logo/X-Rite/Barbieri or other format
+ RGB or CMYK test chart results into Argyll .ti3 CGATS format. </big></small><br
+ style="font-family: monospace;">
+ <small><big><small><a style="font-family: monospace;"
+ href="ls2ti3.html">ls2ti3</a><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Convert
@@ -4101,12 +4015,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- LightSpace format RGB .bcs test chart results into Argyll
- .ti3 CGATS format.</big></small></big><br>
- <a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
+
+ LightSpace format RGB .bcs test chart results into Argyll
+ .ti3 CGATS format.</big></small></big><br>
+ <a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4201,13 +4113,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span><big>Create a fake Argyll .ti3 CMY data file from a CMYK
- profile, as a basis of creating a CMY to CMYK separation<br>
- </big></small><small><a style="font-family: monospace;"
- href="average.html">average</a><span style="font-family:
+
+ </span><big>Create a fake Argyll .ti3 CMY data file from a CMYK
+ profile, as a basis of creating a CMY to CMYK separation<br>
+ </big></small><small><a style="font-family: monospace;"
+ href="average.html">average</a><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Average
@@ -4231,13 +4141,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- or Merge two or more measurement data files, or average patches
- within a single file.</big></small><br>
- <h3>Creating Device Profiles</h3>
- <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
+
+ or Merge two or more measurement data files, or average patches
+ within a single file.</big></small><br>
+ <h3>Creating Device Profiles</h3>
+ <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4332,11 +4240,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Create an ICC profile from the .ti3 test data. <br>
- <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
+
+ </span></small>Create an ICC profile from the .ti3 test data. <br>
+ <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4431,12 +4337,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Create a Model Printer Profile (MPP) from the .ti3
- test data. <br>
- <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
+
+ </span></small>Create a Model Printer Profile (MPP) from the .ti3
+ test data. <br>
+ <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4531,13 +4435,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Regenerate a device profiles B2A table data by
- inverting the A2B table.
- <h3>Creating Device Link Profiles</h3>
- <small><a style="font-family: monospace;" href="collink.html">collink</a><span
+
+ </span></small>Regenerate a device profiles B2A table data by
+ inverting the A2B table.
+ <h3>Creating Device Link Profiles</h3>
+ <small><a style="font-family: monospace;" href="collink.html">collink</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4632,14 +4534,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Link two device ICC profiles to create a device
- link profile.
- <h3>Converting colors or applying print calibration<br>
- </h3>
- <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
+
+ </span></small>Link two device ICC profiles to create a device
+ link profile.
+ <h3>Converting colors or applying print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4734,13 +4634,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Color convert a TIFF or JPEG file using a sequence
- of ICC device, device link, abstract profiles and calibration files.
- <br>
- <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
+
+ </span></small>Color convert a TIFF or JPEG file using a sequence
+ of ICC device, device link, abstract profiles and calibration files.
+ <br>
+ <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Apply
@@ -4834,11 +4732,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- calibration curves to an ICC profile.<br>
- <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
+
+ calibration curves to an ICC profile.<br>
+ <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -4933,12 +4829,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Lookup individual color values through any ICC
- profile table. <br>
- <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
+
+ </span></small>Lookup individual color values through any ICC
+ profile table. <br>
+ <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5033,12 +4927,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Lookup individual color values forward or inverted
- though an ICC profile or CAL table. <br>
- <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
+
+ </span></small>Lookup individual color values forward or inverted
+ though an ICC profile or CAL table. <br>
+ <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5133,12 +5025,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Lookup individual color values though an MPP
- profile. Also create MPP gamut files/views.<br>
- <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
+
+ </span></small>Lookup individual color values though an MPP
+ profile. Also create MPP gamut files/views.<br>
+ <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
@@ -5233,20 +5123,18 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a TIFF file to monochrome using an ICC device profile <br>
- <h3>Color Tweaking tools<br>
- </h3>
- <small><a style="font-family: monospace;" href="refine.html">refine</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
- abstract profile from two chart readings, useful for refining
- proofing profiles. <a href="mppprof.html"><br>
- </a>
- <h3>Creating gamut views</h3>
- <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
+
+ a TIFF file to monochrome using an ICC device profile <br>
+ <h3>Color Tweaking tools<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="refine.html">refine</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
+ abstract profile from two chart readings, useful for refining
+ proofing profiles. <a href="mppprof.html"><br>
+ </a>
+ <h3>Creating gamut views</h3>
+ <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -5341,11 +5229,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a gamut file or VRML file of the color gamut of an ICC profile. <br>
- <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
+
+ a gamut file or VRML file of the color gamut of an ICC profile. <br>
+ <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -5440,12 +5326,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a gamut file or VRML file of the color gamut of a TIFF or JPEG
- image. <br>
- <small><a style="font-family: monospace;" href="viewgam.html">viewgam</a><span
+
+ a gamut file or VRML file of the color gamut of a TIFF or JPEG
+ image. <br>
+ <small><a style="font-family: monospace;" href="viewgam.html">viewgam</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5540,14 +5424,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Convert one or more gamuts into a VRML 3D
- visualization file. Compute an intersection.<br>
- <h3>Diagnostic and test tools<br>
- </h3>
- <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
+
+ </span></small>Convert one or more gamuts into a VRML 3D
+ visualization file. Compute an intersection.<br>
+ <h3>Diagnostic and test tools<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -5642,11 +5524,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Dump the contents of an ICC profile as text. <br>
- <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
+
+ </span></small>Dump the contents of an ICC profile as text. <br>
+ <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -5741,11 +5621,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an ICC profile against .ti3 test chart data, create pruned .ti3
- file.<br>
+
+ an ICC profile against .ti3 test chart data, create pruned .ti3
+ file.<br>
<small style="font-family: monospace;"><a href="invprofcheck.html">invprofcheck</a>&nbsp;
@@ -5840,11 +5718,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </small>Check ICC forward against inverse lookup. <br>
- <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
+
+ </small>Check ICC forward against inverse lookup. <br>
+ <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Split
@@ -5938,15 +5814,13 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a CGATS file (ie. a .ti3) into two parts randomly to verify
- profiling. <br>
- <small style="font-family: monospace;"><a href="timage.html">timage</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Create TIFF test
- images. <br>
- <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
+
+ a CGATS file (ie. a .ti3) into two parts randomly to verify
+ profiling. <br>
+ <small style="font-family: monospace;"><a href="timage.html">timage</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Create TIFF test
+ images. <br>
+ <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -6041,11 +5915,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an MPP profile against .ti3 test chart data. <br>
- <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
+
+ an MPP profile against .ti3 test chart data. <br>
+ <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -6139,11 +6011,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an instrument to read a single spot color value. <br>
- <small><a style="font-family: monospace;" href="colverify.html">colverify</a><span
+
+ an instrument to read a single spot color value. <br>
+ <small><a style="font-family: monospace;" href="colverify.html">colverify</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Verify
@@ -6181,12 +6051,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- matching of CIE in two CGATS/.ti3 files (also view differences as
- VRML)<br>
- <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
+
+ matching of CIE in two CGATS/.ti3 files (also view differences as
+ VRML)<br>
+ <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -6280,13 +6148,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a synthetic input, display or output calibration (<a
- href="File_Formats.html#.cal">.cal</a>)file.
- <h3>Other Tools</h3>
- <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
+
+ a synthetic input, display or output calibration (<a
+ href="File_Formats.html#.cal">.cal</a>)file.
+ <h3>Other Tools</h3>
+ <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -6380,14 +6246,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a Spectrometer to create a Colorimeter Correction Matrix
- (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
- for a particular display.<br>
- <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
- style="font-family: monospace;"></span></small><small><span
+
+ a Spectrometer to create a Colorimeter Correction Matrix
+ (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
+ for a particular display.<br>
+ <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
+ style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp; </span>Extract
@@ -6482,17 +6346,15 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an embedded ICC profile from a TIFF or JPEG file.<br>
- </small><small><a style="font-family: monospace;"
- href="extractttag.html">extractttag</a><span style="font-family:
- monospace;"></span></small><small><span style="font-family:
- monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
- .ti3 data or CAL) from an ICC profile.</small><br>
- <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
- style="font-family: monospace;"></span></small><small><span
+
+ an embedded ICC profile from a TIFF or JPEG file.<br>
+ </small><small><a style="font-family: monospace;"
+ href="extractttag.html">extractttag</a><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
+ .ti3 data or CAL) from an ICC profile.</small><br>
+ <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
+ style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; </span></small>Install
@@ -6587,18 +6449,16 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- or uninstall display profile, set display calibration from profile
- or .cal file, test displace and dispwin access to a display.<br>
- <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span></small>Install Instrument manufacturers files for the
- Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
- 5,&nbsp; CCMX files for colorimeters.<br>
- <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
+
+ or uninstall display profile, set display calibration from profile
+ or .cal file, test displace and dispwin access to a display.<br>
+ <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span></small>Install Instrument manufacturers files for the
+ Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
+ 5,&nbsp; CCMX files for colorimeters.<br>
+ <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
style="text-decoration: underline; font-family: monospace;"></span></small>&nbsp;
@@ -6693,12 +6553,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
- <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
+
+ Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
+ <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
style="text-decoration: underline; font-family: monospace;"></span></small>Convert
@@ -6793,15 +6651,13 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- reflective spectral .ti3 readings into CIE XYZ and D50 L*a*b*
- readings. Apply FWA, plot spectrums.<br>
- &nbsp;
- <h2><b><u><font size="+2"><a name="AlphList"></a>Main Tools
- Alphabetic Listing:</font></u></b></h2>
- <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
+
+ reflective spectral .ti3 readings into CIE XYZ and D50 L*a*b*
+ readings. Apply FWA, plot spectrums.<br>
+ &nbsp;
+ <h2><b><u><font size="+2"><a name="AlphList"></a>Main Tools
+ Alphabetic Listing:</font></u></b></h2>
+ <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Apply
@@ -6895,11 +6751,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- calibration curves to an ICC profile.<br>
- <small><a style="font-family: monospace;" href="average.html">average</a><span
+
+ calibration curves to an ICC profile.<br>
+ <small><a style="font-family: monospace;" href="average.html">average</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -6994,12 +6848,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small><small><big>Average or Merge two or more
- measurement data files, or average patches within a single file.</big></small><br>
- <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
+
+ </span></small><small><big>Average or Merge two or more
+ measurement data files, or average patches within a single file.</big></small><br>
+ <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7094,12 +6946,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Convert Colorblind format CMY/RGB test chart into
- Argyll .ti3 CGATS format. <br>
- <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
+
+ </span></small>Convert Colorblind format CMY/RGB test chart into
+ Argyll .ti3 CGATS format. <br>
+ <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7194,12 +7044,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Color convert a TIFF or JPEG file using a sequence
- of ICC device, device link, abstract profiles and calibration files.<br>
- <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
+
+ </span></small>Color convert a TIFF or JPEG file using a sequence
+ of ICC device, device link, abstract profiles and calibration files.<br>
+ <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -7293,13 +7141,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a Spectrometer to create a Colorimeter Correction Matrix
- (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
- for a particular display.<br>
- <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
+
+ a Spectrometer to create a Colorimeter Correction Matrix
+ (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
+ for a particular display.<br>
+ <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Read
@@ -7394,11 +7240,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a test chart using an instrument to create a .ti3 data file. <br>
- <small><a style="font-family: monospace;" href="collink.html">collink</a><span
+
+ a test chart using an instrument to create a .ti3 data file. <br>
+ <small><a style="font-family: monospace;" href="collink.html">collink</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7493,12 +7337,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Link two device ICC profiles to create a device
- link profile. <br>
- <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
+
+ </span></small>Link two device ICC profiles to create a device
+ link profile. <br>
+ <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -7593,12 +7435,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Create an ICC profile from the .ti3 test data.<br>
- <font size="-1"><a style="font-family: monospace;"
- href="colverify.html">colverify</a><span
+
+ </span></small>Create an ICC profile from the .ti3 test data.<br>
+ <font size="-1"><a style="font-family: monospace;"
+ href="file:///D:/src/argyll/doc/colverify.html">colverify</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></font>Verify
@@ -7693,15 +7533,13 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- matching of CIE in two CGATS/.ti3 files (also view differences as
- VRML)<br>
- <small style="font-family: monospace;"><a href="dispcal.html">dispcal</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Adjust, calibrate and
- profile a display<small><big>.</big></small><br>
- <small><a style="font-family: monospace;" href="dispread.html">dispread</a><span
+
+ matching of CIE in two CGATS/.ti3 files (also view differences as
+ VRML)<br>
+ <small style="font-family: monospace;"><a href="dispcal.html">dispcal</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Adjust, calibrate and
+ profile a display<small><big>.</big></small><br>
+ <small><a style="font-family: monospace;" href="dispread.html">dispread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Test
@@ -7796,12 +7634,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- and read colorimetric values from a display <br>
- <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
- style="font-family: monospace;"></span></small><small><span
+
+ and read colorimetric values from a display <br>
+ <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
+ style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; </span></small>Install
@@ -7896,13 +7732,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- or uninstall display profile, set display calibration from profile
- or .cal file, test displace and dispwin access to a display.<br>
- <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
- style="font-family: monospace;"></span></small><small><span
+
+ or uninstall display profile, set display calibration from profile
+ or .cal file, test displace and dispwin access to a display.<br>
+ <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
+ style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp; </span>Extract
@@ -7997,16 +7831,14 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an embedded ICC profile from a TIFF or JPEG file.<br>
- </small><small><a style="font-family: monospace;"
- href="extractttag.html">extractttag</a><span style="font-family:
- monospace;"></span></small><small><span style="font-family:
- monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
- .ti3 data or CAL) from an ICC profile.</small><br>
- <small><a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
+
+ an embedded ICC profile from a TIFF or JPEG file.<br>
+ </small><small><a style="font-family: monospace;"
+ href="extractttag.html">extractttag</a><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
+ .ti3 data or CAL) from an ICC profile.</small><br>
+ <small><a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -8101,12 +7933,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Create a fake Argyll .ti3 CMY data file from a CMYK
- profile, as a basis of creating a CMY to CMYK separation <br>
- <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
+
+ </span></small>Create a fake Argyll .ti3 CMY data file from a CMYK
+ profile, as a basis of creating a CMY to CMYK separation <br>
+ <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Fake
@@ -8201,11 +8031,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- the reading of a device using an ICC or MPP profile. <br>
- <small><a style="font-family: monospace;" href="filmread.html">filmread</a><span
+
+ the reading of a device using an ICC or MPP profile. <br>
+ <small><a style="font-family: monospace;" href="filmread.html">filmread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Read
@@ -8300,11 +8128,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- film colorimetric values using a SpectroScanT (Deprecated ?)<br>
- <small><a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
+
+ film colorimetric values using a SpectroScanT (Deprecated ?)<br>
+ <small><a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -8399,11 +8225,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- film recorder TIFF files from Argyll .ti1 file. <br>
- <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
+
+ film recorder TIFF files from Argyll .ti1 file. <br>
+ <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
@@ -8498,12 +8322,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a TIFF file to monochrome using an ICC device profile <small><a
- style="font-family: monospace;" href="oeminst.html"></a></small><br>
- <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
+
+ a TIFF file to monochrome using an ICC device profile <small><a
+ style="font-family: monospace;" href="oeminst.html"></a></small><br>
+ <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -8598,11 +8420,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Dump the contents of an ICC profile as text. <br>
- <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
+
+ </span></small>Dump the contents of an ICC profile as text. <br>
+ <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -8697,11 +8517,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a gamut file or VRML file of the color gamut of an ICC profile. <br>
- <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
+
+ a gamut file or VRML file of the color gamut of an ICC profile. <br>
+ <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -8796,12 +8614,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Lookup individual color values through any ICC
- profile table. <br>
- <small><a style="font-family: monospace;" href="illumread.html">illumread</a><span
+
+ </span></small>Lookup individual color values through any ICC
+ profile table. <br>
+ <small><a style="font-family: monospace;" href="illumread.html">illumread</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use
@@ -8895,15 +8711,13 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an instrument to measure an illuminant spectrum, and estimate its UV
- content.<br>
- <small><a style="font-family: monospace;" href="invprofcheck.html">invprofcheck</a><span
- style="font-family: monospace;">&nbsp; </span></small>Check ICC
- forward against inverse lookup. <br>
- <small><a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
+
+ an instrument to measure an illuminant spectrum, and estimate its UV
+ content.<br>
+ <small><a style="font-family: monospace;" href="invprofcheck.html">invprofcheck</a><span
+ style="font-family: monospace;">&nbsp; </span></small>Check ICC
+ forward against inverse lookup. <br>
+ <small><a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
@@ -8998,13 +8812,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
- format. <br>
- <small><big><small><a style="font-family: monospace;"
- href="ls2ti3.html">ls2ti3</a><span
+
+ Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
+ format. <br>
+ <small><big><small><a style="font-family: monospace;"
+ href="file:///D:/src/argyll/doc/ls2ti3.html">ls2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9099,12 +8911,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span><big>Convert LightSpace format RGB .bcs test chart
- results into Argyll .ti3 CGATS format.</big></small></big></small><br>
- <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
+
+ </span><big>Convert LightSpace format RGB .bcs test chart
+ results into Argyll .ti3 CGATS format.</big></small></big></small><br>
+ <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -9199,11 +9009,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an MPP profile against .ti3 test chart data. <br>
- <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
+
+ an MPP profile against .ti3 test chart data. <br>
+ <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9298,12 +9106,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Lookup individual color values though an MPP
- profile. Also create MPP gamut files/views. <br>
- <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
+
+ </span></small>Lookup individual color values though an MPP
+ profile. Also create MPP gamut files/views. <br>
+ <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9398,17 +9204,15 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Create a Model Printer Profile (MPP) from the .ti3
- test data. <br>
- <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span></small>Install Instrument manufacturers files for the
- Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
- 5,&nbsp; CCMX files for colorimeters.<br>
- <small><a style="font-family: monospace;" href="printcal.html">printcal</a><span
+
+ </span></small>Create a Model Printer Profile (MPP) from the .ti3
+ test data. <br>
+ <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span></small>Install Instrument manufacturers files for the
+ Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4 or
+ 5,&nbsp; CCMX files for colorimeters.<br>
+ <small><a style="font-family: monospace;" href="printcal.html">printcal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -9502,11 +9306,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
- <small><a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
+
+ a printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
+ <small><a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small><small><big>Create
@@ -9601,12 +9403,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a PS, EPS or TIFF file containing test patch values, ready for
- printing.</big></small><br>
- <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
+
+ a PS, EPS or TIFF file containing test patch values, ready for
+ printing.</big></small><br>
+ <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
@@ -9701,17 +9501,15 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an ICC profile against .ti3 test chart data, create pruned .ti3
- file.<br>
- <small><a style="font-family: monospace;" href="refine.html">refine</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
- abstract profile from two chart readings, useful for refining
- proofing profiles. <br>
- <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
+
+ an ICC profile against .ti3 test chart data, create pruned .ti3
+ file.<br>
+ <small><a style="font-family: monospace;" href="refine.html">refine</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
+ abstract profile from two chart readings, useful for refining
+ proofing profiles. <br>
+ <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9806,12 +9604,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Regenerate a device profiles B2A table data by
- inverting the A2B table. <br>
- <small><a style="font-family: monospace;" href="scanin.html">scanin</a><span
+
+ </span></small>Regenerate a device profiles B2A table data by
+ inverting the A2B table. <br>
+ <small><a style="font-family: monospace;" href="scanin.html">scanin</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -9906,13 +9702,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Convert a TIFF&nbsp; image of a test chart into
- .ti3 device values. <br>
- <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
- style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
+
+ </span></small>Convert a TIFF&nbsp; image of a test chart into
+ .ti3 device values. <br>
+ <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
style="text-decoration: underline; font-family: monospace;"></span></small>Convert
@@ -10007,13 +9801,11 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- reflective spectral .ti3 readings into CIE XYZ and D50 L*a*b*
- readings. Apply FWA, plot spectrums.<br>
- <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
- style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
+
+ reflective spectral .ti3 readings into CIE XYZ and D50 L*a*b*
+ readings. Apply FWA, plot spectrums.<br>
+ <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
style="text-decoration: underline; font-family: monospace;"></span></small>&nbsp;
@@ -10108,11 +9900,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
- <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
+
+ Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
+ <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Split
@@ -10206,12 +9996,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a CGATS file (ie. a .ti3) into two parts randomly to verify
- profiling. <br>
- <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
+
+ a CGATS file (ie. a .ti3) into two parts randomly to verify
+ profiling. <br>
+ <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
@@ -10305,12 +10093,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- an instrument to read a single spot color value. <small><a
- style="font-family: monospace;" href="oeminst.html"></a></small><br>
- <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
+
+ an instrument to read a single spot color value. <small><a
+ style="font-family: monospace;" href="oeminst.html"></a></small><br>
+ <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -10404,12 +10190,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a synthetic input, display or output calibration (<a
- href="File_Formats.html#.cal">.cal</a>)file.<br>
- <small><a style="font-family: monospace;" href="synthread.html">synthread</a><span
+
+ a synthetic input, display or output calibration (<a
+ href="File_Formats.html#.cal">.cal</a>)file.<br>
+ <small><a style="font-family: monospace;" href="synthread.html">synthread</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake
@@ -10504,11 +10288,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- the reading of a device using a synthetic device model. </big></small><br>
- <small><a style="font-family: monospace;" href="targen.html">targen</a><span
+
+ the reading of a device using a synthetic device model. </big></small><br>
+ <small><a style="font-family: monospace;" href="targen.html">targen</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -10603,12 +10385,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Generate a profiling test target values .ti1 file.
- <br>
- <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
+
+ </span></small>Generate a profiling test target values .ti1 file.
+ <br>
+ <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
@@ -10703,16 +10483,14 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- a gamut file or VRML file of the color gamut of a TIFF or JPEG
- image. <br>
- <small><a style="font-family: monospace;" href="timage.html">timage</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create TIFF
- test images. <br>
- <small><a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
+
+ a gamut file or VRML file of the color gamut of a TIFF or JPEG
+ image. <br>
+ <small><a style="font-family: monospace;" href="timage.html">timage</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create TIFF
+ test images. <br>
+ <small><a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -10807,14 +10585,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small><small><big>Convert Gretag/Logo/X-Rite/Barbieri or
- other format RGB or CMYK test chart results into Argyll .ti3
- CGATS format.</big></small> <br>
- <font size="-1"><a style="font-family: monospace;"
- href="viewgam.html">viewgam</a><span style="font-family:
+
+ </span></small><small><big>Convert Gretag/Logo/X-Rite/Barbieri or
+ other format RGB or CMYK test chart results into Argyll .ti3
+ CGATS format.</big></small> <br>
+ <font size="-1"><a style="font-family: monospace;"
+ href="viewgam.html">viewgam</a><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font>Convert
@@ -10908,12 +10684,10 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- one or more gamuts into a VRML 3D visualization file. Compute an
- intersection.<br>
- <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
+
+ one or more gamuts into a VRML 3D visualization file. Compute an
+ intersection.<br>
+ <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11008,39 +10782,37 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- </span></small>Lookup individual color values forward or inverted
- though an ICC profile or CAL table. <br>
- <br>
- <h2><u><a href="Environment.html">Environment Variables<br>
- </a></u></h2>
- <span style="text-decoration: underline;"><span style="font-weight:
- bold;"></span></span> Performance/memory tuning hints, plus
- tweaks for scipting.<br>
- <h2><u><a href="Performance.html">Performance Tuning<br>
- </a></u></h2>
- <span style="text-decoration: underline;"><span style="font-weight:
- bold;"></span></span> Performance hints. <br>
- <h2><u><a href="Overview.html">Overview</a></u></h2>
- Overview of the software and its aims and functionality.<br>
- <h2><u><a href="Limitations.html">Limitations</a></u></h2>
- Limitations of the current functionality.<br>
- <h2><u><a href="Organisation.html">Organization</a></u></h2>
- How directories are organized, what they contain.
- <h2><u><a href="Source.html">Source</a></u></h2>
- Any detailed documentation on how the software works, or what
- algorithms it is based on. (Very incomplete.)
- <h2><u><a href="MinorTools.html">Minor Tools</a></u></h2>
- A very brief description of minor tools and test harnesses. <br>
- <br>
- <br>
- <h2><u><a name="FFormats"></a><a href="File_Formats.html">File
- formats that Argyll uses</a></u></h2>
- Argyll uses a number of file formats for its operation, some that
- are external standards, and some that are unique to Argyll. <br>
- <br>
+
+ </span></small>Lookup individual color values forward or inverted
+ though an ICC profile or CAL table. <br>
+ <br>
+ <h2><u><a href="Environment.html">Environment Variables<br>
+ </a></u></h2>
+ <span style="text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span> Performance/memory tuning hints, plus
+ tweaks for scipting.<br>
+ <h2><u><a href="Performance.html">Performance Tuning<br>
+ </a></u></h2>
+ <span style="text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span> Performance hints. <br>
+ <h2><u><a href="Overview.html">Overview</a></u></h2>
+ Overview of the software and its aims and functionality.<br>
+ <h2><u><a href="Limitations.html">Limitations</a></u></h2>
+ Limitations of the current functionality.<br>
+ <h2><u><a href="Organisation.html">Organization</a></u></h2>
+ How directories are organized, what they contain.
+ <h2><u><a href="Source.html">Source</a></u></h2>
+ Any detailed documentation on how the software works, or what
+ algorithms it is based on. (Very incomplete.)
+ <h2><u><a href="MinorTools.html">Minor Tools</a></u></h2>
+ A very brief description of minor tools and test harnesses. <br>
+ <br>
+ <br>
+ <h2><u><a name="FFormats"></a><a href="File_Formats.html">File
+ formats that Argyll uses</a></u></h2>
+ Argyll uses a number of file formats for its operation, some that
+ are external standards, and some that are unique to Argyll. <br>
+ <br>
<a href="File_Formats.html#.ti1">.ti1</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11135,10 +10907,8 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Device test values <br>
+
+ Device test values <br>
<a href="File_Formats.html#.ti2">.ti2</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11233,10 +11003,8 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Device test values &amp; chart layout <br>
+
+ Device test values &amp; chart layout <br>
<a href="File_Formats.html#.ti3">.ti3</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11331,14 +11099,12 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Device test values &amp; CIE tristimulus/spectral results&nbsp; <a
- href="ti3_format.html">Format details.</a><br>
- <a href="File_Formats.html#.cal">.cal</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Device
- calibration information. <a href="cal_format.html">Format details.</a><br>
+
+ Device test values &amp; CIE tristimulus/spectral results&nbsp; <a
+ href="ti3_format.html">Format details.</a><br>
+ <a href="File_Formats.html#.cal">.cal</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Device
+ calibration information. <a href="cal_format.html">Format details.</a><br>
<a href="File_Formats.html#.cht">.cht</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11433,11 +11199,9 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Test chart recognition template. <a href="cht_format.html">Format
- details.</a> <br>
+
+ Test chart recognition template. <a href="cht_format.html">Format
+ details.</a> <br>
<a href="File_Formats.html#.gam">.gam</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11532,10 +11296,8 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- 3D gamut surface description <br>
+
+ 3D gamut surface description <br>
<a href="File_Formats.html#.sp">.sp</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11630,18 +11392,16 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Illuminant spectral description <br>
- <a href="File_Formats.html#.cmf">.cmf</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Color Matching
- Functions<br>
- <a href="File_Formats.html#.ccmx">.ccmx</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Colorimeter Correction Matrix <br>
- <a href="File_Formats.html#.ccmx">.ccss</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Colorimeter Calibration
- Spectral Set <br>
+
+ Illuminant spectral description <br>
+ <a href="File_Formats.html#.cmf">.cmf</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Color Matching
+ Functions<br>
+ <a href="File_Formats.html#.ccmx">.ccmx</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Colorimeter Correction Matrix <br>
+ <a href="File_Formats.html#.ccmx">.ccss</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Colorimeter Calibration
+ Spectral Set <br>
<a href="File_Formats.html#CGATS">CGATS</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11736,10 +11496,8 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Standard text based data exchange format <br>
+
+ Standard text based data exchange format <br>
<a href="File_Formats.html#ICC">ICC</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11834,10 +11592,8 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- International Color Consortium profile format <br>
+
+ International Color Consortium profile format <br>
<a href="File_Formats.html#MPP">MPP</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -11932,10 +11688,8 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Model device profile format <br>
+
+ Model device profile format <br>
<a href="File_Formats.html#TIFF">TIFF</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -12030,10 +11784,8 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Tag Image File Format raster files. <br>
+
+ Tag Image File Format raster files. <br>
<a href="File_Formats.html#JPEG">JPEG</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -12128,15 +11880,13 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Joint Photographic Experts Group, JPEG File Interchange Format
- raster files. <br>
- <a href="doc/ucmm.html">ucmm</a> &nbsp;
- &nbsp;&nbsp;&nbsp; Unix micro Color Management Module convention and
- configuration file format and <span style="color: rgb(204, 0, 0);
- font-weight: bold;">Profile Locations</span>.<br>
+
+ Joint Photographic Experts Group, JPEG File Interchange Format
+ raster files. <br>
+ <a href="file:///D:/src/argyll/doc/ucmm.html">ucmm</a> &nbsp;
+ &nbsp;&nbsp;&nbsp; Unix micro Color Management Module convention and
+ configuration file format and <span style="color: rgb(204, 0, 0);
+ font-weight: bold;">Profile Locations</span>.<br>
<a href="File_Formats.html#VRML">VRML</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -12231,45 +11981,43 @@ href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">
-
-
-
- Virtual Reality Modelling Language 3D file format. <br>
- <a href="File_Formats.html#X3D">X3D</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open
- standards file format to represent 3D scenes using XML.<br>
- <a href="File_Formats.html#X3DOM">X3DOM</a> &nbsp;&nbsp;&nbsp;
- Open-source framework and runtime for 3D graphics on the Web.<br>
- <br>
- &nbsp;
- <h2><u>Errors, Corrections and Omissions:</u></h2>
- <script language="JavaScript">
-
-<!--
-
-// Comment
-
-var v1 = ".com"
-
-var v2 = "argyllcms"
-
-var v3 = "Graeme"
-
-var v4 = "@"
-
-var v5 = "mailto:"
-
-var v6 = v5 + v3 + v4 + v2 + v1
-
-document.write("<a href=" + v6 + ">" + "Let me know" + "</a>")
-
-//-->
-
-
-
-</script> If you notice any errors, corrections needed or omissions in
- the current documentation, please contact the author.<br>
- &nbsp; <br>
- &nbsp;<br>
- </body>
-</html>
+
+ Virtual Reality Modelling Language 3D file format. <br>
+ <a href="File_Formats.html#X3D">X3D</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open
+ standards file format to represent 3D scenes using XML.<br>
+ <a href="File_Formats.html#X3DOM">X3DOM</a> &nbsp;&nbsp;&nbsp;
+ Open-source framework and runtime for 3D graphics on the Web.<br>
+ <br>
+ &nbsp;
+ <h2><u>Errors, Corrections and Omissions:</u></h2>
+ <script language="JavaScript">
+
+<!--
+
+// Comment
+
+var v1 = ".com"
+
+var v2 = "argyllcms"
+
+var v3 = "Graeme"
+
+var v4 = "@"
+
+var v5 = "mailto:"
+
+var v6 = v5 + v3 + v4 + v2 + v1
+
+document.write("<a href=" + v6 + ">" + "Let me know" + "</a>")
+
+//-->
+
+
+
+</script> If you notice any errors, corrections needed or omissions in
+ the current documentation, please contact the author.<br>
+ &nbsp; <br>
+ &nbsp;<br>
+ </body>
+</html>
diff --git a/doc/ChangesSummary.html b/doc/ChangesSummary.html
index fb586e3..9bf9dca 100644
--- a/doc/ChangesSummary.html
+++ b/doc/ChangesSummary.html
@@ -16,50 +16,6 @@
<h1> Summary of Argyll CMS Changes since last release</h1>
<h3>For a <span style="text-decoration: underline;">complete</span>
and more detailed list of changes, please see the log.txt file.</h3>
- <h1>[V1.8.2 -&gt; V1.8.3] 26th October 2015</h1>
- <ul>
- <li>Added SpyderCheckr24 scaning .cht and .cie files.</li>
- <li>Fixed USB problem with i1pro (Rev B &amp; D ?), where
- communications would occasionally break down on fast systems.<br>
- </li>
- <li>Added another fixed display intergration time to i1pro
- non-adaptive emission mode to cope with higher brightness
- displays.</li>
- <li>Added workaround for i1d3 Rev. B status code 0x83 on very low
- light measurement</li>
- <li>Fixed minor bug in i1d3.c that truncated serial number string.
- (Thanks to Mikael Sterner).</li>
- <li>Fixed bug in Klein K10 driver - adaptive measurement wasn't
- properly using all the extra measurements.</li>
- <li>Improved Klein K10 driver to be more robust when lights off
- command returns bogus error codes, or causes a cascade of bogus
- measurement errors.<br>
- </li>
- <li>Added workaround for OS X 10.9+ "App Nap" problem.</li>
- <li>Added maximum sensor frequency check for Spyder &amp; i1d3
- drivers, so that erronious readings due to excessive brightness
- can't be missed.</li>
- <li>Changed chartread so that it doesn't warn of a possible wrong
- strip being read, nor allows bi-directional strip reading, if
- "printtarg -r" was used. A warning will be issued if "printtarg
- -r" was used, and "chartread -B" wasn't used.<br>
- </li>
- <li>Fixed collink for eeColor Full range RGB to use output curve
- ("second" 1D curves) to compensate for cLUT being wired for 1.0
- output from 1.0 input.<br>
- </li>
- <li>Added "lp" gamut mapping intent :- Luminance Preserving
- Perceptual, for Photographers concerned with maintaining tonal
- variations.</li>
- <li>Fixed bugs in image specific gamut mapping that were degrading
- the accuracy of the result.</li>
- <li>Re-wrote gamut smoothing code, and re-tuned it to behave
- similarly to the V1.8.2 release.</li>
- <li>Changed default viewing condition glare to 5%, to smooth out
- shadow tone curve.</li>
- <li>Reduced the level of Helmholtz-Kohlrausch effect in CIECAM02
- implementation in the light of visual experiments.</li>
- </ul>
<h1>[V1.8.1 -&gt; V1.8.2] 7th September 2015</h1>
<ul>
<li>Fixed endless loop bug in alternate calibration selectors
@@ -1030,7 +986,6 @@
-
</span>for systems with &gt; 3Gig Ram.</li>
<li>Add support for the Eye-One Monitor spectrometer.</li>
<li>Added -L option to <span style="font-weight: bold;">printtarg</span>
@@ -1071,7 +1026,6 @@
-
and memory usage issues.</li>
<li>Fixed issues with Eye-One Pro Rev B timeouts.</li>
<li>Added new option to collink -fk, that forces 000K input to K
diff --git a/doc/File_Formats.html b/doc/File_Formats.html
index ae59dd2..70a196a 100644
--- a/doc/File_Formats.html
+++ b/doc/File_Formats.html
@@ -99,7 +99,7 @@
spectral samples.<br>
<h2><a name=".cmf"></a>.cmf</h2>
Color Matching Functions. This is an ASCII text, <a
- href="File_Formats.html#CGATS">CGATS</a>,
+ href="file:///D:/src/argyll/doc/File_Formats.html#CGATS">CGATS</a>,
Argyll specific format, used to hold three spectral response curves
that define a tristimulus observer. The format is the same as a .sp
file.<i></i>
diff --git a/doc/Installing_OSX.html b/doc/Installing_OSX.html
index 76aa98a..fb01e4a 100644
--- a/doc/Installing_OSX.html
+++ b/doc/Installing_OSX.html
@@ -1,116 +1,116 @@
-<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html;
- charset=windows-1252">
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
- [Netscape]">
- <title>Argyll Installation on Apple OS X</title>
- </head>
- <body>
- <h1> <u>Installing the software on Apple OS X<br>
- </u></h1>
- <br>
- You will need to unpack the downloaded file in such a way that the
- files it contains end up in the location you have chosen to hold its
- contents.<br>
- <br>
- If you want to install it system wide, then you probably want to
- unpack it in the <i>/Applications</i> folder, so that it ends up in
- the <i>/Applications/Argyll_VX.X.X</i> folder.<br>
- Another option is just to install it somewhere under your $HOME
- folder, such as <span style="font-style: italic;">$HOME/</span><i>Argyll_VX.X.X</i>
- or <span style="font-style: italic;">$HOME/</span><i>bin/Argyll_VX.X.X</i>,
- depending on how you like to organize your applications and utility
- programs. ($HOME is the shell symbolic name for your home folder,
- typically /Users/<i>username</i>. Another abbreviation for it is the
- ~ character.)<br>
- <br>
- You can unpack it by control-click on the downloaded file and “Open
- With” BOMArchiveHelper or Archive Utility. Drag the resulting folder
- to where you want it, e.g. into <i>/Applications</i>, <i>$HOME</i>
- or <i>$HOME/bin</i>.<br>
- <br>
- Alternatively you can unpack it on the command line using&nbsp; the
- command <span style="font-weight: bold;">tar -zxf</span> <span
- style="font-weight: bold;">archivename.tgz</span>, which will
- create a folder <span style="font-weight: bold;">Argyll_VX.X.X</span>
- in your current folder, where X.X.X is the version number, and the
- executables will be in <span style="font-weight: bold;">Argyll_VX.X.X/bin</span>
- sub-folder.<br>
- <br>
- Open a Terminal shell. This will be in
- Applications-&gt;Utilities-&gt;Terminal (Dragging it to the dock is
- a good idea to make it more accessible).<br>
- <br>
- You should configure your $PATH environment variable to give the
- shell access to the executable from your command line environment
- without having to spell out the whole path every time, by editing
- your <span style="font-weight: bold;">.profile</span> file, which
- will be in your $HOME folder. You can open a graphical editor on
- this file by using the open command:<br>
- <br>
- &nbsp; open $HOME/.profile<br>
- <br>
- or alternatively, use some other text editor that you are familiar
- with.<br>
- <br>
- Add a line similar to the following line to your .profile file:<br>
- <br>
- &nbsp; PATH=$PATH:/Applications/Argyll_VX.X.X/bin<br>
- <br>
- where "/Applications/Argyll_VX.X.X/bin" is the path to the folder
- that contains the ArgyllCMS executables.<br>
- Save your changes and exit the editor.<br>
- <br>
- If you want further guidance in setting up and using a command line
- environment, then please consult an appropriate tutorial, e.g. &lt;<a
-href="http://heather.cs.ucdavis.edu/matloff/public_html/UnixAndC/Unix/ShellIntro.pdf">ShellIntro</a>&gt;.<br>
- <br>
- The .tgz file also contains several useful reference files (such as
- scanner chart recognition templates, sample illumination spectrum
- etc.) in the <b>ref</b> sub-folder, as well as all the current
- documentation in a <b>doc</b> sub-folder.<br>
- <br>
- For most devices there is nothing special to do. Plug in and go.
- Some devices may not work without some extra help though:<br>
- <h3><a name="ColorMunki"></a><span style="text-decoration:
- underline;">X-Rite ColorMunki</span></h3>
- Some version of X-Rite's ColorMunki drivers released between 2009
- and 2011 install an X-Rite daemon that runs as root and grabs the
- device, preventing any other programs (such as Argyll) from opening
- them. Latter versions seem to be more cooperative, and don't suffer
- from this problem. There are three ways of working around this
- problem:<br>
- <br>
- 1) Turn off the X-Rite service for the ColorMunki. See &lt;<a
- class="moz-txt-link-freetext"
-href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
- <br>
- 2) Run all Argyll programs that need to access the instrument as
- root. For instance:<br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo spotread<br>
- <br>
- and then you will be asked for the root password.<br>
- While these methods will work, they are inconvenient. <br>
- <br>
- 3) Alter the X-Rite drivers Daeomon so that it runs under your user
- account.<br>
- <br>
- To do this you need to edit the script that controls the X-Rite
- Daemon.<br>
- <br>
- &nbsp;&nbsp;&nbsp; cd ~<br>
- &nbsp;&nbsp;&nbsp; whoami<br>
- &nbsp;&nbsp;&nbsp; cp
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist temp.plist<br>
- &nbsp;&nbsp;&nbsp; open temp.plist<br>
- <br>
- and add one child below the root:<br>
- <br>
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=windows-1252">
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Installation on Apple OS X</title>
+ </head>
+ <body>
+ <h1> <u>Installing the software on Apple OS X<br>
+ </u></h1>
+ <br>
+ You will need to unpack the downloaded file in such a way that the
+ files it contains end up in the location you have chosen to hold its
+ contents.<br>
+ <br>
+ If you want to install it system wide, then you probably want to
+ unpack it in the <i>/Applications</i> folder, so that it ends up in
+ the <i>/Applications/Argyll_VX.X.X</i> folder.<br>
+ Another option is just to install it somewhere under your $HOME
+ folder, such as <span style="font-style: italic;">$HOME/</span><i>Argyll_VX.X.X</i>
+ or <span style="font-style: italic;">$HOME/</span><i>bin/Argyll_VX.X.X</i>,
+ depending on how you like to organize your applications and utility
+ programs. ($HOME is the shell symbolic name for your home folder,
+ typically /Users/<i>username</i>. Another abbreviation for it is the
+ ~ character.)<br>
+ <br>
+ You can unpack it by control-click on the downloaded file and “Open
+ With” BOMArchiveHelper or Archive Utility. Drag the resulting folder
+ to where you want it, e.g. into <i>/Applications</i>, <i>$HOME</i>
+ or <i>$HOME/bin</i>.<br>
+ <br>
+ Alternatively you can unpack it on the command line using&nbsp; the
+ command <span style="font-weight: bold;">tar -zxf</span> <span
+ style="font-weight: bold;">archivename.tgz</span>, which will
+ create a folder <span style="font-weight: bold;">Argyll_VX.X.X</span>
+ in your current folder, where X.X.X is the version number, and the
+ executables will be in <span style="font-weight: bold;">Argyll_VX.X.X/bin</span>
+ sub-folder.<br>
+ <br>
+ Open a Terminal shell. This will be in
+ Applications-&gt;Utilities-&gt;Terminal (Dragging it to the dock is
+ a good idea to make it more accessible).<br>
+ <br>
+ You should configure your $PATH environment variable to give the
+ shell access to the executable from your command line environment
+ without having to spell out the whole path every time, by editing
+ your <span style="font-weight: bold;">.profile</span> file, which
+ will be in your $HOME folder. You can open a graphical editor on
+ this file by using the open command:<br>
+ <br>
+ &nbsp; open $HOME/.profile<br>
+ <br>
+ or alternatively, use some other text editor that you are familiar
+ with.<br>
+ <br>
+ Add a line similar to the following line to your .profile file:<br>
+ <br>
+ &nbsp; PATH=$PATH:/Applications/Argyll_VX.X.X/bin<br>
+ <br>
+ where "/Applications/Argyll_VX.X.X/bin" is the path to the folder
+ that contains the ArgyllCMS executables.<br>
+ Save your changes and exit the editor.<br>
+ <br>
+ If you want further guidance in setting up and using a command line
+ environment, then please consult an appropriate tutorial, e.g. &lt;<a
+href="http://heather.cs.ucdavis.edu/matloff/public_html/UnixAndC/Unix/ShellIntro.pdf">ShellIntro</a>&gt;.<br>
+ <br>
+ The .tgz file also contains several useful reference files (such as
+ scanner chart recognition templates, sample illumination spectrum
+ etc.) in the <b>ref</b> sub-folder, as well as all the current
+ documentation in a <b>doc</b> sub-folder.<br>
+ <br>
+ For most devices there is nothing special to do. Plug in and go.
+ Some devices may not work without some extra help though:<br>
+ <h3><a name="ColorMunki"></a><span style="text-decoration:
+ underline;">X-Rite ColorMunki</span></h3>
+ Some version of X-Rite's ColorMunki drivers released between 2009
+ and 2011 install an X-Rite daemon that runs as root and grabs the
+ device, preventing any other programs (such as Argyll) from opening
+ them. Latter versions seem to be more cooperative, and don't suffer
+ from this problem. There are three ways of working around this
+ problem:<br>
+ <br>
+ 1) Turn off the X-Rite service for the ColorMunki. See &lt;<a
+ class="moz-txt-link-freetext"
+href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
+ <br>
+ 2) Run all Argyll programs that need to access the instrument as
+ root. For instance:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo spotread<br>
+ <br>
+ and then you will be asked for the root password.<br>
+ While these methods will work, they are inconvenient. <br>
+ <br>
+ 3) Alter the X-Rite drivers Daeomon so that it runs under your user
+ account.<br>
+ <br>
+ To do this you need to edit the script that controls the X-Rite
+ Daemon.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cd ~<br>
+ &nbsp;&nbsp;&nbsp; whoami<br>
+ &nbsp;&nbsp;&nbsp; cp
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist temp.plist<br>
+ &nbsp;&nbsp;&nbsp; open temp.plist<br>
+ <br>
+ and add one child below the root:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;">Item&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -121,10 +121,10 @@ Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs
-
- Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span><br>
- &nbsp;&nbsp;&nbsp; UserName &nbsp;
+
+ Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span><br>
+ &nbsp;&nbsp;&nbsp; UserName &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -135,63 +135,63 @@ string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n
-
- myusername<br>
- <br>
- where "myusername" is your username shown by whoami, and save the
- file. You then need to copy the modified file back: <br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo cp temp.plist
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
- <br>
- You will then need to restart the machine for this change to take
- effect, or invoke the following commands:<br>
- <br>
- &nbsp;&nbsp; sudo launchctl unload
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
- &nbsp;&nbsp; sudo launchctl load
- /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that after running
- Argyll tools, you may have to turn the X-Rite service off then on
- again, or disconnect and reconnect the instrument.<br>
- <br>
- <h3><a name="ColorMunki"></a><span style="text-decoration:
- underline;">X-Rite EyeOne Pro</span><br>
- </h3>
- Some version of X-Rite's EyeOne Pro drivers drivers released between
- 2009 and 2011 install an X-Rite daemon that runs as root and grabs
- the device, preventing any other programs (such as Argyll) from
- opening them. Latter versions seem to be more cooperative, and don't
- suffer from this problem. There are three ways of working around
- this problem:<br>
- <br>
- 1) Turn off the X-Rite service for the EyeOne Pro. See &lt;<a
- class="moz-txt-link-freetext"
-href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
- <br>
- 2) Run all Argyll programs that need to access the instrument as
- root. For instance:<br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo spotread<br>
- <br>
- and then you will be asked for the root password.<br>
- While these methods will work, they are inconvenient. <br>
- <br>
- 3) Alter the X-Rite drivers Daemon so that it runs under your user
- account.<br>
- <br>
- To do this you need to edit the script that controls the X-Rite
- Daemon.<br>
- <br>
- &nbsp;&nbsp;&nbsp; cd ~<br>
- &nbsp;&nbsp;&nbsp; whoami<br>
- &nbsp;&nbsp;&nbsp; cp
- /Library/LaunchDaemons/com.xrite.device.i1.plist temp.plist<br>
- &nbsp;&nbsp;&nbsp; open temp.plist<br>
- <br>
- and add one child below the root:<br>
- <br>
+
+ myusername<br>
+ <br>
+ where "myusername" is your username shown by whoami, and save the
+ file. You then need to copy the modified file back: <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo cp temp.plist
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+ <br>
+ You will then need to restart the machine for this change to take
+ effect, or invoke the following commands:<br>
+ <br>
+ &nbsp;&nbsp; sudo launchctl unload
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+ &nbsp;&nbsp; sudo launchctl load
+ /Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that after running
+ Argyll tools, you may have to turn the X-Rite service off then on
+ again, or disconnect and reconnect the instrument.<br>
+ <br>
+ <h3><a name="ColorMunki"></a><span style="text-decoration:
+ underline;">X-Rite EyeOne Pro</span><br>
+ </h3>
+ Some version of X-Rite's EyeOne Pro drivers drivers released between
+ 2009 and 2011 install an X-Rite daemon that runs as root and grabs
+ the device, preventing any other programs (such as Argyll) from
+ opening them. Latter versions seem to be more cooperative, and don't
+ suffer from this problem. There are three ways of working around
+ this problem:<br>
+ <br>
+ 1) Turn off the X-Rite service for the EyeOne Pro. See &lt;<a
+ class="moz-txt-link-freetext"
+href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
+ <br>
+ 2) Run all Argyll programs that need to access the instrument as
+ root. For instance:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo spotread<br>
+ <br>
+ and then you will be asked for the root password.<br>
+ While these methods will work, they are inconvenient. <br>
+ <br>
+ 3) Alter the X-Rite drivers Daemon so that it runs under your user
+ account.<br>
+ <br>
+ To do this you need to edit the script that controls the X-Rite
+ Daemon.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cd ~<br>
+ &nbsp;&nbsp;&nbsp; whoami<br>
+ &nbsp;&nbsp;&nbsp; cp
+ /Library/LaunchDaemons/com.xrite.device.i1.plist temp.plist<br>
+ &nbsp;&nbsp;&nbsp; open temp.plist<br>
+ <br>
+ and add one child below the root:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;">Item&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -202,10 +202,10 @@ Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs
-
- Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- </span><br>
- &nbsp;&nbsp;&nbsp; UserName &nbsp;
+
+ Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span><br>
+ &nbsp;&nbsp;&nbsp; UserName &nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -216,27 +216,27 @@ string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n
-
- myusername<br>
- <br>
- where "myusername" is your username shown by whoami, and save the
- file. You then need to copy the modified file back: <br>
- <br>
- &nbsp;&nbsp;&nbsp; sudo cp temp.plist
- /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
- <br>
- You will then need to restart the machine for this change to take
- effect, or invoke the following commands:<br>
- <br>
- &nbsp;&nbsp; sudo launchctl unload
- /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
- &nbsp;&nbsp; sudo launchctl load
- /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that after running
- Argyll tools, you may have to turn the X-Rite service off then on
- again, or disconnect and reconnect the instrument.<br>
- <br>
+
+ myusername<br>
+ <br>
+ where "myusername" is your username shown by whoami, and save the
+ file. You then need to copy the modified file back: <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; sudo cp temp.plist
+ /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+ <br>
+ You will then need to restart the machine for this change to take
+ effect, or invoke the following commands:<br>
+ <br>
+ &nbsp;&nbsp; sudo launchctl unload
+ /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+ &nbsp;&nbsp; sudo launchctl load
+ /Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that after running
+ Argyll tools, you may have to turn the X-Rite service off then on
+ again, or disconnect and reconnect the instrument.<br>
+ <br>
<h3><a name="specbos"></a><span style="text-decoration: underline;">JETI
specbos
@@ -247,69 +247,69 @@ specbos
-
- 1201 and 1211</span> and <u>Klein K10A</u><br>
- </h3>
- <br>
- If you are using the <b>JETI</b> specbos <span style="font-weight:
- bold;">1211</span><span style="font-weight: bold;"> </span>and <b>1201</b>,
- or the <b>Klein K10A</b> then you may need to install the <a
- href="http://www.ftdichip.com/Drivers/VCP.htm">FTDI Virtual COM
- Port Drivers</a> (VCP), if they are not already on your system.<br>
- <br>
- <h3><a name="HCFR"></a><u>HCFR Colorimeter</u></h3>
- The default OS X class drivers will grab this device, preventing
- Argyll from accessing it. To overcome this, you need to install a
- codeless kernel extension if you wish to use the HCFR colorimeter,
- that prevents this from happening. From the command line you need to
- create a folder called Argyll.kext somewhere convenient, and then
- place in it one file called Info.plist, containing the following:<br>
- <br>
- &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
- &nbsp;&nbsp; &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>
- &nbsp;&nbsp; &lt;!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST
- 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;<br>
- &nbsp;&nbsp; &lt;plist version="1.0"&gt;<br>
- &nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp; &nbsp;&nbsp; &nbsp;
- &lt;key&gt;CFBundleDevelopmentRegion&lt;/key&gt;
- &lt;string&gt;English&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp;
- &lt;key&gt;CFBundleGetInfoString&lt;/key&gt; &lt;string&gt;Libusb
- USB device Shield&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
- &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
- &lt;string&gt;com.libusb.USB_Shield&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp;
- &lt;key&gt;CFBundleInfoDictionaryVersion&lt;/key&gt;
- &lt;string&gt;6.0&lt;/string&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleName&lt;/key&gt;
- &lt;string&gt;Libusb USB device Shield&lt;/string&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp;
- &lt;key&gt;CFBundlePackageType&lt;/key&gt;
- &lt;string&gt;KEXT&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;CFBundleSignature&lt;/key&gt;
- &lt;string&gt;????&lt;/string&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleVersion&lt;/key&gt;
- &lt;string&gt;6.0&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
- &lt;key&gt;IOKitPersonalities&lt;/key&gt;<br>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
- &lt;key&gt;HCFR&lt;/key&gt;<br>
- &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
- &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
- &lt;string&gt;com.apple.driver.AppleUSBComposite&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp; &lt;key&gt;IOClass&lt;/key&gt;
- &lt;string&gt;AppleUSBComposite&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
- &nbsp; &lt;key&gt;IOProviderClass&lt;/key&gt;
- &lt;string&gt;IOUSBDevice&lt;/string&gt;<br>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp; &lt;key&gt;idVendor&lt;/key&gt;
- &lt;integer&gt;1243&lt;/integer&gt;<br>
+
+ 1201 and 1211</span> and <u>Klein K10A</u><br>
+ </h3>
+ <br>
+ If you are using the <b>JETI</b> specbos <span style="font-weight:
+ bold;">1211</span><span style="font-weight: bold;"> </span>and <b>1201</b>,
+ or the <b>Klein K10A</b> then you may need to install the <a
+ href="http://www.ftdichip.com/Drivers/VCP.htm">FTDI Virtual COM
+ Port Drivers</a> (VCP), if they are not already on your system.<br>
+ <br>
+ <h3><a name="HCFR"></a><u>HCFR Colorimeter</u></h3>
+ The default OS X class drivers will grab this device, preventing
+ Argyll from accessing it. To overcome this, you need to install a
+ codeless kernel extension if you wish to use the HCFR colorimeter,
+ that prevents this from happening. From the command line you need to
+ create a folder called Argyll.kext somewhere convenient, and then
+ place in it one file called Info.plist, containing the following:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
+ &nbsp;&nbsp; &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>
+ &nbsp;&nbsp; &lt;!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST
+ 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;<br>
+ &nbsp;&nbsp; &lt;plist version="1.0"&gt;<br>
+ &nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;
+ &lt;key&gt;CFBundleDevelopmentRegion&lt;/key&gt;
+ &lt;string&gt;English&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp;
+ &lt;key&gt;CFBundleGetInfoString&lt;/key&gt; &lt;string&gt;Libusb
+ USB device Shield&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
+ &lt;string&gt;com.libusb.USB_Shield&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp;
+ &lt;key&gt;CFBundleInfoDictionaryVersion&lt;/key&gt;
+ &lt;string&gt;6.0&lt;/string&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleName&lt;/key&gt;
+ &lt;string&gt;Libusb USB device Shield&lt;/string&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp;
+ &lt;key&gt;CFBundlePackageType&lt;/key&gt;
+ &lt;string&gt;KEXT&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;CFBundleSignature&lt;/key&gt;
+ &lt;string&gt;????&lt;/string&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleVersion&lt;/key&gt;
+ &lt;string&gt;6.0&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &lt;key&gt;IOKitPersonalities&lt;/key&gt;<br>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+ &lt;key&gt;HCFR&lt;/key&gt;<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
+ &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
+ &lt;string&gt;com.apple.driver.AppleUSBComposite&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp; &lt;key&gt;IOClass&lt;/key&gt;
+ &lt;string&gt;AppleUSBComposite&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
+ &nbsp; &lt;key&gt;IOProviderClass&lt;/key&gt;
+ &lt;string&gt;IOUSBDevice&lt;/string&gt;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; &lt;key&gt;idVendor&lt;/key&gt;
+ &lt;integer&gt;1243&lt;/integer&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -319,36 +319,36 @@ specbos
-
- &nbsp; &lt;key&gt;idProduct&lt;/key&gt;
- &lt;integer&gt;91&lt;/integer&gt;<br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &lt;/dict&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp; &lt;/dict&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp;
- &lt;key&gt;OSBundleCompatibleVersion&lt;/key&gt;
- &lt;string&gt;1.8&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;OSBundleLibraries&lt;/key&gt;<br>
- &nbsp; &nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
- &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &lt;key&gt;com.apple.kernel.iokit&lt;/key&gt;
- &lt;string&gt;6.0&lt;/string&gt;<br>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dict&gt;<br>
- &nbsp;&nbsp; &lt;/dict&gt;<br>
- &nbsp;&nbsp; &lt;/plist&gt;<br>
- &nbsp; &nbsp; ----------------- cut here ---------------------<br>
- <br>
- (You can also copy this from the source installation in
- usb/Argyll.kext)<br>
- <br>
- You then need to install it by using:<br>
- <br>
- &nbsp; sudo cp -R Argyll.kext /System/Library/Extensions<br>
- <br>
- supplying the appropriate root password when prompted.<br>
- Reboot the system to activate the extension.<br>
- <br>
- <p><br>
- </p>
- </body>
-</html>
+
+ &nbsp; &lt;key&gt;idProduct&lt;/key&gt;
+ &lt;integer&gt;91&lt;/integer&gt;<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &lt;/dict&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp; &lt;/dict&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp;
+ &lt;key&gt;OSBundleCompatibleVersion&lt;/key&gt;
+ &lt;string&gt;1.8&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;OSBundleLibraries&lt;/key&gt;<br>
+ &nbsp; &nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
+ &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &lt;key&gt;com.apple.kernel.iokit&lt;/key&gt;
+ &lt;string&gt;6.0&lt;/string&gt;<br>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dict&gt;<br>
+ &nbsp;&nbsp; &lt;/dict&gt;<br>
+ &nbsp;&nbsp; &lt;/plist&gt;<br>
+ &nbsp; &nbsp; ----------------- cut here ---------------------<br>
+ <br>
+ (You can also copy this from the source installation in
+ usb/Argyll.kext)<br>
+ <br>
+ You then need to install it by using:<br>
+ <br>
+ &nbsp; sudo cp -R Argyll.kext /System/Library/Extensions<br>
+ <br>
+ supplying the appropriate root password when prompted.<br>
+ Reboot the system to activate the extension.<br>
+ <br>
+ <p><br>
+ </p>
+ </body>
+</html>
diff --git a/doc/Scenarios.html b/doc/Scenarios.html
index c8bb154..8cd45c9 100644
--- a/doc/Scenarios.html
+++ b/doc/Scenarios.html
@@ -1,134 +1,134 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>Argyll Usage Scenarios</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- </head>
- <body>
- <h2><u>Typical usage Scenarios and Examples</u></h2>
- Choose a task from the list below. For more details on alternative
- options, follow the links to the individual tools being used.<br>
- <br>
- Note that by default it is assumed that ICC profile have the file
- extension <span style="font-weight: bold;">.icm</span>, but that on
- Apple OS X and Unix/Linux platforms, the <span style="font-weight:
- bold;">.icc</span> extension is expected and should be used.<br>
- <h4><a href="#PM1">Profiling Displays</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1a">Checking you can access your
- display<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1b">Adjusting and Calibrating a
- displays</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1c">Adjusting, calibrating and
- profiling in one step<br>
- </a><span style="font-weight: bold;"></span><span
- style="font-weight: bold;"></span><span style="text-decoration:
- underline;"></span></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PM2">Creating display test values</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PM3">Taking readings from a
- display</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PM4">Creating a display profile</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
- href="#PM5">Installing a display profile</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
- href="#PM6">Expert tips when measuring displays</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
- href="#PM7">Calibrating and profiling a display that doesn't
- have VideoLUT access.</a></h4>
- <h4><br>
- <a href="#PS1">Profiling Scanners and other input devices such as
- cameras<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PS2">Types of test charts</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PS3">Taking readings from a
- scanner</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PS4">Creating a scanner profile</a></h4>
- <h4><br>
- <a href="#PP1">Profiling Printers</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PP2">Creating a print profile
- test chart</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PP2b">Printing a
- print profile test chart</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PP3">Reading a print test chart
- using an instrument</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="#PP4">Reading a print test chart
- using a scanner</a></h4>
- <h4> </h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PP5">Creating a printer profile<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PP6">Choosing a black generation
- curve</a></h4>
- <br>
- <h4><a href="Scenarios.html#PC1">Calibrating Printers</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC2">Calibrated
- print workflows</a></h4>
- <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC3">Creating a
- print calibration test chart</a></h4>
- <h4> </h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC4">Creating a
- printer calibration<br>
- </a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC5">Using a printer
- calibration</a></h4>
- <h4>&nbsp;&nbsp;&nbsp; <a href="#PC6">How profile ink limits are
- handled when calibration is being used<br>
- </a></h4>
- <h4> <a href="#LP1">Linking Profiles</a></h4>
- <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Image dependent gamut
- mapping using device links</a></b><br>
- </p>
- <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Soft Proofing Link</a></b><br>
- </p>
- <h4> <a href="#TR1">Transforming colorspaces of raster files</a></h4>
- <h4></h4>
- <h4> <a href="#TV1">Creating Video Calibration 3DLuts</a></h4>
- <h4><a href="Scenarios.html#TV2">Verifying Video Calibration 3DLuts</a></h4>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <h3><a name="PM1"></a>Profiling Displays</h3>
- Argyll supports adjusting, calibrating and profiling of displays
- using one of a number of instruments - see <a
- href="instruments.html">instruments</a> for a current list.&nbsp;
- Adjustment and calibration are prior steps to profiling, in which
- the display is adjusted using it's screen controls,&nbsp; and then
- per channel lookup tables are created to make it meet a well behaved
- response of the desired type. The&nbsp; process following that of
- creating a display profile is then similar to that of all other
- output devices :- first a set of device colorspace test values needs
- to be created to exercise the display, then these values need to be
- displayed, while taking measurements of the resulting colors using
- the instrument. Finally, the device value/measured color values need
- to be converted into an ICC profile.<br>
- <br>
- <h3><a name="PM1a"></a>Checking you can access your display<br>
- </h3>
- You might first want to check that you are accessing and can
- calibrate your display. You can do this using the <a
- href="dispwin.html">dispwin</a><span style="font-weight: bold;"></span>
- tool<span style="font-weight: bold;">.</span> If you just run <span
- style="font-weight: bold;">dispwin</span> it will create a test
- window and run through a series of test colors before checking that
- the VideoLUT can be accessed by the display. If you invoke the usage
- for <span style="font-weight: bold;">dispwin</span> (by giving it
- an unrecognized option, e.g. <span style="font-weight: bold;">-?</span>)
- then it will show a list of available displays next to the <span
- style="font-weight: bold;"><span style="font-weight: bold;">-d</span></span>
- flag. Make sure that you are accessing the display you intend to
- calibrate and profile, and that the VideoLUT is effective (the <span
- style="font-weight: bold;">-r</span> flag can be used to just run
- the VideoLUT test). You can also try clearing the VideoLUTs using
- the <span style="font-weight: bold;">-c</span> flag, and loading a
- deliberately strange looking calibration <span style="font-weight:
- bold;">strange.cal</span> that is provided in the Argyll <span
- style="font-weight: bold;">ref</span> directory.<br>
- <br>
- Note that calibrating and/or profiling <span style="font-weight:
- bold;">remote</span> displays is possible using X11 or a web
- browser (see <span style="font-weight: bold;">-d</span> option of
- dispcal and dispread), or by using some external program to send
- test colors to a display (see <span style="font-weight: bold;">-C</span>
- and <span style="font-weight: bold;">-M</span> options of dispcal
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Argyll Usage Scenarios</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ </head>
+ <body>
+ <h2><u>Typical usage Scenarios and Examples</u></h2>
+ Choose a task from the list below. For more details on alternative
+ options, follow the links to the individual tools being used.<br>
+ <br>
+ Note that by default it is assumed that ICC profile have the file
+ extension <span style="font-weight: bold;">.icm</span>, but that on
+ Apple OS X and Unix/Linux platforms, the <span style="font-weight:
+ bold;">.icc</span> extension is expected and should be used.<br>
+ <h4><a href="#PM1">Profiling Displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1a">Checking you can access your
+ display<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1b">Adjusting and Calibrating a
+ displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1c">Adjusting, calibrating and
+ profiling in one step<br>
+ </a><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span><span style="text-decoration:
+ underline;"></span></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM2">Creating display test values</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PM3">Taking readings from a
+ display</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PM4">Creating a display profile</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM5">Installing a display profile</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM6">Expert tips when measuring displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM7">Calibrating and profiling a display that doesn't
+ have VideoLUT access.</a></h4>
+ <h4><br>
+ <a href="#PS1">Profiling Scanners and other input devices such as
+ cameras<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS2">Types of test charts</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS3">Taking readings from a
+ scanner</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS4">Creating a scanner profile</a></h4>
+ <h4><br>
+ <a href="#PP1">Profiling Printers</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP2">Creating a print profile
+ test chart</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PP2b">Printing a
+ print profile test chart</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP3">Reading a print test chart
+ using an instrument</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP4">Reading a print test chart
+ using a scanner</a></h4>
+ <h4> </h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PP5">Creating a printer profile<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PP6">Choosing a black generation
+ curve</a></h4>
+ <br>
+ <h4><a href="Scenarios.html#PC1">Calibrating Printers</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC2">Calibrated
+ print workflows</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC3">Creating a
+ print calibration test chart</a></h4>
+ <h4> </h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC4">Creating a
+ printer calibration<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC5">Using a printer
+ calibration</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PC6">How profile ink limits are
+ handled when calibration is being used<br>
+ </a></h4>
+ <h4> <a href="#LP1">Linking Profiles</a></h4>
+ <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Image dependent gamut
+ mapping using device links</a></b><br>
+ </p>
+ <p>&nbsp;&nbsp;&nbsp; <b><a href="#LP2">Soft Proofing Link</a></b><br>
+ </p>
+ <h4> <a href="#TR1">Transforming colorspaces of raster files</a></h4>
+ <h4></h4>
+ <h4> <a href="#TV1">Creating Video Calibration 3DLuts</a></h4>
+ <h4><a href="Scenarios.html#TV2">Verifying Video Calibration 3DLuts</a></h4>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <h3><a name="PM1"></a>Profiling Displays</h3>
+ Argyll supports adjusting, calibrating and profiling of displays
+ using one of a number of instruments - see <a
+ href="instruments.html">instruments</a> for a current list.&nbsp;
+ Adjustment and calibration are prior steps to profiling, in which
+ the display is adjusted using it's screen controls,&nbsp; and then
+ per channel lookup tables are created to make it meet a well behaved
+ response of the desired type. The&nbsp; process following that of
+ creating a display profile is then similar to that of all other
+ output devices :- first a set of device colorspace test values needs
+ to be created to exercise the display, then these values need to be
+ displayed, while taking measurements of the resulting colors using
+ the instrument. Finally, the device value/measured color values need
+ to be converted into an ICC profile.<br>
+ <br>
+ <h3><a name="PM1a"></a>Checking you can access your display<br>
+ </h3>
+ You might first want to check that you are accessing and can
+ calibrate your display. You can do this using the <a
+ href="dispwin.html">dispwin</a><span style="font-weight: bold;"></span>
+ tool<span style="font-weight: bold;">.</span> If you just run <span
+ style="font-weight: bold;">dispwin</span> it will create a test
+ window and run through a series of test colors before checking that
+ the VideoLUT can be accessed by the display. If you invoke the usage
+ for <span style="font-weight: bold;">dispwin</span> (by giving it
+ an unrecognized option, e.g. <span style="font-weight: bold;">-?</span>)
+ then it will show a list of available displays next to the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">-d</span></span>
+ flag. Make sure that you are accessing the display you intend to
+ calibrate and profile, and that the VideoLUT is effective (the <span
+ style="font-weight: bold;">-r</span> flag can be used to just run
+ the VideoLUT test). You can also try clearing the VideoLUTs using
+ the <span style="font-weight: bold;">-c</span> flag, and loading a
+ deliberately strange looking calibration <span style="font-weight:
+ bold;">strange.cal</span> that is provided in the Argyll <span
+ style="font-weight: bold;">ref</span> directory.<br>
+ <br>
+ Note that calibrating and/or profiling <span style="font-weight:
+ bold;">remote</span> displays is possible using X11 or a web
+ browser (see <span style="font-weight: bold;">-d</span> option of
+ dispcal and dispread), or by using some external program to send
+ test colors to a display (see <span style="font-weight: bold;">-C</span>
+ and <span style="font-weight: bold;">-M</span> options of dispcal
and dispread), but you may want to refer to <a href="#PM7">Calibrating
@@ -181,29 +181,27 @@
-
-
-
- and profiling a display that doesn't have VideoLUT access</a>.<br>
- <br>
- <h3><a name="PM1b"></a>Adjusting and Calibrating Displays</h3>
- Please read <a href="calvschar.html">What's the difference between
- Calibration and Characterization ?</a> if you are unclear as to
- the difference .<br>
- <br>
- The first step is to decide what the target should be for adjustment
- and calibration. This boils down to three things: The desired
- brightness, the desired white point, and the desired response curve.
- The native brightness and white points of a display may be different
- to the desired characteristics for some purposes. For instance, for
- graphic arts use, it might be desirable to run with a warmer white
- point of about 5000 degrees Kelvin, rather than the default display
- white point of 6500 to 9000 Kelvin. Some LCD displays are too bright
- to compare to printed material under available lighting, so it might
- be desirable to reduce the maximum brightness.<br>
- <br>
- You can run <a href="dispcal.html#r">dispcal -r</a> to check on how
- your display is currently set up. (you may have to run this as <span
+
+ and profiling a display that doesn't have VideoLUT access</a>.<br>
+ <br>
+ <h3><a name="PM1b"></a>Adjusting and Calibrating Displays</h3>
+ Please read <a href="calvschar.html">What's the difference between
+ Calibration and Characterization ?</a> if you are unclear as to
+ the difference .<br>
+ <br>
+ The first step is to decide what the target should be for adjustment
+ and calibration. This boils down to three things: The desired
+ brightness, the desired white point, and the desired response curve.
+ The native brightness and white points of a display may be different
+ to the desired characteristics for some purposes. For instance, for
+ graphic arts use, it might be desirable to run with a warmer white
+ point of about 5000 degrees Kelvin, rather than the default display
+ white point of 6500 to 9000 Kelvin. Some LCD displays are too bright
+ to compare to printed material under available lighting, so it might
+ be desirable to reduce the maximum brightness.<br>
+ <br>
+ You can run <a href="dispcal.html#r">dispcal -r</a> to check on how
+ your display is currently set up. (you may have to run this as <span
style="text-decoration: underline; color: rgb(204, 51, 204);">dispcal
-yl
@@ -262,334 +260,332 @@
-
-
-
- -r</span> for an LCD display, or <span style="text-decoration:
- underline; color: rgb(204, 51, 204);">dispcal -yc -r</span> for a
- CRT display with most of the colorimeter instruments. If so, this
- will apply to all of the following examples.)<br>
- <br>
- Once this is done, <a href="dispcal.html">dispcal</a> can be run to
- guide you through the display adjustments, and then calibrate it. By
- default, the brightness and white point will be kept the same as the
- devices natural brightness and white point. The default response
- curve is a gamma of 2.4, except for Apple OS X systems prior to 10.6
- where a gamma of 1.8 is the default. 2.4 is close to that of&nbsp;
- many monitors, and close to that of the sRGB colorspace. <br>
- <br>
- A typical calibration that leaves the brightness and white point
- alone, might be:<br>
- <br>
- <a href="dispcal.html">dispcal</a> -v TargetA<br>
- <br>
- which will result in a "TargetA.cal" calibration file, that can then
- be used during the profiling stage.<br>
- <br>
- If the absolutely native response of the display is desired during
- profiling, then calibration should be skipped, and the linear.cal
- file from the "ref" directory used instead as the argument to the -k
- flag of <span style="font-weight: bold;">dispread</span>.<br>
- <br>
- <b>Dispcal</b> will display a test window in the middle of the
- screen, and issue a series of instructions about placing the
- instrument on the display. You may need to make sure that the
- display cursor is not in the test window, and it may also be
- necessary to disable any screensaver and powersavers before starting
- the process, although both <span style="font-weight: bold;">dispcal</span>
- and <span style="font-weight: bold;">dispread</span> will attempt
- to do this for you. It's also highly desirable on CRT's, to clear
- your screen of any white or bright background images or windows
- (running your shell window with white text on a black background
- helps a lot here.), or at least keep any bright areas away from the
- test window, and be careful not to change anything on the display
- while the readings are taken. Lots of bright images or windows can
- affect the ability to measure the black point accurately, and
- changing images on the display can cause inconsistency in the
- readings,&nbsp; and leading to poor results.<span
- style="font-weight: bold;"></span> LCD displays seem to be less
- influenced by what else is on the screen.<br>
- <br>
- If <span style="font-weight: bold;">dispcal</span> is run without
- arguments, it will provide a usage screen. The <span
- style="font-weight: bold;">-c</span> parameter allows selecting a
- communication port for an instrument, or selecting the instrument
- you want to use,&nbsp; and the <a href="dispcal.html#d"><span
- style="font-weight: bold;">-d</span></a> option allows selecting
- a target display on a multi-display system. On some multi-monitor
- systems, it may not be possible to independently calibrate and
- profile each display if they appear as one single screen to the
- operating system, or if it is not possible to set separate video
- lookup tables for each display. You can change the position and size
- of the test window using the <a href="dispcal.html#P"><span
- style="font-weight: bold;">-P</span></a> parameter. You can
- determine how best to arrange the test window, as well as whether
- each display has separate video lookup capability, by experimenting
- with the <a href="dispwin.html">dispwin</a> tool. <br>
- <br>
- For a more detailed discussion on interactively adjusting the
- display controls using <span style="font-weight: bold;">dispcal</span>,
- see <a href="dispcal.html#Adjustment">dispcal-adjustment</a>. Once
- you have adjusted and calibrated your display, you can move on to
- the next step.<br>
- <br>
- When you have calibrated and profiled your display, you can keep it
- calibrated using the <a href="dispcal.html#u">dispcal -u</a>
- option.<br>
- <br>
- <h4><a name="PM1c"></a>Adjusting, calibrating and profiling in one
- step.</h4>
- If a simple matrix/shaper display profile is all that is desired, <span
- style="font-weight: bold;">dispcal</span> can be used to do this,
- permitting display adjustment, calibration and profiling all in one
- operation. This is done by using the <span style="font-weight:
- bold;"><span style="font-weight: bold;">dispcal </span>-o</span>
- flag:<br>
- <br>
- <a href="dispcal.html">dispcal</a> <a href="dispcal.html#v">-v</a>
- <a href="dispcal.html#o">-o</a> <a href="dispcal.html#p1">TargetA</a><br>
- <br>
- This will create both a TargetA.cal file, but also a TargetA.icm
- file. See <a href="dispcal.html#o">-o</a> and <a
- href="dispcal.html#O">-O</a> for other variations.<br>
- <br>
- For more flexibility in creating a display profile, the separate
- steps of creating characterization test values using <span
- style="font-weight: bold;">targen</span>, reading them from the
- display using <span style="font-weight: bold;">dispread</span>, and
- then creating a profile using <span style="font-weight: bold;">colprof</span>
- are used. The following steps illustrate this:<br>
- <h4><a name="PM2"></a>Profiling in several steps: Creating display
- test values</h4>
- If the <span style="font-weight: bold;">dispcal</span> has not been
- used to create a display profile at the same time as adjustment and
- calibration, then it can be used to create a suitable set of
- calibration curves as the first step, or the calibration step can be
- omitted, and the display cansimply be profiled.<br>
- <br>
- The first step in profiling any output device, is to create a set of
- device colorspace test values. The important parameters needed are:
- <br>
- <ul>
- <li>What colorspace does the device use ?</li>
- <li>How many test patches do I want to use ?</li>
- <li>What information do I already have about how the device
- behaves ?</li>
- </ul>
- For a display device, &nbsp;the colorspace will be RGB. The number
- of test patches will depend somewhat on what quality profile you
- want to make, what type of profile you want to make, and how long
- you are prepared to wait when testing the display.<br>
- At a minimum, a few hundred values are needed. A matrix/shaper type
- of profile can get by with fewer test values, while a LUT based
- profile will give better results if more test values are used. A
- typical number might be 200-600 or so values, while 1000-2000 is not
- an unreasonable number for a high quality characterization of a
- display.<br>
- <br>
- To assist the choice of test patch values, it can help to have a
- rough idea of how the device behaves. This could be in the form of
- an ICC profile of a similar device, or a lower quality, or previous
- profile for that particular device. If one were going to make a very
- high quality LUT based profile, then it might be worthwhile to make
- up a smaller, preliminary shaper/matrix profile using a few hundred
- test points, before embarking on testing the device with several
- thousand.<br>
- <br>
- Lets say that we ultimately want to make a profile for the device
- "DisplayA", the simplest approach is to make a set of test values
- that is independent of the characteristics of the particular device:<br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
- <a href="targen.html#p1">DisplayA</a><br>
- <br>
- If there is a preliminary or previous profile called "OldDisplay"
- available, and we want to try creating a "pre-conditioned" set of
- test values that will more efficiently sample the device response,
- then the following would achieve this:<br>
- <u><br>
- </u><a href="targen.html"> targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
- <a href="targen.html#c">-cOldDisplay.icm</a> <a
- href="targen.html#p1">DisplayA</a><br>
- <br>
- The output of <b>targen</b> will be the file DisplayA.ti1,
- containing the device space test values, as well as expected CIE
- values used for chart recognition purposes.<br>
- <br>
- <h4><a name="PM3"></a>Profiling in several steps: Taking readings
- from a display</h4>
- First it is necessary to connect your measurement instrument to your
- computer, and check which communication port it is connected to. In
- the following example, it is assumed that the instrument is
- connected to the default port 1, which is either the first USB
- instrument found, or serial port found. Invoking dispread so as to
- display the usage information (by using a flag -? or --) will list
- the identified serial and USB ports, and their labels.<br>
- <br>
- <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
- <a href="dispread.html#p1">DisplayA</a><br>
- <br>
- If we created a calibration for the display using <a
- href="dispcal.html">dispcal</a>, then we will want to use this
- when we take the display readings (e.g. TargetA.cal from the
- calibration example)..<br>
- <br>
- <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
- <a href="dispread.html#k">-k TargetA.cal</a> <a
- href="dispread.html#p1">DisplayA</a><br>
- <br>
- <b>dispread</b> will display a test window in the middle of the
- screen, and issue a series of instructions about placing the
- instrument on the display. You may need to make sure that the
- display cursor is not in the test window, and it may also be
- necessary to disable any screensaver before starting the process.
- Exactly the same facilities are provided to select alternate
- displays using the <span style="font-weight: bold;">-d</span>
- parameter, and an alternate location and size for the test window
- using the <span style="font-weight: bold;">-P</span> parameter as
- with <span style="font-weight: bold;">dispcal</span>.<br>
- <h4><a name="PM4"></a>Profiling in several steps: Creating a display
- profile</h4>
- There are two basic choices of profile type for a display, a
- shaper/matrix profile, or a LUT based profile. They have different
- tradeoffs. A shaper/matrix profile will work well on a well behaved
- display, that is one that behaves in an additive color manner, will
- give very smooth looking results, and needs fewer test points to
- create. A LUT based profile on the other hand, will model any
- display behaviour more accurately, and can accommodate gamut mapping
- and different intent tables. Often it can show some unevenness and
- contouring in the results though.<br>
- <br>
- To create a matrix/shaper profile, the following suffices:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-as</a> <a href="colprof.html#p1">DisplayA</a><br>
- <br>
- For a LUT based profile, where gamut mapping is desired, then a
- source profile will need to be provided to define the source gamut.
- For instance, if the display profile was likely to be linked to a
- CMYK printing source profile, say "swop.icm" or "fogra39l.icm", then
- the following would suffice:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S">
- fogra39l.icm</a> <a href="colprof.html#c">-cpp</a> <a
- href="colprof.html#d">-dmt</a> <a href="colprof.html#p1">DisplayA</a><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably.<br>
- If a calibration file was used with <a href="dispread.html">dispread</a>,
- then it will be converted to a vcgt tag in the profile, so that the
- operating system or other system color tools load the lookup curves
- into the display hardware, when the profile is used.<br>
- <h4><a name="PM5"></a>Installing a display profile</h4>
- <a href="dispwin.html">dispwin</a> provides a convenient way of
- installing a profile as the default system profile for the chosen
- display:<br>
- <br>
- <a href="dispwin.html">dispwin</a> <a href="dispwin.html#I">-I</a>
- <a href="dispwin.html#p1">DisplayA.icm</a><br>
- <br>
- This also sets the display to the calibration contained in the
- profile. If you want to try out a calibration before installing the
- profile, using dispwin without the <span style="font-weight: bold;">-I</span>
- option will load a calibration (ICC profile or .cal file) into the
- current display.<br>
- <br>
- Some systems will automatically set the display to the calibration
- contained in the installed profile (ie. OS X), while on other
- systems (ie. MSWindows and Linux/X11) it is necessary to use some
- tool to do this. On MSWindows XP you could install the
- optional&nbsp; <span style="font-weight: bold;">Microsoft&nbsp;Color&nbsp;Control&nbsp;Panel&nbsp;Applet&nbsp;for&nbsp;Windows&nbsp;XP</span>
- available for download from Microsoft to do this, but&nbsp;<span
- style="font-weight: bold;">NOTE</span> however that it seems to
- have a <span style="font-weight: bold;">bug</span>, in that it
- sometimes associates the profiles with the <span
- style="font-weight: bold;">wrong monitor</span> entry. Other
- display calibration tools will often install a similar tool, so
- beware of there being multiple, competing programs. [ Commonly these
- will be in your Start-&gt;Programs-&gt;Startup folder. ]<br>
- On Microsoft Vista, you need to use dispwin -L or some other tool to
- load the installed profiles calibration at startup.<br>
- <br>
- To use dispwin to load the installed profiles calibration to the
- display, use<br>
- <br>
- <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a><br>
- <br>
- As per usual, you can select the appropriate display using the <a
- href="dispwin.html#d">-d</a> flag.<br>
- <br>
- This can be automated on MSWindows and X11/Linux by adding this
- command to an appropriate startup script.<br>
- More system specific details, including how to create such startup
- scripts are <a href="dispprofloc.html">here</a>. <br>
- <br>
- If you are using Microsoft <span style="font-weight: bold;">Vista</span>,
- there is a known <span style="font-weight: bold;">bug</span> in
- Vista that resets the calibration every time a fade-in effect is
- executed, which happens if you lock and unlock the computer, resume
- from sleep or hibernate, or User Access Control is activated. Using
- <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a>
- may not restore the calibration, because Vista filters out setting
- (what it thinks) is a calibration that is already loaded. Use <a
- href="dispwin.html">dispwin</a> <a href="dispwin.html#c">-c</a> <a
- href="dispwin.html#L">-L</a><span style="font-family: monospace;"></span>
- as a workaround, as this will first clear the calibration, then
- re-load the current calibration.<br>
- <br>
- On X11/Linux systems, you could try adding <a href="dispwin.html">dispwin</a>
- <a href="dispwin.html#L">-L</a> to your <span style="font-weight:
- bold;">~/.config/autostart</span> file, so that your window
- manager automatically sets calibration when it starts. If you are
- running XRandR 1.2, you might consider running the experimental <a
- href="dispwin.html#D">dispwin -E</a> in the background, as in its
- "daemon" mode it will update the profile and calibration in response
- to any changes in the the connected display.<br>
- <br>
- <h4><a name="PM6"></a>Expert tips when measuring displays:<br>
- </h4>
- Sometimes it can be difficult to get good quality, consistent and
- visually relevant readings from displays, due to various practical
- considerations with regard to instruments and the displays
- themselves. Argyll's tools have some extra options that may assist
- in overcoming these problems.<br>
- <br>
- If you are using an Eye-One Pro or ColorMunki spectrometer, then you
- may wish to use the <a href="dispcal.html#H">high resolution
- spectral mode</a> (<span style="font-weight: bold;">-H</span>).
- This may be better at capturing the often narrow wavelength peaks
- that are typical of display primary colors.<br>
- <br>
- All instruments depend on silicon sensors, and such sensors generate
- a temperature dependant level of noise ("dark noise") that is
- factored out of the measurements by a dark or black instrument
- calibration. The spectrometers in particular need this calibration
- before commencing each set of measurements. Often an instrument will
- warm up as it sits on a display, and this warming up can cause the
- dark noise to increase, leading to inaccuracies in dark patch
- measurements. The longer the measurement takes, the worse this
- problem is likely to be. One way of addressing this is to
- "acclimatise" the instrument before commencing measurements by
- placing it on the screen in a powered up state, and leaving it for
- some time. (Some people leave it for up to an hour to acclimatise.).
- Another approach is to try and <a href="dispcal.html#I">compensate
- for dark calibration changes</a> (<span style="font-weight: bold;">-Ib</span>)
- by doing on the fly calibrations during the measurements, based on
- the assumption that the black level of the display itself won't
- change significantly. <br>
- <br>
- Some displays take a long time to settle down and stabilise. The is
- often the case with LCD (Liquid Crystal) displays that use
- fluorescent back lights, and these sorts of displays can change in
- brightness significantly with changes in temperature. One way of
- addressing this is to make sure that the display is given adequate
- time to warm up before measurements. Another approach is to try and
+
+ -r</span> for an LCD display, or <span style="text-decoration:
+ underline; color: rgb(204, 51, 204);">dispcal -yc -r</span> for a
+ CRT display with most of the colorimeter instruments. If so, this
+ will apply to all of the following examples.)<br>
+ <br>
+ Once this is done, <a href="dispcal.html">dispcal</a> can be run to
+ guide you through the display adjustments, and then calibrate it. By
+ default, the brightness and white point will be kept the same as the
+ devices natural brightness and white point. The default response
+ curve is a gamma of 2.4, except for Apple OS X systems prior to 10.6
+ where a gamma of 1.8 is the default. 2.4 is close to that of&nbsp;
+ many monitors, and close to that of the sRGB colorspace. <br>
+ <br>
+ A typical calibration that leaves the brightness and white point
+ alone, might be:<br>
+ <br>
+ <a href="dispcal.html">dispcal</a> -v TargetA<br>
+ <br>
+ which will result in a "TargetA.cal" calibration file, that can then
+ be used during the profiling stage.<br>
+ <br>
+ If the absolutely native response of the display is desired during
+ profiling, then calibration should be skipped, and the linear.cal
+ file from the "ref" directory used instead as the argument to the -k
+ flag of <span style="font-weight: bold;">dispread</span>.<br>
+ <br>
+ <b>Dispcal</b> will display a test window in the middle of the
+ screen, and issue a series of instructions about placing the
+ instrument on the display. You may need to make sure that the
+ display cursor is not in the test window, and it may also be
+ necessary to disable any screensaver and powersavers before starting
+ the process, although both <span style="font-weight: bold;">dispcal</span>
+ and <span style="font-weight: bold;">dispread</span> will attempt
+ to do this for you. It's also highly desirable on CRT's, to clear
+ your screen of any white or bright background images or windows
+ (running your shell window with white text on a black background
+ helps a lot here.), or at least keep any bright areas away from the
+ test window, and be careful not to change anything on the display
+ while the readings are taken. Lots of bright images or windows can
+ affect the ability to measure the black point accurately, and
+ changing images on the display can cause inconsistency in the
+ readings,&nbsp; and leading to poor results.<span
+ style="font-weight: bold;"></span> LCD displays seem to be less
+ influenced by what else is on the screen.<br>
+ <br>
+ If <span style="font-weight: bold;">dispcal</span> is run without
+ arguments, it will provide a usage screen. The <span
+ style="font-weight: bold;">-c</span> parameter allows selecting a
+ communication port for an instrument, or selecting the instrument
+ you want to use,&nbsp; and the <a href="dispcal.html#d"><span
+ style="font-weight: bold;">-d</span></a> option allows selecting
+ a target display on a multi-display system. On some multi-monitor
+ systems, it may not be possible to independently calibrate and
+ profile each display if they appear as one single screen to the
+ operating system, or if it is not possible to set separate video
+ lookup tables for each display. You can change the position and size
+ of the test window using the <a href="dispcal.html#P"><span
+ style="font-weight: bold;">-P</span></a> parameter. You can
+ determine how best to arrange the test window, as well as whether
+ each display has separate video lookup capability, by experimenting
+ with the <a href="dispwin.html">dispwin</a> tool. <br>
+ <br>
+ For a more detailed discussion on interactively adjusting the
+ display controls using <span style="font-weight: bold;">dispcal</span>,
+ see <a href="dispcal.html#Adjustment">dispcal-adjustment</a>. Once
+ you have adjusted and calibrated your display, you can move on to
+ the next step.<br>
+ <br>
+ When you have calibrated and profiled your display, you can keep it
+ calibrated using the <a href="dispcal.html#u">dispcal -u</a>
+ option.<br>
+ <br>
+ <h4><a name="PM1c"></a>Adjusting, calibrating and profiling in one
+ step.</h4>
+ If a simple matrix/shaper display profile is all that is desired, <span
+ style="font-weight: bold;">dispcal</span> can be used to do this,
+ permitting display adjustment, calibration and profiling all in one
+ operation. This is done by using the <span style="font-weight:
+ bold;"><span style="font-weight: bold;">dispcal </span>-o</span>
+ flag:<br>
+ <br>
+ <a href="dispcal.html">dispcal</a> <a href="dispcal.html#v">-v</a>
+ <a href="dispcal.html#o">-o</a> <a href="dispcal.html#p1">TargetA</a><br>
+ <br>
+ This will create both a TargetA.cal file, but also a TargetA.icm
+ file. See <a href="dispcal.html#o">-o</a> and <a
+ href="dispcal.html#O">-O</a> for other variations.<br>
+ <br>
+ For more flexibility in creating a display profile, the separate
+ steps of creating characterization test values using <span
+ style="font-weight: bold;">targen</span>, reading them from the
+ display using <span style="font-weight: bold;">dispread</span>, and
+ then creating a profile using <span style="font-weight: bold;">colprof</span>
+ are used. The following steps illustrate this:<br>
+ <h4><a name="PM2"></a>Profiling in several steps: Creating display
+ test values</h4>
+ If the <span style="font-weight: bold;">dispcal</span> has not been
+ used to create a display profile at the same time as adjustment and
+ calibration, then it can be used to create a suitable set of
+ calibration curves as the first step, or the calibration step can be
+ omitted, and the display cansimply be profiled.<br>
+ <br>
+ The first step in profiling any output device, is to create a set of
+ device colorspace test values. The important parameters needed are:
+ <br>
+ <ul>
+ <li>What colorspace does the device use ?</li>
+ <li>How many test patches do I want to use ?</li>
+ <li>What information do I already have about how the device
+ behaves ?</li>
+ </ul>
+ For a display device, &nbsp;the colorspace will be RGB. The number
+ of test patches will depend somewhat on what quality profile you
+ want to make, what type of profile you want to make, and how long
+ you are prepared to wait when testing the display.<br>
+ At a minimum, a few hundred values are needed. A matrix/shaper type
+ of profile can get by with fewer test values, while a LUT based
+ profile will give better results if more test values are used. A
+ typical number might be 200-600 or so values, while 1000-2000 is not
+ an unreasonable number for a high quality characterization of a
+ display.<br>
+ <br>
+ To assist the choice of test patch values, it can help to have a
+ rough idea of how the device behaves. This could be in the form of
+ an ICC profile of a similar device, or a lower quality, or previous
+ profile for that particular device. If one were going to make a very
+ high quality LUT based profile, then it might be worthwhile to make
+ up a smaller, preliminary shaper/matrix profile using a few hundred
+ test points, before embarking on testing the device with several
+ thousand.<br>
+ <br>
+ Lets say that we ultimately want to make a profile for the device
+ "DisplayA", the simplest approach is to make a set of test values
+ that is independent of the characteristics of the particular device:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
+ <a href="targen.html#p1">DisplayA</a><br>
+ <br>
+ If there is a preliminary or previous profile called "OldDisplay"
+ available, and we want to try creating a "pre-conditioned" set of
+ test values that will more efficiently sample the device response,
+ then the following would achieve this:<br>
+ <u><br>
+ </u><a href="targen.html"> targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
+ <a href="targen.html#c">-cOldDisplay.icm</a> <a
+ href="targen.html#p1">DisplayA</a><br>
+ <br>
+ The output of <b>targen</b> will be the file DisplayA.ti1,
+ containing the device space test values, as well as expected CIE
+ values used for chart recognition purposes.<br>
+ <br>
+ <h4><a name="PM3"></a>Profiling in several steps: Taking readings
+ from a display</h4>
+ First it is necessary to connect your measurement instrument to your
+ computer, and check which communication port it is connected to. In
+ the following example, it is assumed that the instrument is
+ connected to the default port 1, which is either the first USB
+ instrument found, or serial port found. Invoking dispread so as to
+ display the usage information (by using a flag -? or --) will list
+ the identified serial and USB ports, and their labels.<br>
+ <br>
+ <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#p1">DisplayA</a><br>
+ <br>
+ If we created a calibration for the display using <a
+ href="dispcal.html">dispcal</a>, then we will want to use this
+ when we take the display readings (e.g. TargetA.cal from the
+ calibration example)..<br>
+ <br>
+ <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#k">-k TargetA.cal</a> <a
+ href="dispread.html#p1">DisplayA</a><br>
+ <br>
+ <b>dispread</b> will display a test window in the middle of the
+ screen, and issue a series of instructions about placing the
+ instrument on the display. You may need to make sure that the
+ display cursor is not in the test window, and it may also be
+ necessary to disable any screensaver before starting the process.
+ Exactly the same facilities are provided to select alternate
+ displays using the <span style="font-weight: bold;">-d</span>
+ parameter, and an alternate location and size for the test window
+ using the <span style="font-weight: bold;">-P</span> parameter as
+ with <span style="font-weight: bold;">dispcal</span>.<br>
+ <h4><a name="PM4"></a>Profiling in several steps: Creating a display
+ profile</h4>
+ There are two basic choices of profile type for a display, a
+ shaper/matrix profile, or a LUT based profile. They have different
+ tradeoffs. A shaper/matrix profile will work well on a well behaved
+ display, that is one that behaves in an additive color manner, will
+ give very smooth looking results, and needs fewer test points to
+ create. A LUT based profile on the other hand, will model any
+ display behaviour more accurately, and can accommodate gamut mapping
+ and different intent tables. Often it can show some unevenness and
+ contouring in the results though.<br>
+ <br>
+ To create a matrix/shaper profile, the following suffices:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-as</a> <a href="colprof.html#p1">DisplayA</a><br>
+ <br>
+ For a LUT based profile, where gamut mapping is desired, then a
+ source profile will need to be provided to define the source gamut.
+ For instance, if the display profile was likely to be linked to a
+ CMYK printing source profile, say "swop.icm" or "fogra39l.icm", then
+ the following would suffice:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S">
+ fogra39l.icm</a> <a href="colprof.html#c">-cpp</a> <a
+ href="colprof.html#d">-dmt</a> <a href="colprof.html#p1">DisplayA</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably.<br>
+ If a calibration file was used with <a href="dispread.html">dispread</a>,
+ then it will be converted to a vcgt tag in the profile, so that the
+ operating system or other system color tools load the lookup curves
+ into the display hardware, when the profile is used.<br>
+ <h4><a name="PM5"></a>Installing a display profile</h4>
+ <a href="dispwin.html">dispwin</a> provides a convenient way of
+ installing a profile as the default system profile for the chosen
+ display:<br>
+ <br>
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#I">-I</a>
+ <a href="dispwin.html#p1">DisplayA.icm</a><br>
+ <br>
+ This also sets the display to the calibration contained in the
+ profile. If you want to try out a calibration before installing the
+ profile, using dispwin without the <span style="font-weight: bold;">-I</span>
+ option will load a calibration (ICC profile or .cal file) into the
+ current display.<br>
+ <br>
+ Some systems will automatically set the display to the calibration
+ contained in the installed profile (ie. OS X), while on other
+ systems (ie. MSWindows and Linux/X11) it is necessary to use some
+ tool to do this. On MSWindows XP you could install the
+ optional&nbsp; <span style="font-weight: bold;">Microsoft&nbsp;Color&nbsp;Control&nbsp;Panel&nbsp;Applet&nbsp;for&nbsp;Windows&nbsp;XP</span>
+ available for download from Microsoft to do this, but&nbsp;<span
+ style="font-weight: bold;">NOTE</span> however that it seems to
+ have a <span style="font-weight: bold;">bug</span>, in that it
+ sometimes associates the profiles with the <span
+ style="font-weight: bold;">wrong monitor</span> entry. Other
+ display calibration tools will often install a similar tool, so
+ beware of there being multiple, competing programs. [ Commonly these
+ will be in your Start-&gt;Programs-&gt;Startup folder. ]<br>
+ On Microsoft Vista, you need to use dispwin -L or some other tool to
+ load the installed profiles calibration at startup.<br>
+ <br>
+ To use dispwin to load the installed profiles calibration to the
+ display, use<br>
+ <br>
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a><br>
+ <br>
+ As per usual, you can select the appropriate display using the <a
+ href="dispwin.html#d">-d</a> flag.<br>
+ <br>
+ This can be automated on MSWindows and X11/Linux by adding this
+ command to an appropriate startup script.<br>
+ More system specific details, including how to create such startup
+ scripts are <a href="dispprofloc.html">here</a>. <br>
+ <br>
+ If you are using Microsoft <span style="font-weight: bold;">Vista</span>,
+ there is a known <span style="font-weight: bold;">bug</span> in
+ Vista that resets the calibration every time a fade-in effect is
+ executed, which happens if you lock and unlock the computer, resume
+ from sleep or hibernate, or User Access Control is activated. Using
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a>
+ may not restore the calibration, because Vista filters out setting
+ (what it thinks) is a calibration that is already loaded. Use <a
+ href="dispwin.html">dispwin</a> <a href="dispwin.html#c">-c</a> <a
+ href="dispwin.html#L">-L</a><span style="font-family: monospace;"></span>
+ as a workaround, as this will first clear the calibration, then
+ re-load the current calibration.<br>
+ <br>
+ On X11/Linux systems, you could try adding <a href="dispwin.html">dispwin</a>
+ <a href="dispwin.html#L">-L</a> to your <span style="font-weight:
+ bold;">~/.config/autostart</span> file, so that your window
+ manager automatically sets calibration when it starts. If you are
+ running XRandR 1.2, you might consider running the experimental <a
+ href="dispwin.html#D">dispwin -E</a> in the background, as in its
+ "daemon" mode it will update the profile and calibration in response
+ to any changes in the the connected display.<br>
+ <br>
+ <h4><a name="PM6"></a>Expert tips when measuring displays:<br>
+ </h4>
+ Sometimes it can be difficult to get good quality, consistent and
+ visually relevant readings from displays, due to various practical
+ considerations with regard to instruments and the displays
+ themselves. Argyll's tools have some extra options that may assist
+ in overcoming these problems.<br>
+ <br>
+ If you are using an Eye-One Pro or ColorMunki spectrometer, then you
+ may wish to use the <a href="dispcal.html#H">high resolution
+ spectral mode</a> (<span style="font-weight: bold;">-H</span>).
+ This may be better at capturing the often narrow wavelength peaks
+ that are typical of display primary colors.<br>
+ <br>
+ All instruments depend on silicon sensors, and such sensors generate
+ a temperature dependant level of noise ("dark noise") that is
+ factored out of the measurements by a dark or black instrument
+ calibration. The spectrometers in particular need this calibration
+ before commencing each set of measurements. Often an instrument will
+ warm up as it sits on a display, and this warming up can cause the
+ dark noise to increase, leading to inaccuracies in dark patch
+ measurements. The longer the measurement takes, the worse this
+ problem is likely to be. One way of addressing this is to
+ "acclimatise" the instrument before commencing measurements by
+ placing it on the screen in a powered up state, and leaving it for
+ some time. (Some people leave it for up to an hour to acclimatise.).
+ Another approach is to try and <a href="dispcal.html#I">compensate
+ for dark calibration changes</a> (<span style="font-weight: bold;">-Ib</span>)
+ by doing on the fly calibrations during the measurements, based on
+ the assumption that the black level of the display itself won't
+ change significantly. <br>
+ <br>
+ Some displays take a long time to settle down and stabilise. The is
+ often the case with LCD (Liquid Crystal) displays that use
+ fluorescent back lights, and these sorts of displays can change in
+ brightness significantly with changes in temperature. One way of
+ addressing this is to make sure that the display is given adequate
+ time to warm up before measurements. Another approach is to try and
<a href="dispcal.html#I">compensate for display white level</a>&nbsp;
@@ -647,23 +643,21 @@
-
-
-
- (<span style="font-weight: bold;">-Iw</span>) changes by doing on
- the fly calibrations during the measurements. Instrument black level
- drift and display white level drift can be combined (<span
- style="font-weight: bold;">-Ibw</span>).<br>
- <br>
- Colorimeter instruments make use of physical color filters that
- approximate the standard observer spectral sensitivity curves.
- Because these filters are not perfectly accurate, the manufacturer
- calibrates the instrument for typical displays, which is why you
- have to make a selection between CRT (Cathode Ray Tube) and LCD
- (Liquid Crystal Display) modes. If you are measuring a display that
- has primary colorants that differ significantly from those typical
- displays,&nbsp; (ie. you have a Wide Gamut Display), then you may
- get disappointing results with a Colorimeter. One way of addressing
+
+ (<span style="font-weight: bold;">-Iw</span>) changes by doing on
+ the fly calibrations during the measurements. Instrument black level
+ drift and display white level drift can be combined (<span
+ style="font-weight: bold;">-Ibw</span>).<br>
+ <br>
+ Colorimeter instruments make use of physical color filters that
+ approximate the standard observer spectral sensitivity curves.
+ Because these filters are not perfectly accurate, the manufacturer
+ calibrates the instrument for typical displays, which is why you
+ have to make a selection between CRT (Cathode Ray Tube) and LCD
+ (Liquid Crystal Display) modes. If you are measuring a display that
+ has primary colorants that differ significantly from those typical
+ displays,&nbsp; (ie. you have a Wide Gamut Display), then you may
+ get disappointing results with a Colorimeter. One way of addressing
this problem is to use a <a href="File_Formats.html#.ccmx">Colorimeter
@@ -720,120 +714,118 @@
-
-
-
- Correction Matrix</a>. These are specific to a particular
- Colorimeter and Display make and model combination, although a
- matrix for a different but similar type of display may give better
- results than none at all. A list of contributed <span
- style="font-weight: bold;">ccmx</span> files is <a
- href="ccmxs.html">here</a>.<br>
- <br>
- <h4><a name="PM7"></a>Calibrating and profiling a display that
- doesn't have VideoLUT access.</h4>
- <p>In some situation there is no access to a displays VideoLUT
- hardware, and this hardware is what is usually used to implement
- display calibration. This could be because the display is being
- accessed via a web server, or because the driver or windowing
- system doesn't support VideoLUT access.<br>
- </p>
- <p>There are two basic options in this situation:<br>
- </p>
- <p>&nbsp; 1) Don't attempt to calibrate, just profile the display.<br>
- &nbsp; 2) Calibrate, but incorporate the calibration in some other
- way in the workflow.<br>
- </p>
- <p>The first case requires nothing special - just skip calibration
- (see the previous section <a href="#PM7">Profiling in several
- steps: Creating display test values</a>).</p>
- <p> In the second case, there are three choices:<br>
- </p>
- <p>&nbsp;2a) Use dispcal to create a calibration and a quick profile
- that incorporates the calibration into the profile.<br>
- &nbsp;2b) Use dispcal to create the calibration, then dispread and
- colprof to create a profile, and then incorporate the calibration
- into the profile using applycal.<br>
- &nbsp;2c) Use dispcal to create the calibration, then dispread and
- colprof to create a profile, and then apply the calibration after
- the profile in a cctiff workflow.<br>
- </p>
- <p>The first case requires nothing special, use dispcal in a normal
- fashioned with the <span style="font-weight: bold;">-o</span>
- option to generate a quick profile.The profile created will <span
- style="text-decoration: underline;">not</span> contain a 'vcgt'
- tag, but instead will have the calibration curves incorporated
- into the profile itself. If calibration parameters are chosen that
- change the displays white point or brightness, then this will
- result in a slightly unusual profile that has a white point that
- does not correspond with device R=G=B=1.0. Some systems may not
- cope properly with this type of profile, and a general shift in
- white point through such a profile can create an odd looking
- display if it is applied to images but not to other elements on
- the display say as GUI decoration elements or other application
- windows.<br>
- </p>
- <p>In the second case, the calibration file created using dispcal
- should be provided to dispread using the <span
- style="font-weight: bold;">-K</span> flag:<br>
- </p>
- <p><a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
- <a href="dispread.html#K">-K TargetA.cal</a> <a
- href="dispread.html#p1">DisplayA</a></p>
- <p><span style="font-weight: bold;"></span>Create the profile as
- usual using colprof. but note that colprof will ignore the
- calibration, and that no 'vcgt' tag will be added to the profile.<br>
- You can then use <a href="applycal.html">applycal </a>to combine
- the calibration into the profile. Note that the resulting profile
- will be slightly unusual, since the profile is not made completely
- consistent with the effects of the calibration, and the device
- R=G=B=1.0 probably not longer corresponds with the PCS white or
- the white point.<br>
- </p>
- In the third case, the same procedure as above is used to create a
- profile, but the calibration is applied in a raster transformation
- workflow explicitly, e.g.:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
- href="cctiff.html#p1">SourceProfile.icm</a> <a
- href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
- <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
- or<br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
- href="cctiff.html#p1">SourceProfile.icm</a> <a
- href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
- <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
- <span style="font-weight: bold;"></span><br>
- <hr size="2" width="100%">
- <h3><a name="PS1"></a>Profiling Scanners and other input devices
- such as cameras<br>
- </h3>
- Because a scanner or camera is an input device, it is necessary to
- go about profiling it in quite a different way to an output device.
- To profile it, a test chart is needed to exercise the input device
- response, to which the CIE values for each test patch is known.
- Generally standard reflection or transparency test charts are used
- for this purpose.<br>
- <h4><a name="PS2"></a>Types of test charts</h4>
- The most common and popular test chart for scanner profiling is the
- IT8.7/2 chart. This is a standard format chart generally reproduced
- on photographic film, containing about 264 test patches.<br>
- An accessible and affordable source of such targets is Wolf Faust a
- <a href="http://www.targets.coloraid.de/">www.coloraid.de</a>.<br>
- Another source is LaserSoft <a
- href="http://www.silverfast.com/show/it8/en.html">www.silverfast.com.</a><br>
- The Kodak Q-60 Color Input Target is also a typical example:<br>
- <br>
- <img src="Q60.jpg" alt="Kodak Q60 chart image" width="200"
- height="141"> <br>
- <br>
- A very simple chart that is widely available is the Macbeth
- ColorChecker chart, although it contains only 24 patches and
- therefore is probably not ideal for creating profiles:<br>
- <img alt="ColorChecker 24 patch" src="colorchecker.jpg"
- style="width: 112px; height: 78px;"><br>
- <br>
- Other popular charts are the X-Rite/GretagMacbeth ColorChecker DC
+
+ Correction Matrix</a>. These are specific to a particular
+ Colorimeter and Display make and model combination, although a
+ matrix for a different but similar type of display may give better
+ results than none at all. A list of contributed <span
+ style="font-weight: bold;">ccmx</span> files is <a
+ href="ccmxs.html">here</a>.<br>
+ <br>
+ <h4><a name="PM7"></a>Calibrating and profiling a display that
+ doesn't have VideoLUT access.</h4>
+ <p>In some situation there is no access to a displays VideoLUT
+ hardware, and this hardware is what is usually used to implement
+ display calibration. This could be because the display is being
+ accessed via a web server, or because the driver or windowing
+ system doesn't support VideoLUT access.<br>
+ </p>
+ <p>There are two basic options in this situation:<br>
+ </p>
+ <p>&nbsp; 1) Don't attempt to calibrate, just profile the display.<br>
+ &nbsp; 2) Calibrate, but incorporate the calibration in some other
+ way in the workflow.<br>
+ </p>
+ <p>The first case requires nothing special - just skip calibration
+ (see the previous section <a href="#PM7">Profiling in several
+ steps: Creating display test values</a>).</p>
+ <p> In the second case, there are three choices:<br>
+ </p>
+ <p>&nbsp;2a) Use dispcal to create a calibration and a quick profile
+ that incorporates the calibration into the profile.<br>
+ &nbsp;2b) Use dispcal to create the calibration, then dispread and
+ colprof to create a profile, and then incorporate the calibration
+ into the profile using applycal.<br>
+ &nbsp;2c) Use dispcal to create the calibration, then dispread and
+ colprof to create a profile, and then apply the calibration after
+ the profile in a cctiff workflow.<br>
+ </p>
+ <p>The first case requires nothing special, use dispcal in a normal
+ fashioned with the <span style="font-weight: bold;">-o</span>
+ option to generate a quick profile.The profile created will <span
+ style="text-decoration: underline;">not</span> contain a 'vcgt'
+ tag, but instead will have the calibration curves incorporated
+ into the profile itself. If calibration parameters are chosen that
+ change the displays white point or brightness, then this will
+ result in a slightly unusual profile that has a white point that
+ does not correspond with device R=G=B=1.0. Some systems may not
+ cope properly with this type of profile, and a general shift in
+ white point through such a profile can create an odd looking
+ display if it is applied to images but not to other elements on
+ the display say as GUI decoration elements or other application
+ windows.<br>
+ </p>
+ <p>In the second case, the calibration file created using dispcal
+ should be provided to dispread using the <span
+ style="font-weight: bold;">-K</span> flag:<br>
+ </p>
+ <p><a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#K">-K TargetA.cal</a> <a
+ href="dispread.html#p1">DisplayA</a></p>
+ <p><span style="font-weight: bold;"></span>Create the profile as
+ usual using colprof. but note that colprof will ignore the
+ calibration, and that no 'vcgt' tag will be added to the profile.<br>
+ You can then use <a href="applycal.html">applycal </a>to combine
+ the calibration into the profile. Note that the resulting profile
+ will be slightly unusual, since the profile is not made completely
+ consistent with the effects of the calibration, and the device
+ R=G=B=1.0 probably not longer corresponds with the PCS white or
+ the white point.<br>
+ </p>
+ In the third case, the same procedure as above is used to create a
+ profile, but the calibration is applied in a raster transformation
+ workflow explicitly, e.g.:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">SourceProfile.icm</a> <a
+ href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">SourceProfile.icm</a> <a
+ href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <span style="font-weight: bold;"></span><br>
+ <hr size="2" width="100%">
+ <h3><a name="PS1"></a>Profiling Scanners and other input devices
+ such as cameras<br>
+ </h3>
+ Because a scanner or camera is an input device, it is necessary to
+ go about profiling it in quite a different way to an output device.
+ To profile it, a test chart is needed to exercise the input device
+ response, to which the CIE values for each test patch is known.
+ Generally standard reflection or transparency test charts are used
+ for this purpose.<br>
+ <h4><a name="PS2"></a>Types of test charts</h4>
+ The most common and popular test chart for scanner profiling is the
+ IT8.7/2 chart. This is a standard format chart generally reproduced
+ on photographic film, containing about 264 test patches.<br>
+ An accessible and affordable source of such targets is Wolf Faust a
+ <a href="http://www.targets.coloraid.de/">www.coloraid.de</a>.<br>
+ Another source is LaserSoft <a
+ href="http://www.silverfast.com/show/it8/en.html">www.silverfast.com.</a><br>
+ The Kodak Q-60 Color Input Target is also a typical example:<br>
+ <br>
+ <img src="Q60.jpg" alt="Kodak Q60 chart image" height="141"
+ width="200"> <br>
+ <br>
+ A very simple chart that is widely available is the Macbeth
+ ColorChecker chart, although it contains only 24 patches and
+ therefore is probably not ideal for creating profiles:<br>
+ <img alt="ColorChecker 24 patch" src="colorchecker.jpg"
+ style="width: 112px; height: 78px;"><br>
+ <br>
+ Other popular charts are the X-Rite/GretagMacbeth ColorChecker DC
and <a href="http://www.xrite.com/product_overview.aspx?ID=938">ColorChecker
@@ -891,20 +883,18 @@
-
-
-
- SG</a> charts:<br>
- <br>
- <img src="DC.jpg" alt="GretagMacbeth ColorChecker DC chart"
- width="200" height="122"> <img alt="ColorChecker SG" src="SG.jpg"
- style="width: 174px; height: 122px;"><br>
- <br>
- The GretagMacbeth Eye-One Pro Scan Target 1.4 can also be used:<br>
- <br>
- <img alt="Eye-One Scan Target 1.4" src="i1scan14.jpg" style="border:
- 2px solid ; width: 200px; height: 140px;"><br>
- <br>
+
+ SG</a> charts:<br>
+ <br>
+ <img src="DC.jpg" alt="GretagMacbeth ColorChecker DC chart"
+ height="122" width="200"> <img alt="ColorChecker SG" src="SG.jpg"
+ style="width: 174px; height: 122px;"><br>
+ <br>
+ The GretagMacbeth Eye-One Pro Scan Target 1.4 can also be used:<br>
+ <br>
+ <img alt="Eye-One Scan Target 1.4" src="i1scan14.jpg" style="border:
+ 2px solid ; width: 200px; height: 140px;"><br>
+ <br>
Also supported is the <a href="http://www.hutchcolor.com/hct.htm">HutchColor
@@ -962,25 +952,23 @@
-
-
-
- HCT</a> :<br>
- <br>
- <img alt="HutchColor HCT" src="HCT.jpg" style="width: 182px; height:
- 140px;"><br>
- <br>
- <br>
- and <a href="http://www.cmp-color.fr/DT3.html">Christophe
- Métairie's Digital TargeT 003</a> and <a
- href="http://www.cmp-color.fr/digital%20target.html">Christophe
- Métairie's Digital Target - 4</a> :<br>
- <br>
- <img alt="CMP_DT_003" src="CMP_DT_003.jpg" style="width: 186px;
- height: 141px;">&nbsp; <img style="width: 203px; height: 140px;"
- alt="CMP_Digital_Target-4" src="CMP_Digital_Target-4.jpg"
- width="203" height="140"><br>
- <br>
+
+ HCT</a> :<br>
+ <br>
+ <img alt="HutchColor HCT" src="HCT.jpg" style="width: 182px; height:
+ 140px;"><br>
+ <br>
+ <br>
+ and <a href="http://www.cmp-color.fr/DT3.html">Christophe
+ Métairie's Digital TargeT 003</a> and <a
+ href="http://www.cmp-color.fr/digital%20target.html">Christophe
+ Métairie's Digital Target - 4</a> :<br>
+ <br>
+ <img alt="CMP_DT_003" src="CMP_DT_003.jpg" style="width: 186px;
+ height: 141px;">&nbsp; <img style="width: 203px; height: 140px;"
+ alt="CMP_Digital_Target-4" src="CMP_Digital_Target-4.jpg"
+ height="140" width="203"><br>
+ <br>
and the <a href="http://www.silverfast.com/show/dc-targets/en.html">LaserSoft
@@ -1038,28 +1026,20 @@
-
-
-
- Imaging DCPro Target</a>:<br>
- <br>
- <img style="width: 153px; height: 122px;" alt="LaserSoft DCPro
- Target" src="LSDC.jpg"><br>
- <br>
- The Datacolor <a
- href="http://spyder.datacolor.com/product-cb-spydercheckr.php">SpyderCheckr</a>:<br>
- <br>
- <img style=" width: 146px; height: 109px;" alt="Datacolor
- SpyderCheckr" src="SpyderChecker.jpg"><br>
- <br>
- The Datacolor <a
- href="http://spyder.datacolor.com/portfolio-view/spydercheckr-24/">SpyderCheckr24</a>:<br>
- <br>
- <img alt="SpyderCheckr24" src="SpyderChecker24.jpg" width="82"
- height="122"><br>
- <br>
- One of the QPcard's:<br>
- <a
+
+ Imaging DCPro Target</a>:<br>
+ <br>
+ <img style="width: 153px; height: 122px;" alt="LaserSoft DCPro
+ Target" src="LSDC.jpg"><br>
+ <br>
+ The Datacolor <a
+ href="http://spyder.datacolor.com/product-cb-spydercheckr.php">SpyderCheckr</a>:<br>
+ <br>
+ <img style=" width: 146px; height: 109px;" alt="Datacolor
+ SpyderCheckr" src="SpyderChecker.jpg"><br>
+ <br>
+ One of the QPcard's:<br>
+ <a
href="http://www.qpcard.com/en_b2c/color-reference-cards/qpcard201.html">QPcard
@@ -1111,10 +1091,8 @@
-
-
-
- 201</a>:&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <a
+
+ 201</a>:&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <a
href="http://www.qpcard.com/en_b2c/color-reference-cards/instant-camera-raw-profiling-with-qpcard-202.html">QPcard
@@ -1166,89 +1144,87 @@ href="http://www.qpcard.com/en_b2c/color-reference-cards/instant-camera-raw-prof
-
-
-
- 202</a>:<br>
- <br>
- <img style=" width: 41px; height: 141px;" alt="QPCard201"
- src="QPcard201.jpg">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <img
- style=" width: 97px; height: 141px;" alt="QPcard202"
- src="QPcard202.jpg"><br>
- <br>
- <h4><a name="PS3"></a>Taking readings from a scanner or camera<br>
- </h4>
- The test chart you are using needs to be placed on the scanner, and
- the scanner needs to be configured to a suitable state, and restored
- to that same state when used subsequently with the resulting
- profile. For a camera, the chart needs to be lit in a controlled and
- even manner using the light source that will be used for subsequent
- photographs, and should be shot so as to minimise any geometric
- distortion, although the <a href="scanin.html#p">scanin -p</a> flag
- may be used to compensate for some degree of distortion. As with any
- color profiling task, it is important to setup a known and
- repeatable image processing flow, to ensure that the resulting
- profile will be usable.<br>
- <br>
- The chart should be captured and saved to a TIFF format file. I will
- assume the resulting file is called scanner.tif. The raster file
- need only be roughly cropped so as to contain the test chart
- (including the charts edges).<br>
- <br>
- The second step is to extract the RGB values from the scanner.tif
- file, and match then to the reference CIE values. To locate the
- patch values in the scan, the <b>scanin</b> tool needs to be given
- a template <a href="File_Formats.html#.cht">.cht</a> file that
- describes the features of the chart, and how the test patches are
- labeled. Also needed is a file containing the CIE values for each of
- the patches in the chart, which is typically supplied with the
- chart, available from the manufacturers web site, or has been
- measured using a spectrometer.<br>
- <br>
- <div style="margin-left: 40px;">For an IT8.7/2 chart, this is the <span
- style="font-weight: bold;">ref/</span><b>it8.cht</b> file
- supplied with Argyll, and&nbsp; the manufacturer will will supply
- an individual or batch average file along with the chart
- containing this information, or downloadable from their web site.
- For instance, Kodak Q60 target reference files are <a
- href="ftp://ftp.kodak.com/gastds/Q60DATA/">here</a>.<br>
- NOTE that the reference file for the IT8.7/2 chart supplied with <span
- style="font-weight: bold;">Monaco&nbsp;EZcolor</span> can be
- obtained by unzipping the .mrf file. (You may have to make a copy
- of the file with a .zip extension to do this.)<br>
- <br>
- For the ColorChecker 24 patch chart, the <span
- style="font-weight: bold;">ref/ColorChecker.cht</span> file
- should be used, and there is also a <span style="font-weight:
- bold;">ref/ColorChecker.cie</span> file provided that is based
- on the manufacturers reference values for the chart. You can also
- create your own reference file using an instrument and chartread,
- making use of the chart reference file <span style="font-weight:
- bold;">ref/ColorChecker.ti2</span>:<br>
- &nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
- ColorChecker.ti2<br>
- Note that due to the small number of patches, a profile created
- from such a chart is not likely to be very detailed.<br>
- <br>
- For the ColorChecker DC chart, the <span style="font-weight:
- bold;">ref/ColorCheckerDC.cht</span> file should be used, and
- there will be a ColorCheckerDC reference file supplied by
- X-Rite/GretagMacbeth with the chart.<br>
- <br>
- The ColorChecker SG is relatively expensive, but is preferred by
- many people because (like the ColorChecker and ColorCheckerDC) its
- colors are composed of multiple different pigments, giving it
- reflective spectra that are more representative of the real world,
- unlike many other charts that are created out of combination of 3
- or 4 colorants.<br>
- A limited CIE reference file is available from X-Rite <a
-href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.txt">here</a>,
- but it is not in the usual CGATS format. To convert it to a CIE
- reference file useful for <span style="font-weight: bold;">scanin</span>,
- you will need to edit the X-Rite file using a <span
- style="text-decoration: underline;">plain text</span> editor,
- first deleting everything before the line starting with "A1" and
+
+ 202</a>:<br>
+ <br>
+ <img style=" width: 41px; height: 141px;" alt="QPCard201"
+ src="QPcard201.jpg">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <img
+ style=" width: 97px; height: 141px;" alt="QPcard202"
+ src="QPcard202.jpg"><br>
+ <br>
+ <h4><a name="PS3"></a>Taking readings from a scanner or camera<br>
+ </h4>
+ The test chart you are using needs to be placed on the scanner, and
+ the scanner needs to be configured to a suitable state, and restored
+ to that same state when used subsequently with the resulting
+ profile. For a camera, the chart needs to be lit in a controlled and
+ even manner using the light source that will be used for subsequent
+ photographs, and should be shot so as to minimise any geometric
+ distortion, although the <a href="scanin.html#p">scanin -p</a> flag
+ may be used to compensate for some degree of distortion. As with any
+ color profiling task, it is important to setup a known and
+ repeatable image processing flow, to ensure that the resulting
+ profile will be usable.<br>
+ <br>
+ The chart should be captured and saved to a TIFF format file. I will
+ assume the resulting file is called scanner.tif. The raster file
+ need only be roughly cropped so as to contain the test chart
+ (including the charts edges).<br>
+ <br>
+ The second step is to extract the RGB values from the scanner.tif
+ file, and match then to the reference CIE values. To locate the
+ patch values in the scan, the <b>scanin</b> tool needs to be given
+ a template <a href="File_Formats.html#.cht">.cht</a> file that
+ describes the features of the chart, and how the test patches are
+ labeled. Also needed is a file containing the CIE values for each of
+ the patches in the chart, which is typically supplied with the
+ chart, available from the manufacturers web site, or has been
+ measured using a spectrometer.<br>
+ <br>
+ <div style="margin-left: 40px;">For an IT8.7/2 chart, this is the <span
+ style="font-weight: bold;">ref/</span><b>it8.cht</b> file
+ supplied with Argyll, and&nbsp; the manufacturer will will supply
+ an individual or batch average file along with the chart
+ containing this information, or downloadable from their web site.
+ For instance, Kodak Q60 target reference files are <a
+ href="ftp://ftp.kodak.com/gastds/Q60DATA/">here</a>.<br>
+ NOTE that the reference file for the IT8.7/2 chart supplied with <span
+ style="font-weight: bold;">Monaco&nbsp;EZcolor</span> can be
+ obtained by unzipping the .mrf file. (You may have to make a copy
+ of the file with a .zip extension to do this.)<br>
+ <br>
+ For the ColorChecker 24 patch chart, the <span
+ style="font-weight: bold;">ref/ColorChecker.cht</span> file
+ should be used, and there is also a <span style="font-weight:
+ bold;">ref/ColorChecker.cie</span> file provided that is based
+ on the manufacturers reference values for the chart. You can also
+ create your own reference file using an instrument and chartread,
+ making use of the chart reference file <span style="font-weight:
+ bold;">ref/ColorChecker.ti2</span>:<br>
+ &nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
+ ColorChecker.ti2<br>
+ Note that due to the small number of patches, a profile created
+ from such a chart is not likely to be very detailed.<br>
+ <br>
+ For the ColorChecker DC chart, the <span style="font-weight:
+ bold;">ref/ColorCheckerDC.cht</span> file should be used, and
+ there will be a ColorCheckerDC reference file supplied by
+ X-Rite/GretagMacbeth with the chart.<br>
+ <br>
+ The ColorChecker SG is relatively expensive, but is preferred by
+ many people because (like the ColorChecker and ColorCheckerDC) its
+ colors are composed of multiple different pigments, giving it
+ reflective spectra that are more representative of the real world,
+ unlike many other charts that are created out of combination of 3
+ or 4 colorants.<br>
+ A limited CIE reference file is available from X-Rite <a
+href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.txt">here</a>,
+ but it is not in the usual CGATS format. To convert it to a CIE
+ reference file useful for <span style="font-weight: bold;">scanin</span>,
+ you will need to edit the X-Rite file using a <span
+ style="text-decoration: underline;">plain text</span> editor,
+ first deleting everything before the line starting with "A1" and
everything after "N10", then prepending <a href="SG_header.txt">this
@@ -1305,95 +1281,83 @@ href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.t
-
-
-
- header</a>, and appending <a href="SG_footer.txt">this footer</a>,
- making sure there are no blank lines inserted in the process.
- There are reports that X-Rite have experimented with different ink
- formulations for certain patches, so the above reference may not
- be as accurate as desired, and it is preferable to measure your
- own chart using a spectrometer, if you have the capability.<br>
- If you do happen to have access to a more comprehensive instrument
- measurement of the ColorChecker SG, or you have measured it
- yourself using a color instrument,<br>
- then you <span style="text-decoration: underline;">may</span>
- need to convert the reference information from spectral <span
- style="font-weight: bold;">ColorCheckerSG.txt</span> file to CIE
- value <span style="font-weight: bold;">ColorCheckerSG.cie</span>
- reference file, follow the following steps:<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="txt2ti3.html">txt2ti3</a>
- ColorCheckerSG.txt ColorCheckerSG<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="spec2cie.html">spec2cie</a>
- ColorCheckerSG.ti3 ColorCheckerSG.cie<br>
- <br>
- For the Eye-One Pro Scan Target 1.4 chart, the <span
- style="font-weight: bold;"><span style="font-weight: bold;">ref/</span>i1_RGB_Scan_1.4.cht</span>
- file should be used, and as there is no reference file
- accompanying this chart, the chart needs to be read with an
- instrument (usually the Eye-One Pro). This can be done using
- chartread,&nbsp; making use of the chart reference file <span
- style="font-weight: bold;">ref/i1_RGB_Scan_1.4.ti2</span>:<br>
- &nbsp;&nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
- i1_RGB_Scan_1.4<br>
- and then rename the resulting <span style="font-weight: bold;">i1_RGB_Scan_1.4.ti3</span>
- file to <span style="font-weight: bold;">i1_RGB_Scan_1.4.cie</span><br>
- <span style="font-weight: bold;"></span><br>
- For the HutchColor HCT chart, the <span style="font-weight:
- bold;"><span style="font-weight: bold;">ref/</span>Hutchcolor.cht</span>
- file should be used, and the reference <span style="font-weight:
- bold;">.txt</span> file downloaded from the HutchColor website.<br>
- <br>
- For the Christophe Métairie's Digital TargeT 003 chart with 285
- patches, the <span style="font-weight: bold;"><span
- style="font-weight: bold;">ref/</span>CMP_DT_003.cht</span>
- file should be used, and the cie reference <span
- style="font-weight: bold;"></span>files come with the chart.<br>
- <br>
- For the Christophe Métairie's Digital Target-4 chart with 570
- patches, the <span style="font-weight: bold;">ref/CMP_Digital_Target-4.cht</span>
- file should be used, and the cie reference <span
- style="font-weight: bold;"></span>files come with the chart.<br>
- <br>
- For the LaserSoft DCPro chart, the <span style="font-weight:
- bold;">ref/LaserSoftDCPro.cht</span> file should be used, and
- reference <span style="font-weight: bold;">.txt</span> file
- downloaded from the <a
- href="http://www.silverfast.com/it8calibration/">Silverfast
- website</a>.<br>
- <br>
- For the Datacolor SpyderCheckr, the <span style="font-weight:
- bold;">ref/SpyderChecker.cht</span> file should be used, and a
- reference <span style="font-weight: bold;">ref/SpyderChecker.cie
- </span>file made from measuring a sample chart is also available.
- Alternately you could create your own reference file by
- transcribing the <a
- href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
- on the Datacolor website. <br>
- <br>
- For the Datacolor SpyderCheckr, the <span style="font-weight:
- bold;">ref/SpyderChecker24.cht</span> file should be used, and a
- reference <span style="font-weight: bold;">ref/SpyderChecker24.cie
-
- </span>file made from measuring a sample chart is also available.
- Alternately you could create your own reference file by
- transcribing the <a
- href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
- on the Datacolor website. <br>
- <br>
- For the QPCard 201, the <span style="font-weight: bold;">ref/QPcard_201.cht</span>
- file should be used, and a reference <span style="font-weight:
- bold;">ref/QPcard_201.cie</span> file made from measuring a
- sample chart is also available. <br>
- <br>
- For the QPCard 202, the <span style="font-weight: bold;">ref/QPcard_202.cht</span>
- file should be used, and a reference <span style="font-weight:
- bold;">ref/QPcard_202.cie</span> file made from measuring a
- sample chart is also available. <br>
- </div>
- <br>
- For any other type of chart, a chart recognition template file will
- need to be created (this is beyond the scope of the current
+
+ header</a>, and appending <a href="SG_footer.txt">this footer</a>,
+ making sure there are no blank lines inserted in the process.
+ There are reports that X-Rite have experimented with different ink
+ formulations for certain patches, so the above reference may not
+ be as accurate as desired, and it is preferable to measure your
+ own chart using a spectrometer, if you have the capability.<br>
+ If you do happen to have access to a more comprehensive instrument
+ measurement of the ColorChecker SG, or you have measured it
+ yourself using a color instrument,<br>
+ then you <span style="text-decoration: underline;">may</span>
+ need to convert the reference information from spectral <span
+ style="font-weight: bold;">ColorCheckerSG.txt</span> file to CIE
+ value <span style="font-weight: bold;">ColorCheckerSG.cie</span>
+ reference file, follow the following steps:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="txt2ti3.html">txt2ti3</a>
+ ColorCheckerSG.txt ColorCheckerSG<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="spec2cie.html">spec2cie</a>
+ ColorCheckerSG.ti3 ColorCheckerSG.cie<br>
+ <br>
+ For the Eye-One Pro Scan Target 1.4 chart, the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">ref/</span>i1_RGB_Scan_1.4.cht</span>
+ file should be used, and as there is no reference file
+ accompanying this chart, the chart needs to be read with an
+ instrument (usually the Eye-One Pro). This can be done using
+ chartread,&nbsp; making use of the chart reference file <span
+ style="font-weight: bold;">ref/i1_RGB_Scan_1.4.ti2</span>:<br>
+ &nbsp;&nbsp;&nbsp; <a href="chartread.html">chartread</a> -n
+ i1_RGB_Scan_1.4<br>
+ and then rename the resulting <span style="font-weight: bold;">i1_RGB_Scan_1.4.ti3</span>
+ file to <span style="font-weight: bold;">i1_RGB_Scan_1.4.cie</span><br>
+ <span style="font-weight: bold;"></span><br>
+ For the HutchColor HCT chart, the <span style="font-weight:
+ bold;"><span style="font-weight: bold;">ref/</span>Hutchcolor.cht</span>
+ file should be used, and the reference <span style="font-weight:
+ bold;">.txt</span> file downloaded from the HutchColor website.<br>
+ <br>
+ For the Christophe Métairie's Digital TargeT 003 chart with 285
+ patches, the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">ref/</span>CMP_DT_003.cht</span>
+ file should be used, and the cie reference <span
+ style="font-weight: bold;"></span>files come with the chart.<br>
+ <br>
+ For the Christophe Métairie's Digital Target-4 chart with 570
+ patches, the <span style="font-weight: bold;">ref/CMP_Digital_Target-4.cht</span>
+ file should be used, and the cie reference <span
+ style="font-weight: bold;"></span>files come with the chart.<br>
+ <br>
+ For the LaserSoft DCPro chart, the <span style="font-weight:
+ bold;">ref/LaserSoftDCPro.cht</span> file should be used, and
+ reference <span style="font-weight: bold;">.txt</span> file
+ downloaded from the <a
+ href="http://www.silverfast.com/it8calibration/">Silverfast
+ website</a>.<br>
+ <br>
+ For the Datacolor SpyderCheckr, the <span style="font-weight:
+ bold;">ref/SpyderChecker.cht</span> file should be used, and a
+ reference <span style="font-weight: bold;">ref/SpyderChecker.cie
+ </span>file made from measuring a sample chart is also available.
+ Alternately you could create your own reference file by
+ transcribing the <a
+ href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
+ on the Datacolor website. <br>
+ <br>
+ For the QPCard 201, the <span style="font-weight: bold;">ref/QPcard_201.cht</span>
+ file should be used, and a reference <span style="font-weight:
+ bold;">ref/QPcard_201.cie</span> file made from measuring a
+ sample chart is also available. <br>
+ <br>
+ For the QPCard 202, the <span style="font-weight: bold;">ref/QPcard_202.cht</span>
+ file should be used, and a reference <span style="font-weight:
+ bold;">ref/QPcard_202.cie</span> file made from measuring a
+ sample chart is also available. <br>
+ </div>
+ <br>
+ For any other type of chart, a chart recognition template file will
+ need to be created (this is beyond the scope of the current
documentation, although see&nbsp; the <a href="cht_format.html">.cht_format
@@ -1450,405 +1414,403 @@ href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.t
-
-
-
- documentation</a>).<br>
- <br>
- To create the scanner .ti3 file, run the <b>scanin</b> tool as
- follows (assuming an IT8 chart is being used):<br>
- <br>
- <a href="scanin.html"> scanin</a> -v scanner.tif It8.cht It8ref.txt<br>
- <br>
- "It8ref.txt" or "It8ref.cie" is assumed to be the name of the CIE
- reference file supplied by the chart manufacturer. The resulting
- file will be named "<b>scanner.ti3</b>".<br>
- <br>
- <span style="font-weight: bold;">scanin</span> will process 16 bit
- per component .tiff files, which (if the scanner is capable of
- creating such files),&nbsp; may improve the quality of the profile.
- <br>
- <br>
- If you have any doubts about the correctness of the chart
- recognition, or the subsequent profile's delta E report is unusual,
- then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
- and examine the <span style="font-weight: bold;">diag.tif</span>
- diagnostic file, to make sure that the patches are identified and
- aligned correctly. If you have problems getting good automatic
- alignment, then consider doing a manual alignment by locating the
- fiducial marks on your scan, and feeding them into scanin <a
- href="scanin.html#F">-F</a> parameters. The fiducial marks should
- be listed in a clockwise direction starting at the top left.<br>
- <h4><a name="PS4"></a>Creating a scanner or camera input profile</h4>
- Similar to a display profile, an input profile can be either a
- shaper/matrix or LUT based profile. Well behaved input devices will
- probably give the best results with a shaper/matrix profile, and
- this may also be the best choice if your test chart has a small or
- unevenly distributed set of test patchs (ie. the IT8.7.2). If a
- shaper/matrix profile is a poor fit, consider using a LUT type
- profile.<br>
- <br>
- When creating a LUT type profile, there is the choice of XYZ or
- L*a*b* PCS (Device independent, Profile Connection Space). Often for
- input devices, it is better to choose the XYZ PCS, as this may be a
- better fit given that input devices are usually close to being
- linearly additive in behaviour.<br>
- <br>
- If the purpose of the input profile is to use it as a substitute for
- a colorimeter, then the <b>-u</b> flag should be used to avoid
- clipping values above the white point. Unless the shaper/matrix type
- profile is a very good fit, it is probably advisable to use a LUT
- type profile in this situation.<br>
- <br>
- To create a matrix/shaper profile, the following suffices:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Scanner</a> <a href="colprof.html#E">A"</a>
- <a href="colprof.html#q">-qm</a> <a href="colprof.html#a">-as</a> <a
- href="colprof.html#p1">scanner</a><br>
- <br>
- For an XYZ PCS LUT based profile then the following would be used:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-ax</a> <a href="colprof.html#p1">scanner</a><br>
- <br>
- For the purposes of a poor mans colorimeter, the following would
- generally be used:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-ax</a> <a href="colprof.html#u">-u</a> <a
- href="colprof.html#p1">scanner</a><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably. Depending on the type of device, and the consistency of
- the readings, average errors of 5 or less, and maximum errors of 15
- or less would normally be expected. If errors are grossly higher
- than this, then this is an indication that something is seriously
- wrong with the device measurement, or profile creation.<br>
- <br>
- If profiling a <span style="font-weight: bold;">camera</span> in <span
- style="font-weight: bold;">RAW</span> mode, then there may be some
- advantage in creating a pure matrix only profile, in which it is
- assumed that the camera response is completely linear. This may
- reduce extrapolation artefacts. If setting the white point will be
- done in some application, then it may also be an advantage to use
- the <span style="font-weight: bold;">-u</span> flag and avoid
- setting the white point to that of the profile chart:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Camera"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#a">-am</a> <a href="colprof.html#u">-u</a> <a
- href="colprof.html#p1">scanner</a><br>
- <br>
- <br>
- <hr size="2" width="100%">
- <h3><a name="PP1"></a>Profiling Printers<br>
- </h3>
- The overall process is to create a set of device measurement target
- values, print them out, measure them, and then create an ICC profile
- from the measurements. If the printer is an RGB based printer, then
- the process is only slightly more complicated than profiling a
- display. If the printer is CMYK based, then some additional
- parameters are required to set the total ink limit (TAC) and
- &nbsp;black generation curve.<br>
- <h4><a name="PP2"></a>Creating a print profile test chart</h4>
- The first step in profiling any output device, is to create a set of
- device colorspace test values. The important parameters needed are:<br>
- <ul>
- <li>What colorspace does the device use ?</li>
- <li>How many test patches do I want to use/what paper size do I
- want to use ?</li>
- <li>What instrument am I going to use to read the patches ?<br>
- </li>
- <li>If it is a CMYK device, what is the total ink limit ?<br>
- </li>
- <li>What information do I already have about how the device
- behaves ?</li>
- </ul>
- Most printers running through simple drivers will appear as if they
- are RGB devices. In fact there is no such thing as a real RGB
- printer, since printers use white media and the colorant must
- subtract from the light reflected on it to create color, but the
- printer itself turns the incoming RGB into the native print
- colorspace, so for this reason we will tell targen to use the "Print
- RGB" colorspace, so that it knows that it's really a subtractive
- media. Other drivers will drive a printer more directly, and will
- expect a CMYK profile. [Currently Argyll is not capable of creating
- an ICC profile for devices with more colorants than CMYK. When this
- capability is introduced, it will by creating an additional
- separation profile which then allows the printer to be treated as a
- CMY or CMYK printer.] One way of telling what sort of profile is
- expected for your device is to examine an existing profile for that
- device using <a href="http://www.argyllcms.com/doc/iccdump.html">iccdump</a>.<br>
- <br>
- The number of test patches will depend somewhat on what quality
- profile you want to make, how well behaved the printer is, as well
- as the effort needed to read the number of test values. Generally it
- is convenient to fill a certain paper size with the maximum number
- of test values that will fit.<br>
- <br>
- At a minimum, for an "RGB" device, a few hundred values are needed
- (400-1000). For high quality CMYK profiles, 1000-3000 is not an
- unreasonable number of patches.<br>
- <br>
- To assist the determination of test patch values, it can help to
- have a rough idea of how the device behaves, so that the device test
- point locations can be pre-conditioned. This could be in the form of
- an ICC profile of a similar device, or a lower quality, or previous
- profile for that particular device. If one were going to make a very
- high quality Lut based profile, then it might be worthwhile to make
- up a smaller, preliminary shaper/matrix profile using a few hundred
- test points, before embarking on testing the device with several
- thousand.<br>
- <br>
- The documentation for the <a
- href="http://www.argyllcms.com/doc/targen.html">targen</a> tool
- lists a <a href="http://www.argyllcms.com/doc/targen.html#Table">table</a>
- of paper sizes and number of &nbsp;patches for typical situations.<br>
- <br>
- For a CMYK device, a total ink limit usually needs to be specified.
- Sometimes a device will have a maximum total ink limit set by its
- manufacturer or operator, and some CMYK systems (such as chemical
- proofing systems) don't have any limit. Typical printing devices
- such as Xerographic printers, inkjet printers and printing presses
- will have a limit. The exact procedure for determining an ink limit
- is outside the scope of this document, but one way of going about
- this might be to generate some small (say a few hundred patches)
- with targen &amp; pritntarg with different total ink limits, and
- printing them out, making the ink limit as large as possible without
- striking problems that are caused by too much ink.<br>
- <br>
- Generally one wants to use the maximum possible amount of ink to
- maximize the gamut available on the device. For most CMYK devices,
- an ink limit between 200 and 400 is usual, but and ink limit of 250%
- or over is generally desirable for reasonably dense blacks and dark
- saturated colors. And ink limit of less than 200% will begin to
- compromise the fully saturated gamut, as secondary colors (ie
- combinations of any two primary colorants) will not be able to reach
- full strength.<br>
- <br>
- Once an ink limit is used in printing the characterization test
- chart for a device, it becomes a critical parameter in knowing what
- the characterized gamut of the device is. If after printing the test
- chart, a greater ink limit were to be used, the the software would
- effectively be extrapolating the device behaviour at total ink
- levels beyond that used in the test chart, leading to inaccuracies.<br>
- <br>
- Generally in Argyll, the ink limit is established when creating the
- test chart values, and then carried through the profile making
- process automatically. Once the profile has been made however, the
- ink limit is no longer recorded, and you, the user, will have to
- keep track of it if the ICC profile is used in any program than
- needs to know the usable gamut of the device.<br>
- <br>
- <br>
- Lets consider two devices in our examples, "PrinterA" which is an
- "RGB" device, and "PrinterB" which is CMYK, and has a target ink
- limit of 250%. <br>
- <br>
- The simplest approach is to make a set of test values that is
- independent of the characteristics of the particular device:<br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
- <a href="targen.html#p1">PrinterA</a><br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
- <a href="targen.html#f">-f1053</a> <a href="targen.html#p1">PrinterB</a><br>
- <br>
- The number of patches chosen here happens to be right for an A4
- paper size being read using a Spectroscan instrument. See the <a
- href="targen.html#Table">table</a> in&nbsp; the <a
- href="targen.html">targen</a> documentation for some other
- suggested numbers.<br>
- <br>
- If there is a preliminary or previous profile called "OldPrinterA"
- available, and we want to try creating a "pre-conditioned" set of
- test values that will more efficiently sample the device response,
- then the following would achieve this:<u><br>
- </u><br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
- <a href="targen.html#c">-c OldPrinterA</a>&nbsp;<a
- href="targen.html#p1">PrinterA</a><br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
- <a href="targen.html#f">-f1053</a> <a href="targen.html#c">-c
- OldPrinterB</a> <a href="targen.html#p1">PrinterB</a><br>
- <a href="targen.html#p1"></a><br>
- <br>
- The output of <b>targen</b> will be the file PrinterA.ti1 and
- PrinterB.ti1 respectively, containing the device space test values,
- as well as expected CIE values used for chart recognition purposes.<br>
- <br>
- <h4><a name="PP2b"></a>Printing a print profile test chart<br>
- <br>
- </h4>
- The next step is turn the test values in to a PostScript or TIFF
- raster test file that can printed on the device. The basic
- information that needs to be supplied is the type of instrument that
- will be used to read the patches, as well as the paper size it is to
- be formatted for.<br>
- <br>
- For an X-Rite DTP41, the following would be typical:<br>
- <br>
- <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
- <a href="printtarg.html#i">-i41</a> <a href="printtarg.html#p">-pA4</a>
- <a href="printtarg.html#p1">PrinterA</a><br>
- &nbsp;<br>
- For a Gretag Eye-One Pro, the following would be typical:<br>
- <br>
- <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
- <a href="printtarg.html#i">-ii1</a> <a href="printtarg.html#p">-pA4</a>
- <a href="printtarg.html#p1">PrinterA</a><br>
- <br>
- For using with a scanner as a colorimeter, the Gretag Spectroscan
- layout is suitable, but the <a href="printtarg.html#s">-s</a> flag
- should be used so as to generate a layout suitable for scan
- recognition, as well as generating the scan recognition template
- files. (You probably want to use less patches with <span
- style="font-weight: bold;">targen</span>, when using the <span
- style="font-weight: bold;">printtarg -s</span> flag, e.g. 1026
- patches for an A4R page, etc.) The following would be typical:<br>
- <br>
- <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
- <a href="printtarg.html#s">-s</a> <a href="printtarg.html#i">-iSS</a>
- <a href="printtarg.html#p">-pA4R</a> <a href="printtarg.html#p1">PrinterA</a><br>
- <span style="font-weight: bold;"><br>
- printtarg</span> reads the PrinterA.ti1 file, creates a
- PrinterA.ti2 file containing the layout information as well as the
- device values and expected CIE values, as well as a PrinterA.ps file
- containing the test chart. If the <span style="font-weight: bold;">-s</span>
- flag is used, one or more PrinterA.cht files is created to allow the
- <a href="scanin.html">scanin</a> program to recognize the chart.<br>
- <br>
- To create TIFF raster files rather than PostScript, use the <a
- href="printtarg.html#t"><span style="font-weight: bold;">-t</span></a>
- flag.<br>
- <br>
- <span style="font-weight: bold;">GSview</span> is a good program to
- use to check what the PostScript file will look like, without
- actually printing it out. You could also use <span
- style="font-weight: bold;">Photoshop</span> or <span
- style="font-weight: bold;">ImageMagick</span> for this purpose.<br>
- <br>
- The last step is to print the chart out.<br>
- <br>
- Using a suitable PostScript or raster file printing program,
- downloader, print the chart. If you are not using a TIFF test chart,
- and you do not have a PostScript capable printer, then an
- interpreter like GhostScript or even Photoshop could be used to
- rasterize the file into something that can be printed. Note that it
- is important that the PostScript interpreter or TIFF printing
- application and printer configuration is setup for a device
- profiling run, and that any sort of color conversion of color
- correction be turned off so that the device values in the PostScript
- or TIFF file are sent directly to the device. If the device has a
- calibration system, then it would be usual to have setup and
- calibrated the device before starting the profiling run, and to
- apply calibration to the chart values. If Photoshop was to be used,
- then either the chart needs to be a single page, or separate .eps or
- .tiff files for each page should be used, so that they can be
- converted and printed one at a time (see the <a
- href="printtarg.html#e">-e</a> and <a href="printtarg.html#t">-t</a>
- flags).<br>
- <br>
- <h4><a name="PP3"></a>Reading a print test chart using an instrument</h4>
- Once the test chart has been printed, the color of the patches needs
- to be read using a suitable instrument.<br>
- <br>
- Several different instruments are currently supported, some that
- need to be used patch by patch, some read a strip at a time, and
- some read a sheet at a time. See <a href="instruments.html">instruments</a>
- for a current list.<br>
- <br>
- The instrument needs to be connected to your computer before running
- the <a href="chartread.html">chartread</a> command. Both serial
- port and USB connected Instruments are supported. A serial port to
- USB adapter might have to be used if your computer doesn't have any
- serial ports, and you have a serial interface connected instrument.<br>
- <br>
- If you run <a href="chartread.html">chartread</a> so as to print
- out its usage message (ie. by using a <span style="font-weight:
- bold;">-?</span> or <span style="font-weight: bold;">--</span>
- flags), then it will list any identified serial ports or USB
- connected instruments, and their corresponding number for the <a
- href="chartread.html#c">-c</a> option. By default, <a
- href="chartread.html">chartread</a> will try to connect to the
- first available USB instrument, or an instrument on the first serial
- port.<br>
- <br>
- The only arguments required is to specify the basename of the .ti2
- file. If a non-default serial port is to be used, then the <span
- style="font-weight: bold;">-c</span> option would also be
- specified.<br>
- <br>
- &nbsp;e.g. for a Spectroscan on the second port:<br>
- <br>
- <a href="chartread.html">chartread</a> <a href="chartread.html#c">-c2</a>
- <a href="chartread.html#p1">PrinterA</a><br>
- <br>
- For a DTP41 to the default serial port:<br>
- <br>
- <a href="chartread.html">chartread</a><a href="chartread.html#i"></a>
- <a href="chartread.html#p1">PrinterA</a><br>
- <br>
- <span style="font-weight: bold;">chartread</span> will interactively
- prompt you through the process of reading each sheet or strip. See <a
- href="chartread.html">chartread</a> for more details on the
- responses for each type of instrument. Continue with <a
- href="Scenarios.html#PP5">Creating a printer profile</a>.<br>
- <br>
- <h4><a name="PP4"></a>Reading a print test chart using a scanner or
- camera<br>
- </h4>
- <br>
- Argyll supports using a scanner or even a camera as a substitute for
- a colorimeter. While a scanner or camera is no replacement for a
- color measurement instrument, it may give acceptable results in some
- situations, and may give better results than a generic profile for a
- printing device.<br>
- <br>
- The main limitation of the scanner-as-colorimeter approach are:<br>
- <br>
- * The scanner dynamic range and/or precision may not match the
- printers or what is required for a good profile.<br>
- * The spectral interaction of the scanner test chart and printer
- test chart with the scanner spectral response can cause color
- errors.<br>
- * Spectral differences caused by different black amounts in the
- print test chart can cause color errors. <br>
- * The scanner reference chart gamut may be much smaller than the
- printers gamut, making the scanner profile too inaccurate to be
- useful. <br>
- <br>
- As well as some of the above, a camera may not be suitable if it
- automatically adjusts exposure or white point when taking a picture,
- and this behavior cannot be disabled.<br>
- <br>
- The end result is often a profile that has a noticeable color cast,
- compared to a profile created using a colorimeter or spectrometer.<br>
- <br>
- <br>
- It is assumed that you have created a scanner or camera profile
- following the <a
- href="http://www.argyllcms.com/doc/Scenarios.html#PS1">procedure</a>
- outline above. For best possible results it is advisable to both
- profile the scanner or camera, and use it in scanning the printed
- test chart, in as "raw" mode as possible (i.e. using 16 bits per
- component images, if the scanner or camera is capable of doing so;
- not setting white or black points, using a fixed exposure etc.). It
- is generally advisable to create a LUT type input profile, and use
- the <a href="http://www.argyllcms.com/doc/colprof.html#u">-u</a>
- flag to avoid clipping scanned value whiter than the input
- calibration chart.<br>
- <br>
- Scan or photograph your printer chart (or charts) on the scanner or
+
+ documentation</a>).<br>
+ <br>
+ To create the scanner .ti3 file, run the <b>scanin</b> tool as
+ follows (assuming an IT8 chart is being used):<br>
+ <br>
+ <a href="scanin.html"> scanin</a> -v scanner.tif It8.cht It8ref.txt<br>
+ <br>
+ "It8ref.txt" or "It8ref.cie" is assumed to be the name of the CIE
+ reference file supplied by the chart manufacturer. The resulting
+ file will be named "<b>scanner.ti3</b>".<br>
+ <br>
+ <span style="font-weight: bold;">scanin</span> will process 16 bit
+ per component .tiff files, which (if the scanner is capable of
+ creating such files),&nbsp; may improve the quality of the profile.
+ <br>
+ <br>
+ If you have any doubts about the correctness of the chart
+ recognition, or the subsequent profile's delta E report is unusual,
+ then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
+ and examine the <span style="font-weight: bold;">diag.tif</span>
+ diagnostic file, to make sure that the patches are identified and
+ aligned correctly. If you have problems getting good automatic
+ alignment, then consider doing a manual alignment by locating the
+ fiducial marks on your scan, and feeding them into scanin <a
+ href="scanin.html#F">-F</a> parameters. The fiducial marks should
+ be listed in a clockwise direction starting at the top left.<br>
+ <h4><a name="PS4"></a>Creating a scanner or camera input profile</h4>
+ Similar to a display profile, an input profile can be either a
+ shaper/matrix or LUT based profile. Well behaved input devices will
+ probably give the best results with a shaper/matrix profile, and
+ this may also be the best choice if your test chart has a small or
+ unevenly distributed set of test patchs (ie. the IT8.7.2). If a
+ shaper/matrix profile is a poor fit, consider using a LUT type
+ profile.<br>
+ <br>
+ When creating a LUT type profile, there is the choice of XYZ or
+ L*a*b* PCS (Device independent, Profile Connection Space). Often for
+ input devices, it is better to choose the XYZ PCS, as this may be a
+ better fit given that input devices are usually close to being
+ linearly additive in behaviour.<br>
+ <br>
+ If the purpose of the input profile is to use it as a substitute for
+ a colorimeter, then the <b>-u</b> flag should be used to avoid
+ clipping values above the white point. Unless the shaper/matrix type
+ profile is a very good fit, it is probably advisable to use a LUT
+ type profile in this situation.<br>
+ <br>
+ To create a matrix/shaper profile, the following suffices:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner</a> <a href="colprof.html#E">A"</a>
+ <a href="colprof.html#q">-qm</a> <a href="colprof.html#a">-as</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ For an XYZ PCS LUT based profile then the following would be used:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-ax</a> <a href="colprof.html#p1">scanner</a><br>
+ <br>
+ For the purposes of a poor mans colorimeter, the following would
+ generally be used:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-ax</a> <a href="colprof.html#u">-u</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably. Depending on the type of device, and the consistency of
+ the readings, average errors of 5 or less, and maximum errors of 15
+ or less would normally be expected. If errors are grossly higher
+ than this, then this is an indication that something is seriously
+ wrong with the device measurement, or profile creation.<br>
+ <br>
+ If profiling a <span style="font-weight: bold;">camera</span> in <span
+ style="font-weight: bold;">RAW</span> mode, then there may be some
+ advantage in creating a pure matrix only profile, in which it is
+ assumed that the camera response is completely linear. This may
+ reduce extrapolation artefacts. If setting the white point will be
+ done in some application, then it may also be an advantage to use
+ the <span style="font-weight: bold;">-u</span> flag and avoid
+ setting the white point to that of the profile chart:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Camera"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-am</a> <a href="colprof.html#u">-u</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ <br>
+ <hr size="2" width="100%">
+ <h3><a name="PP1"></a>Profiling Printers<br>
+ </h3>
+ The overall process is to create a set of device measurement target
+ values, print them out, measure them, and then create an ICC profile
+ from the measurements. If the printer is an RGB based printer, then
+ the process is only slightly more complicated than profiling a
+ display. If the printer is CMYK based, then some additional
+ parameters are required to set the total ink limit (TAC) and
+ &nbsp;black generation curve.<br>
+ <h4><a name="PP2"></a>Creating a print profile test chart</h4>
+ The first step in profiling any output device, is to create a set of
+ device colorspace test values. The important parameters needed are:<br>
+ <ul>
+ <li>What colorspace does the device use ?</li>
+ <li>How many test patches do I want to use/what paper size do I
+ want to use ?</li>
+ <li>What instrument am I going to use to read the patches ?<br>
+ </li>
+ <li>If it is a CMYK device, what is the total ink limit ?<br>
+ </li>
+ <li>What information do I already have about how the device
+ behaves ?</li>
+ </ul>
+ Most printers running through simple drivers will appear as if they
+ are RGB devices. In fact there is no such thing as a real RGB
+ printer, since printers use white media and the colorant must
+ subtract from the light reflected on it to create color, but the
+ printer itself turns the incoming RGB into the native print
+ colorspace, so for this reason we will tell targen to use the "Print
+ RGB" colorspace, so that it knows that it's really a subtractive
+ media. Other drivers will drive a printer more directly, and will
+ expect a CMYK profile. [Currently Argyll is not capable of creating
+ an ICC profile for devices with more colorants than CMYK. When this
+ capability is introduced, it will by creating an additional
+ separation profile which then allows the printer to be treated as a
+ CMY or CMYK printer.] One way of telling what sort of profile is
+ expected for your device is to examine an existing profile for that
+ device using <a href="http://www.argyllcms.com/doc/iccdump.html">iccdump</a>.<br>
+ <br>
+ The number of test patches will depend somewhat on what quality
+ profile you want to make, how well behaved the printer is, as well
+ as the effort needed to read the number of test values. Generally it
+ is convenient to fill a certain paper size with the maximum number
+ of test values that will fit.<br>
+ <br>
+ At a minimum, for an "RGB" device, a few hundred values are needed
+ (400-1000). For high quality CMYK profiles, 1000-3000 is not an
+ unreasonable number of patches.<br>
+ <br>
+ To assist the determination of test patch values, it can help to
+ have a rough idea of how the device behaves, so that the device test
+ point locations can be pre-conditioned. This could be in the form of
+ an ICC profile of a similar device, or a lower quality, or previous
+ profile for that particular device. If one were going to make a very
+ high quality Lut based profile, then it might be worthwhile to make
+ up a smaller, preliminary shaper/matrix profile using a few hundred
+ test points, before embarking on testing the device with several
+ thousand.<br>
+ <br>
+ The documentation for the <a
+ href="http://www.argyllcms.com/doc/targen.html">targen</a> tool
+ lists a <a href="http://www.argyllcms.com/doc/targen.html#Table">table</a>
+ of paper sizes and number of &nbsp;patches for typical situations.<br>
+ <br>
+ For a CMYK device, a total ink limit usually needs to be specified.
+ Sometimes a device will have a maximum total ink limit set by its
+ manufacturer or operator, and some CMYK systems (such as chemical
+ proofing systems) don't have any limit. Typical printing devices
+ such as Xerographic printers, inkjet printers and printing presses
+ will have a limit. The exact procedure for determining an ink limit
+ is outside the scope of this document, but one way of going about
+ this might be to generate some small (say a few hundred patches)
+ with targen &amp; pritntarg with different total ink limits, and
+ printing them out, making the ink limit as large as possible without
+ striking problems that are caused by too much ink.<br>
+ <br>
+ Generally one wants to use the maximum possible amount of ink to
+ maximize the gamut available on the device. For most CMYK devices,
+ an ink limit between 200 and 400 is usual, but and ink limit of 250%
+ or over is generally desirable for reasonably dense blacks and dark
+ saturated colors. And ink limit of less than 200% will begin to
+ compromise the fully saturated gamut, as secondary colors (ie
+ combinations of any two primary colorants) will not be able to reach
+ full strength.<br>
+ <br>
+ Once an ink limit is used in printing the characterization test
+ chart for a device, it becomes a critical parameter in knowing what
+ the characterized gamut of the device is. If after printing the test
+ chart, a greater ink limit were to be used, the the software would
+ effectively be extrapolating the device behaviour at total ink
+ levels beyond that used in the test chart, leading to inaccuracies.<br>
+ <br>
+ Generally in Argyll, the ink limit is established when creating the
+ test chart values, and then carried through the profile making
+ process automatically. Once the profile has been made however, the
+ ink limit is no longer recorded, and you, the user, will have to
+ keep track of it if the ICC profile is used in any program than
+ needs to know the usable gamut of the device.<br>
+ <br>
+ <br>
+ Lets consider two devices in our examples, "PrinterA" which is an
+ "RGB" device, and "PrinterB" which is CMYK, and has a target ink
+ limit of 250%. <br>
+ <br>
+ The simplest approach is to make a set of test values that is
+ independent of the characteristics of the particular device:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
+ <a href="targen.html#p1">PrinterA</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
+ <a href="targen.html#f">-f1053</a> <a href="targen.html#p1">PrinterB</a><br>
+ <br>
+ The number of patches chosen here happens to be right for an A4
+ paper size being read using a Spectroscan instrument. See the <a
+ href="targen.html#Table">table</a> in&nbsp; the <a
+ href="targen.html">targen</a> documentation for some other
+ suggested numbers.<br>
+ <br>
+ If there is a preliminary or previous profile called "OldPrinterA"
+ available, and we want to try creating a "pre-conditioned" set of
+ test values that will more efficiently sample the device response,
+ then the following would achieve this:<u><br>
+ </u><br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
+ <a href="targen.html#c">-c OldPrinterA</a>&nbsp;<a
+ href="targen.html#p1">PrinterA</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
+ <a href="targen.html#f">-f1053</a> <a href="targen.html#c">-c
+ OldPrinterB</a> <a href="targen.html#p1">PrinterB</a><br>
+ <a href="targen.html#p1"></a><br>
+ <br>
+ The output of <b>targen</b> will be the file PrinterA.ti1 and
+ PrinterB.ti1 respectively, containing the device space test values,
+ as well as expected CIE values used for chart recognition purposes.<br>
+ <br>
+ <h4><a name="PP2b"></a>Printing a print profile test chart<br>
+ <br>
+ </h4>
+ The next step is turn the test values in to a PostScript or TIFF
+ raster test file that can printed on the device. The basic
+ information that needs to be supplied is the type of instrument that
+ will be used to read the patches, as well as the paper size it is to
+ be formatted for.<br>
+ <br>
+ For an X-Rite DTP41, the following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#i">-i41</a> <a href="printtarg.html#p">-pA4</a>
+ <a href="printtarg.html#p1">PrinterA</a><br>
+ &nbsp;<br>
+ For a Gretag Eye-One Pro, the following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#i">-ii1</a> <a href="printtarg.html#p">-pA4</a>
+ <a href="printtarg.html#p1">PrinterA</a><br>
+ <br>
+ For using with a scanner as a colorimeter, the Gretag Spectroscan
+ layout is suitable, but the <a href="printtarg.html#s">-s</a> flag
+ should be used so as to generate a layout suitable for scan
+ recognition, as well as generating the scan recognition template
+ files. (You probably want to use less patches with <span
+ style="font-weight: bold;">targen</span>, when using the <span
+ style="font-weight: bold;">printtarg -s</span> flag, e.g. 1026
+ patches for an A4R page, etc.) The following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#s">-s</a> <a href="printtarg.html#i">-iSS</a>
+ <a href="printtarg.html#p">-pA4R</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <span style="font-weight: bold;"><br>
+ printtarg</span> reads the PrinterA.ti1 file, creates a
+ PrinterA.ti2 file containing the layout information as well as the
+ device values and expected CIE values, as well as a PrinterA.ps file
+ containing the test chart. If the <span style="font-weight: bold;">-s</span>
+ flag is used, one or more PrinterA.cht files is created to allow the
+ <a href="scanin.html">scanin</a> program to recognize the chart.<br>
+ <br>
+ To create TIFF raster files rather than PostScript, use the <a
+ href="printtarg.html#t"><span style="font-weight: bold;">-t</span></a>
+ flag.<br>
+ <br>
+ <span style="font-weight: bold;">GSview</span> is a good program to
+ use to check what the PostScript file will look like, without
+ actually printing it out. You could also use <span
+ style="font-weight: bold;">Photoshop</span> or <span
+ style="font-weight: bold;">ImageMagick</span> for this purpose.<br>
+ <br>
+ The last step is to print the chart out.<br>
+ <br>
+ Using a suitable PostScript or raster file printing program,
+ downloader, print the chart. If you are not using a TIFF test chart,
+ and you do not have a PostScript capable printer, then an
+ interpreter like GhostScript or even Photoshop could be used to
+ rasterize the file into something that can be printed. Note that it
+ is important that the PostScript interpreter or TIFF printing
+ application and printer configuration is setup for a device
+ profiling run, and that any sort of color conversion of color
+ correction be turned off so that the device values in the PostScript
+ or TIFF file are sent directly to the device. If the device has a
+ calibration system, then it would be usual to have setup and
+ calibrated the device before starting the profiling run, and to
+ apply calibration to the chart values. If Photoshop was to be used,
+ then either the chart needs to be a single page, or separate .eps or
+ .tiff files for each page should be used, so that they can be
+ converted and printed one at a time (see the <a
+ href="printtarg.html#e">-e</a> and <a href="printtarg.html#t">-t</a>
+ flags).<br>
+ <br>
+ <h4><a name="PP3"></a>Reading a print test chart using an instrument</h4>
+ Once the test chart has been printed, the color of the patches needs
+ to be read using a suitable instrument.<br>
+ <br>
+ Several different instruments are currently supported, some that
+ need to be used patch by patch, some read a strip at a time, and
+ some read a sheet at a time. See <a href="instruments.html">instruments</a>
+ for a current list.<br>
+ <br>
+ The instrument needs to be connected to your computer before running
+ the <a href="chartread.html">chartread</a> command. Both serial
+ port and USB connected Instruments are supported. A serial port to
+ USB adapter might have to be used if your computer doesn't have any
+ serial ports, and you have a serial interface connected instrument.<br>
+ <br>
+ If you run <a href="chartread.html">chartread</a> so as to print
+ out its usage message (ie. by using a <span style="font-weight:
+ bold;">-?</span> or <span style="font-weight: bold;">--</span>
+ flags), then it will list any identified serial ports or USB
+ connected instruments, and their corresponding number for the <a
+ href="chartread.html#c">-c</a> option. By default, <a
+ href="chartread.html">chartread</a> will try to connect to the
+ first available USB instrument, or an instrument on the first serial
+ port.<br>
+ <br>
+ The only arguments required is to specify the basename of the .ti2
+ file. If a non-default serial port is to be used, then the <span
+ style="font-weight: bold;">-c</span> option would also be
+ specified.<br>
+ <br>
+ &nbsp;e.g. for a Spectroscan on the second port:<br>
+ <br>
+ <a href="chartread.html">chartread</a> <a href="chartread.html#c">-c2</a>
+ <a href="chartread.html#p1">PrinterA</a><br>
+ <br>
+ For a DTP41 to the default serial port:<br>
+ <br>
+ <a href="chartread.html">chartread</a><a href="chartread.html#i"></a>
+ <a href="chartread.html#p1">PrinterA</a><br>
+ <br>
+ <span style="font-weight: bold;">chartread</span> will interactively
+ prompt you through the process of reading each sheet or strip. See <a
+ href="chartread.html">chartread</a> for more details on the
+ responses for each type of instrument. Continue with <a
+ href="Scenarios.html#PP5">Creating a printer profile</a>.<br>
+ <br>
+ <h4><a name="PP4"></a>Reading a print test chart using a scanner or
+ camera<br>
+ </h4>
+ <br>
+ Argyll supports using a scanner or even a camera as a substitute for
+ a colorimeter. While a scanner or camera is no replacement for a
+ color measurement instrument, it may give acceptable results in some
+ situations, and may give better results than a generic profile for a
+ printing device.<br>
+ <br>
+ The main limitation of the scanner-as-colorimeter approach are:<br>
+ <br>
+ * The scanner dynamic range and/or precision may not match the
+ printers or what is required for a good profile.<br>
+ * The spectral interaction of the scanner test chart and printer
+ test chart with the scanner spectral response can cause color
+ errors.<br>
+ * Spectral differences caused by different black amounts in the
+ print test chart can cause color errors. <br>
+ * The scanner reference chart gamut may be much smaller than the
+ printers gamut, making the scanner profile too inaccurate to be
+ useful. <br>
+ <br>
+ As well as some of the above, a camera may not be suitable if it
+ automatically adjusts exposure or white point when taking a picture,
+ and this behavior cannot be disabled.<br>
+ <br>
+ The end result is often a profile that has a noticeable color cast,
+ compared to a profile created using a colorimeter or spectrometer.<br>
+ <br>
+ <br>
+ It is assumed that you have created a scanner or camera profile
+ following the <a
+ href="http://www.argyllcms.com/doc/Scenarios.html#PS1">procedure</a>
+ outline above. For best possible results it is advisable to both
+ profile the scanner or camera, and use it in scanning the printed
+ test chart, in as "raw" mode as possible (i.e. using 16 bits per
+ component images, if the scanner or camera is capable of doing so;
+ not setting white or black points, using a fixed exposure etc.). It
+ is generally advisable to create a LUT type input profile, and use
+ the <a href="http://www.argyllcms.com/doc/colprof.html#u">-u</a>
+ flag to avoid clipping scanned value whiter than the input
+ calibration chart.<br>
+ <br>
+ Scan or photograph your printer chart (or charts) on the scanner or
camera previously profiled. <big><span style="font-weight: bold;">The
@@ -1906,100 +1868,98 @@ href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.t
-
-
-
- scanner or camera must be configured and used exactly the same
- as it was when it was profiled.</span></big><br>
- <br>
- I will assume the resulting scan/photo input file is called <span
- style="font-weight: bold;">PrinterB.tif</span> (or <span
- style="font-weight: bold;">PrinterB1.tif</span>, <span
- style="font-weight: bold;">PrinterB2.tif</span> etc. in the case
- of multiple charts). As with profiling the scanner or camera, the
- raster file need only be roughly cropped so as to contain the test
- chart.<br>
- <br>
- The scanner recognition files created when <span
- style="font-weight: bold;">printtarg</span> was run is assumed to
- be called <span style="font-weight: bold;">PrinterB.cht</span>.
- Using the scanner profile created previously (assumed to be called <span
- style="font-weight: bold;">scanner.icm</span>), the printer test
- chart scan patches are converted to CIE values using the <span
- style="font-weight: bold;">scanin</span> tool:<br>
- <br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB.tif</a>
- <a href="scanin.html#cp2">PrinterB.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <br>
- If there were multiple test chart pages, the results would be
- accumulated page by page using the <a href="scanin.html#ca">-ca</a>
- option, ie., if there were 3 pages:<br>
- <br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB1.tif</a>
- <a href="scanin.html#cp2">PrinterB1.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB2.tif</a>
- <a href="scanin.html#cp2">PrinterB2.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
- href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB3.tif</a>
- <a href="scanin.html#cp2">PrinterB3.cht</a> <a
- href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
- <br>
- Now that the <span style="font-weight: bold;">PrinterB.ti3</span>
- data has been obtained, the profile continue in the next section
- with <span style="font-weight: bold;">Creating a printer profile</span>.<br>
- <br>
- If you have any doubts about the correctness of the chart
- recognition, or the subsequent profile's delta E report is unusual,
- then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
- and examine the <span style="font-weight: bold;">diag.tif</span>
- diagnostic file.<br>
- <h4><a name="PP5"></a>Creating a printer profile<br>
- </h4>
- Creating an RGB based printing profile is very similar to creating a
- display device profile. For a CMYK printer, some additional
- information is needed to set the black generation.<br>
- <br>
- Where the resulting profile will be used conventionally (ie. using <a
- href="collink.html">collink</a> <a href="collink.html#s">-s</a>,
- or <a href="cctiff.html">cctiff</a> or most other "dumb" CMMs) it
- is important to specify that gamut mapping should be computed for
- the output (B2A) perceptual and saturation tables. This is done by
- specifying a device profile as the parameter to the <a
- href="colprof.html">colprof</a> <a href="colprof.html#S">-S</a>
- flag. When you intend to create a "general use" profile, it can be a
- good technique to specify the source gamut as the opposite type of
- profile to that being created, i.e. if a printer profile is being
- created, specify a display profile (e.g. sRGB) as the source gamut.
- If a display profile is being created, then specify a printer
- profile as the source (e.g. Figra, SWOP etc.).&nbsp; When linking to
- the profile you have created this way as the output profile, then
- use perceptual intent if the source is the opposite type, and
- relative colorimetric if it is the same type.<br>
- <br>
- "Opposite type of profile" refers to the native gamut of the device,
- and what its fundamental nature is, additive or subtractive. An
- emissive display will have additive primaries (R, G &amp; B), while
- a reflective print, will have subtractive primaries (C, M, Y &amp;
- possibly others), irrespective of what colorspace the printer is
- driven in (a printer might present an RGB interface, but internally
- this will be converted to CMY, and it will have a CMY type of
- gamut).&nbsp; Because of the complimentary nature of additive and
- subtractive device primary colorants, these types of devices have
- the most different gamuts, and hence need the most gamut mapping to
- convert from one colorspace to the other.<br>
- <br>
- If you are creating a profile for a specific purpose, intending to
- link it to a specific input profile, then you will get the best
- results by specifying that source profile as the source gamut.<br>
- <br>
- If a profile is only going to be used as an input profile, or is
- going to be used with a "smart" CMM (e.g. <a href="collink.html">collink</a>
+
+ scanner or camera must be configured and used exactly the same
+ as it was when it was profiled.</span></big><br>
+ <br>
+ I will assume the resulting scan/photo input file is called <span
+ style="font-weight: bold;">PrinterB.tif</span> (or <span
+ style="font-weight: bold;">PrinterB1.tif</span>, <span
+ style="font-weight: bold;">PrinterB2.tif</span> etc. in the case
+ of multiple charts). As with profiling the scanner or camera, the
+ raster file need only be roughly cropped so as to contain the test
+ chart.<br>
+ <br>
+ The scanner recognition files created when <span
+ style="font-weight: bold;">printtarg</span> was run is assumed to
+ be called <span style="font-weight: bold;">PrinterB.cht</span>.
+ Using the scanner profile created previously (assumed to be called <span
+ style="font-weight: bold;">scanner.icm</span>), the printer test
+ chart scan patches are converted to CIE values using the <span
+ style="font-weight: bold;">scanin</span> tool:<br>
+ <br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB.tif</a>
+ <a href="scanin.html#cp2">PrinterB.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <br>
+ If there were multiple test chart pages, the results would be
+ accumulated page by page using the <a href="scanin.html#ca">-ca</a>
+ option, ie., if there were 3 pages:<br>
+ <br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB1.tif</a>
+ <a href="scanin.html#cp2">PrinterB1.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB2.tif</a>
+ <a href="scanin.html#cp2">PrinterB2.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB3.tif</a>
+ <a href="scanin.html#cp2">PrinterB3.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <br>
+ Now that the <span style="font-weight: bold;">PrinterB.ti3</span>
+ data has been obtained, the profile continue in the next section
+ with <span style="font-weight: bold;">Creating a printer profile</span>.<br>
+ <br>
+ If you have any doubts about the correctness of the chart
+ recognition, or the subsequent profile's delta E report is unusual,
+ then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
+ and examine the <span style="font-weight: bold;">diag.tif</span>
+ diagnostic file.<br>
+ <h4><a name="PP5"></a>Creating a printer profile<br>
+ </h4>
+ Creating an RGB based printing profile is very similar to creating a
+ display device profile. For a CMYK printer, some additional
+ information is needed to set the black generation.<br>
+ <br>
+ Where the resulting profile will be used conventionally (ie. using <a
+ href="collink.html">collink</a> <a href="collink.html#s">-s</a>,
+ or <a href="cctiff.html">cctiff</a> or most other "dumb" CMMs) it
+ is important to specify that gamut mapping should be computed for
+ the output (B2A) perceptual and saturation tables. This is done by
+ specifying a device profile as the parameter to the <a
+ href="colprof.html">colprof</a> <a href="colprof.html#S">-S</a>
+ flag. When you intend to create a "general use" profile, it can be a
+ good technique to specify the source gamut as the opposite type of
+ profile to that being created, i.e. if a printer profile is being
+ created, specify a display profile (e.g. sRGB) as the source gamut.
+ If a display profile is being created, then specify a printer
+ profile as the source (e.g. Figra, SWOP etc.).&nbsp; When linking to
+ the profile you have created this way as the output profile, then
+ use perceptual intent if the source is the opposite type, and
+ relative colorimetric if it is the same type.<br>
+ <br>
+ "Opposite type of profile" refers to the native gamut of the device,
+ and what its fundamental nature is, additive or subtractive. An
+ emissive display will have additive primaries (R, G &amp; B), while
+ a reflective print, will have subtractive primaries (C, M, Y &amp;
+ possibly others), irrespective of what colorspace the printer is
+ driven in (a printer might present an RGB interface, but internally
+ this will be converted to CMY, and it will have a CMY type of
+ gamut).&nbsp; Because of the complimentary nature of additive and
+ subtractive device primary colorants, these types of devices have
+ the most different gamuts, and hence need the most gamut mapping to
+ convert from one colorspace to the other.<br>
+ <br>
+ If you are creating a profile for a specific purpose, intending to
+ link it to a specific input profile, then you will get the best
+ results by specifying that source profile as the source gamut.<br>
+ <br>
+ If a profile is only going to be used as an input profile, or is
+ going to be used with a "smart" CMM (e.g. <a href="collink.html">collink</a>
<a href="collink.html#g">-g</a> or <a href="collink.html#G">-G</a>),
then
@@ -2058,85 +2018,83 @@ then
-
-
-
- it can save considerable processing time and space if the -b flag is
- used, and the -S flag not used.<br>
- <br>
- For an RGB printer intended to print RGB originals, the following
- might be a typical profile usage:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
- <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
- <a href="colprof.html#p1">PrinterA</a><br>
- <br>
- or if you intent to print from Fogra, SWOP or other standard CMYK
- style originals:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S">
- fogra39l.icm</a> <a href="colprof.html#c">-cmt</a> <a
- href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterA</a><br>
- <br>
- If you know what colorspace your originals are in, use that as the
- argument to <span style="font-weight: bold;">-S</span>.<br>
- <br>
- If your viewing environment for the display and print doesn't match
- the ones implied by the <a href="colprof.html#c">-cmt</a> and <a
- href="colprof.html#d">-dpp</a> options, leave them out, and
- evaluate what, if any appearance transformation is appropriate for
- your environment at a later stage.<br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably. Depending on the type of device, and the consistency of
- the readings, average errors of 5 or less, and maximum errors of 15
- or less would normally be expected. If errors are grossly higher
- than this, then this is an indication that something is seriously
- wrong with the device measurement, or profile creation.
- <h4><a name="PP6"></a>Choosing a black generation curve (and other
- CMYK printer options)<br>
- </h4>
- For a CMYK printer, it would be normal to specify the type of black
- generation, either as something simple, or as a specific curve. The
- documentation&nbsp; in <a href="colprof.html#k">colprof</a> for the
- details of the options.<span style="font-weight: bold;"><br>
- <br>
- Note</span> that making a good choice of black generation curve
- can affect things such as: how robust neutrals are given printer
- drift or changes in viewing lighting, how visible screening is, and
- how smooth looking the B2A conversion is.<br>
- <br>
- For instance, maximizing the level of K will mean that the neutral
- colors are composed of greater amounts of Black ink, and black ink
- retains its neutral appearance irrespective of printer behavior or
- the spectrum of the illuminant used to view the print. On the other
- hand, output which is dominantly from one of the color channels will
- tend to emphasize the screening pattern and any unevenness (banding
- etc.) of that channel, and the black channel in particular has the
- highest visibility. So in practice, some balance between the levels
- of the four channels is probably best, with more K if the screening
- is fine and a robust neutral balance is important, or less K if the
- screening is more visible and neutral balance is less critical. The
- levels of K at the edges of the gamut of the device will be fixed by
- the nature of the ink combinations that maximize the gamut (ie.
- typically zero ink for light chromatic colors, some combination for
- dark colors, and a high level of black for very dark near neutrals),
- and it is also usually important to set a curve that smoothly
- transitions to the K values at the gamut edges. Dramatic changes in
- K imply equally dramatic changes in CMY, and these abrupt
- transitions will reveal the limited precision and detail that can be
- captured in a lookup table based profile, often resulting in a
- "bumpy" looking output.<br>
- <br>
- If you want to experiment with the various black generation
- parameters, then it might be a good idea to create a preliminary
- profile (using <a href="colprof.html#q">-ql</a> <a
- href="colprof.html#b">-b</a> <a href="colprof.html#ni">-no</a>, <a
+
+ it can save considerable processing time and space if the -b flag is
+ used, and the -S flag not used.<br>
+ <br>
+ For an RGB printer intended to print RGB originals, the following
+ might be a typical profile usage:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
+ <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#p1">PrinterA</a><br>
+ <br>
+ or if you intent to print from Fogra, SWOP or other standard CMYK
+ style originals:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S">
+ fogra39l.icm</a> <a href="colprof.html#c">-cmt</a> <a
+ href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterA</a><br>
+ <br>
+ If you know what colorspace your originals are in, use that as the
+ argument to <span style="font-weight: bold;">-S</span>.<br>
+ <br>
+ If your viewing environment for the display and print doesn't match
+ the ones implied by the <a href="colprof.html#c">-cmt</a> and <a
+ href="colprof.html#d">-dpp</a> options, leave them out, and
+ evaluate what, if any appearance transformation is appropriate for
+ your environment at a later stage.<br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably. Depending on the type of device, and the consistency of
+ the readings, average errors of 5 or less, and maximum errors of 15
+ or less would normally be expected. If errors are grossly higher
+ than this, then this is an indication that something is seriously
+ wrong with the device measurement, or profile creation.
+ <h4><a name="PP6"></a>Choosing a black generation curve (and other
+ CMYK printer options)<br>
+ </h4>
+ For a CMYK printer, it would be normal to specify the type of black
+ generation, either as something simple, or as a specific curve. The
+ documentation&nbsp; in <a href="colprof.html#k">colprof</a> for the
+ details of the options.<span style="font-weight: bold;"><br>
+ <br>
+ Note</span> that making a good choice of black generation curve
+ can affect things such as: how robust neutrals are given printer
+ drift or changes in viewing lighting, how visible screening is, and
+ how smooth looking the B2A conversion is.<br>
+ <br>
+ For instance, maximizing the level of K will mean that the neutral
+ colors are composed of greater amounts of Black ink, and black ink
+ retains its neutral appearance irrespective of printer behavior or
+ the spectrum of the illuminant used to view the print. On the other
+ hand, output which is dominantly from one of the color channels will
+ tend to emphasize the screening pattern and any unevenness (banding
+ etc.) of that channel, and the black channel in particular has the
+ highest visibility. So in practice, some balance between the levels
+ of the four channels is probably best, with more K if the screening
+ is fine and a robust neutral balance is important, or less K if the
+ screening is more visible and neutral balance is less critical. The
+ levels of K at the edges of the gamut of the device will be fixed by
+ the nature of the ink combinations that maximize the gamut (ie.
+ typically zero ink for light chromatic colors, some combination for
+ dark colors, and a high level of black for very dark near neutrals),
+ and it is also usually important to set a curve that smoothly
+ transitions to the K values at the gamut edges. Dramatic changes in
+ K imply equally dramatic changes in CMY, and these abrupt
+ transitions will reveal the limited precision and detail that can be
+ captured in a lookup table based profile, often resulting in a
+ "bumpy" looking output.<br>
+ <br>
+ If you want to experiment with the various black generation
+ parameters, then it might be a good idea to create a preliminary
+ profile (using <a href="colprof.html#q">-ql</a> <a
+ href="colprof.html#b">-b</a> <a href="colprof.html#ni">-no</a>, <a
href="colprof.html#no">-ni</a> and no <a href="colprof.html#S">-S</a>),
@@ -2193,409 +2151,407 @@ then
-
-
-
- and then used <a href="xicclu.html#g">xicclu</a> to explore the
- effect of the parameters.<br>
- <br>
- For instance, say we have our CMYK .ti3 file <span
- style="font-weight: bold;">PrinterB.ti3</span>. First we make a
- preliminary profile called <span style="font-weight: bold;">PrinterBt</span>:<br>
- <br>
- copy PrinterB.ti3 PrinterBt.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Use
- "cp" on Linux or OSX of course.)<br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#q">-qm</a> <a href="colprof.html#b">-b</a> <a
- href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
- <a href="colprof.html#p1">PrinterBt</a><br>
- <br>
- Then see what the minimum black level down the neutral axis can be.
- Note that we need to also set any ink limits we've decided on as
- well (coloprof defaulting to 10% less than the value recorded in the
- .ti3 file). In this example the test chart has a 300% total ink
- limit, and we've decided to use 290%:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kz</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- Which might be a graph something like this:<br>
- <br>
- <img alt="Graph of CMYK neutral axis with minimum K"
- src="Kgraph1.jpg" style="width: 250px; height: 250px;"><br>
- <br>
- Note&nbsp; how the minimum black is zero up to 93% of the
- white-&gt;black L* curve, and then jumps up to 87%. This is because
- we've reached the total ink limit, and K then has to be substituted
- for CMY, to keep the total under the total ink limit.<br>
- <br>
- Then let's see what the maximum black level down the neutral axis
- can be:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kx</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- Which might be a graph something like this:<br>
- <br>
- <img alt="Graph of CMYK neutral axis with maximum K"
- src="Kgraph2.jpg" style="width: 250px; height: 250px;"><br>
- <br>
- Note how the CMY values are fairly low up to 93% of the
- white-&gt;black L* curve (the low levels of CMY are helping set the
- neutral color), and then they jump up. This is because we've reach
- the point where black on it's own, isn't as dark as the color that
- can be achieved using CMY and K. Because the K has a dominant effect
- on the hue of the black, the levels of CMY are often fairly volatile
- in this region.<br>
- <br>
- Any K curve we specify must lie between the black curves of the
- above two graphs.<br>
- <br>
- Let's say we'd like to chose a moderate black curve, one that aims
- for about equal levels of CMY and K. We should also aim for it to be
- fairly smooth, since this will minimize visual artefacts caused by
- the limited fidelity that profile LUT tables are able to represent
- inside the profile.<br>
- <br>
- <img style="width: 340px; height: 258px;" alt="-k parameters"
- src="Kparams.jpg"><br>
- <br>
- <br>
- For minimum discontinuities we should aim for the curve to finish at
- the point it has to reach to satisfy the total ink limit at 87%
- curve and 93% black. For a first try we can simply set a straight
- line to that point: <br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp 0 0 .93 .87 1.0</a> <a
- href="xicclu.html#l">-l290</a> <a href="xicclu.html#f">-fif</a> <a
- href="xicclu.html#i">-ir</a> <a href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img alt="Graph of CMYK neutral axis with kp 0 0 1.0 1.0 1.0 -l290"
- src="Kgraph3.jpg" style="width: 250px; height: 250px;"><br>
- <br>
- The black "curve" hits the 93%/87% mark well, but is a bit too far
- above CMY, so we'll try making the black curve concave:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
- 0.65</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img alt="Graph of CMYK neutral axis with -kp 0 .05 1 .9 1 -l290"
- src="Kgraph4.jpg" style="width: 250px; height: 249px;"><br>
- <br>
- This looks just about perfect, so the the curve parameters can now
- be used to generate our real profile:<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#k">-kp </a><a href="xicclu.html#k">0 0 .93
- .87 0.65</a> <a href="colprof.html#S">-S</a><a
- href="colprof.html#S"> sRGB.icm</a> <a href="colprof.html#c">-cmt</a>
- <a href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterB</a><br>
- <br>
- and the resulting B2A table black curve can be checked using xicclu:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#f">-fb</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterB.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph5.jpg"><br>
- <br>
- <br>
- <hr style="margin-left: 0px; margin-right: auto; width: 20%; height:
- 2px;"><br>
- <span style="font-weight: bold;">Examples of other inkings:<br>
- <br>
- </span>A smoothed zero black inking:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 .7 .93 .87
- 1.0</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph6.jpg"><br>
- <br>
- A low black inking:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
- 0.15</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph7.jpg"><br>
- <br>
- <br>
- A high black inking:<br>
- <br>
- <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
- href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
- 1.2</a> <a href="xicclu.html#l">-l290</a> <a
- href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
- href="xicclu.html#p1">PrinterBt.icm</a><br>
- <br>
- <img style="width: 250px; height: 250px;" alt="sadsadas"
- src="Kgraph8.jpg"><br>
- <br>
- <span style="font-weight: bold;"></span>
- <h4>Overriding the ink limit<br>
- </h4>
- Normally the total ink limit will be read from the <span
- style="font-weight: bold;">PrinterB.ti3</span> file, and will be
- set at a level 10% lower than the number used in creating the test
- chart values using <a href="targen.html#l">targen -l</a>. If you
- want to override this with a lower limit, then use the <a
- href="colprof.html#l">-l flag</a>.<br>
- <br>
- <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
- <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
- <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
- <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
- <a href="colprof.html#k">-kr</a> <a href="xicclu.html#l">-l290</a>
- <a href="colprof.html#p1">PrinterB</a><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the profile is behaving reasonably.<br>
- <br>
- One way of checking that your ink limit is not too high, is to use "<span
- style="font-weight: bold;">xicc -fif -ia</span>" to check, by
- setting different ink limits using the <span style="font-weight:
- bold;">-l</span> option, feeding Lab = 0 0 0 into it, and checking
- the resulting&nbsp; black point. Starting with the ink limit used
- with <span style="font-weight: bold;">targen</span> for the test
- chart, reduce it until the black point starts to be affected. If it
- is immediately affected by any reduction in the ink limit, then the
- black point may be improved by increasing the ink limit used to
- generate the test chart and then re-print and re-measuring it,
- assuming other aspects such as wetness, smudging, spreading or
- drying time are not an issue.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <h3><a name="PC1"></a>Calibrating Printers<br>
- </h3>
- <span style="font-weight: bold;">Profiling</span> creates a
- description of how a device behaves, while <span
- style="font-weight: bold;">calibration</span> on the other hand is
- intended to <span style="text-decoration: underline;">change</span>
- how a device behaves. Argyll has the ability to create per-channel
- device space calibration curves for print devices, that can then be
- used to improve the behavior of of the device, making a subsequent
- profile fit the device more easily and also allow day to day
- correction of device drift without resorting to a full re-profile.<br>
- <br>
- <span style="font-weight: bold;">NOTE:</span> Because calibration
- adds yet another layer to the way color is processed, it is
- recommended that it not be attempted until the normal profiling
- workflow is established, understood and verified.<br>
- <h4><a name="PC2"></a>Calibrated print workflows</h4>
- There are two main workflows that printer calibration curves can be
- applied to:<br>
- <br>
- <span style="text-decoration: underline;">Workflow <span
- style="font-weight: bold;">with</span> native calibration
- capability</span>:<br>
- <br>
- Firstly the printer itself may have the capability of using per
- channel calibration curves. In this situation, the calibration
- process will be largely independent of profiling. Firstly the
- printer is configured to have both its color management and
- calibration disabled (the latter perhaps achieved by loading linear
- calibration curves), and a print calibration test chart that
- consists of per channel color wedges is printed. The calibration
- chart is read and the resulting .ti3 file converted into calibration
- curves by processing it using <span style="font-weight: bold;">printcal</span>.
- The calibration is then installed into the printer. Subsequent
- profiling will be performed on the <span style="text-decoration:
- underline;">calibrated</span> printer (ie. the profile test chart
- will have the calibration curves applied to it by the printer, and
- the resulting ICC profile will represent the behavior of the
- calibrated printer.)<br>
- <br>
- <span style="text-decoration: underline;">Workflow <span
- style="font-weight: bold;">without</span> native calibration
- capability</span>:<br>
- <br>
- The second workflow is one in which the printer has no calibration
- capability itself. In this situation, the calibration process will
- have to be applied using the ICC color management tools, so careful
- coordination with profiling is needed. Firstly the printer is
- configured to have its color management disabled, and a print
- calibration test chart that consists of per channel color wedges is
- printed. The calibration chart is converted into calibration curves
- by reading it and then processing the resultant .ti3 using <span
- style="font-weight: bold;">printcal</span>,. During the subsequent
- <span style="text-decoration: underline;">profiling</span>, the
- calibration curves will need to be applied to the profile test chart
- in the process of using <span style="font-weight: bold;">printtarg</span>.
- Once the the profile has been created, then in subsequent printing
- the calibration curves will need to be applied to an image being
- printed either explicitly when using <span style="font-weight:
- bold;">cctiff</span> to apply color profiles <span
- style="text-decoration: underline;">and</span> calibration, <span
- style="font-weight: bold;">OR</span> by creating a version of the
- profile that has had the calibration curves incorporated into it
- using the <span style="font-weight: bold;">applycal</span> tool.
- The latter is useful when some CMM (color management module) other
- than <span style="font-weight: bold;">cctiff </span>is being used.<br>
- <br>
- Once calibration aim targets for a particular device and mode
- (screening, paper etc.) have been established, then the printer can
- be re-calibrated at any time to bring its per channel behavior back
- into line if it drifts, and the new calibration curves can be
- installed into the printer, or re-incorporated into the profile.
- &nbsp;
- <h4><a name="PC3"></a>Creating a print calibration test chart</h4>
- The first step is to create a print calibration test chart. Since
- calibration only creates per-channel curves, only single channel
- step wedges are required for the chart. The main choice is the
- number of steps in each wedge. For simple fast calibrations perhaps
- as few as 20 steps per channel may be enough, but for a better
- quality of calibration something like 50 or more steps would be a
- better choice.<br>
- <br>
- Let's consider two devices in our examples, "PrinterA" which is an
- "RGB" printer device, and "PrinterB" which is CMYK. In fact there is
- no such thing as a real RGB printer, since printers use white media
- and the colorant must subtract from the light reflected on it to
- create color, but the printer itself turns the incoming RGB into the
- native print colorspace, so for this reason we are careful to tell
- targen to use the "Print RGB" colorspace, so that it knows to create
- step wedges from media white to full colorant values.<br>
- <br>
- For instance, to create a 50 steps per channel calibration test
- chart for our RGB and CMYK devices, the following would be
- sufficient:<br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#s">-s50</a>
- <a href="targen.html#e">-e3</a> <a href="targen.html#f">-f0</a> <a
- href="targen.html#p1">PrinterA_c</a><br>
- <br>
- <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
- &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#s">-s50</a>
- <a href="targen.html#e">-e4</a> <a href="targen.html#f">-f0</a> <a
- href="targen.html#p1">PrinterB_c</a><br>
- <a href="targen.html#p1"></a><br>
- For an outline of how to then print and read the resulting test
- chart, see&nbsp; <a href="Scenarios.html#PP2b">Printing a print
- profile test chart</a>, and <a href="Scenarios.html#PP3">Reading
- a print test chart using an instrument</a>. Note that the printer
- must be in an un-profiled and un-calibrated mode when doing this
- print. Having done this, there will be a PrinterA.ti3 or
- PrinterB.ti3 file containing the step wedge calibration chart
- readings.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that if you are
- calibrating a raw printer driver, and there is considerable dot
- gain, then you may want to use the <a href="targen.html#p">-p</a>
- parameter to adjust the test chart point distribution to spread them
- more evenly in perceptual space, giving more accurate control over
- the calibration. Typically this will be a value greater than one for
- a device that has dot gain, e.g. values of 1.5, 2.0 or 2.5 might be
- good places to start. You can do a preliminary calibration and use
- the verbose output of printcal to recommend a suitable value for <span
- style="font-weight: bold;">-p</span>.<br>
- <h4><a name="PC4"></a>Creating a printer calibration<br>
- </h4>
- The <a href="printcal.html">printcal</a> tool turns a calibration
- chart <a href="File_Formats.html#.ti3">.ti3</a> file into a <a
- href="File_Formats.html#.cal">.cal</a> file. It has three main
- operating modes:- Initial calibration, Re-Calibration, and
- Verification. (A fourth mode, "Imitation" is very like Initial
- Calibration, but is used for establishing a calibration target that
- a similar printer can attempt to imitate.)<br>
- <br>
- The distinction between Initial Calibration and Re-Calibration is
- that in the initial calibration we establish the "aim points" or
- response we want out of the printer after calibration. There are
- three basic parameters to set this for each channel: Maximum level,
- minimum level, and curve shape.<br>
- <br>
- By default the maximum level will be set using a heuristic which
- attempts to pick the point when there is diminishing returns for
- applying more colorant. This can be overridden using the <span
- style="font-weight: bold;">-x# percent</span> option, where <span
- style="font-weight: bold;">#</span> represents the choice of
- channel this will be applied to. The parameter is the percentage of
- device maximum. <br>
- <br>
- The minimum level defaults to 0, but can be overridden using the <span
- style="font-weight: bold;">-n# deltaE</span> option. A minimum of
- 0 means that zero colorant will correspond to the natural media
- color, but it may be desirable to set a non-pure media color using
- calibration for the purposes of emulating some other media. The
- parameter is in Delta E units.<br>
- <br>
- The curve shape defaults to being perceptually uniform, which means
- that even steps of calibrated device value result in perceptually
- even color steps. In some situations it may be desirable to alter
- this curve (for instance when non color managed output needs to be
- sent to the calibrated printer), and a simple curve shape target can
- be set using the <span style="font-weight: bold;">-t# percent</span>
- parameter. This affects the output value at 50% input value, and
- represents the percentage of perceptual output. By default it is 50%
- perceptual output for 50% device input.<br>
- <br>
- Once a device has been calibrated, it can be re-calibrated to the
- same aim target.<br>
- <br>
- Verification uses a calibration test chart printed through the
- calibration, and compares the achieved response to the aim target.<br>
- <br>
- The simplest possible way of creating the <span style="font-weight:
- bold;">PrinterA.cal</span> file is:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterA_c</a><br>
- <br>
- For more detailed information, you can add the <span
- style="font-weight: bold;">-v</span> and <span
- style="font-weight: bold;">-p</span> flags:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
- href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterB_c</a><br>
- <br>
- (You will need to select the plot window and hit a key to advance
- past each plot).<br>
- <br>
- For re-calibration, the name of the previous calibration file will
- need to be supplied, and a new calibration<br>
- file will be created:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
- href="printcal.html#r">-r</a> <a href="colprof.html#p1">PrinterB_c_old</a>
- <a href="colprof.html#p2">PrinterB_c_new</a><br>
- <br>
- Various aim points are normally set automatically by <span
- style="font-weight: bold;">printcal</span>, but these can be
- overridden using the <a href="colprof.html#x">-x</a>, <a
- href="colprof.html#n">-n</a> and <a href="colprof.html#t">-t</a>
- options. e.g. say we wanted to set the maximum ink for Cyan to 80%
- and Black to 95%, we might use:<br>
- <br>
- &nbsp; <a href="printcal.html">printcal</a> <a
- href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
- href="printcal.html#i">-i</a> <a href="colprof.html#x">-xc 80</a>
- <a href="colprof.html#x">-xk 95</a> <a href="colprof.html#p2">PrinterB_c</a><br>
- <br>
- <a href="colprof.html#p2"></a>
- <h4><a name="PC5"></a>Using a printer calibration</h4>
- The resulting calibration curves can be used with the following
- other Argyll tools:<br>
- <br>
+
+ and then used <a href="xicclu.html#g">xicclu</a> to explore the
+ effect of the parameters.<br>
+ <br>
+ For instance, say we have our CMYK .ti3 file <span
+ style="font-weight: bold;">PrinterB.ti3</span>. First we make a
+ preliminary profile called <span style="font-weight: bold;">PrinterBt</span>:<br>
+ <br>
+ copy PrinterB.ti3 PrinterBt.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Use
+ "cp" on Linux or OSX of course.)<br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#q">-qm</a> <a href="colprof.html#b">-b</a> <a
+ href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#p1">PrinterBt</a><br>
+ <br>
+ Then see what the minimum black level down the neutral axis can be.
+ Note that we need to also set any ink limits we've decided on as
+ well (coloprof defaulting to 10% less than the value recorded in the
+ .ti3 file). In this example the test chart has a 300% total ink
+ limit, and we've decided to use 290%:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kz</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ Which might be a graph something like this:<br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with minimum K"
+ src="Kgraph1.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ Note&nbsp; how the minimum black is zero up to 93% of the
+ white-&gt;black L* curve, and then jumps up to 87%. This is because
+ we've reached the total ink limit, and K then has to be substituted
+ for CMY, to keep the total under the total ink limit.<br>
+ <br>
+ Then let's see what the maximum black level down the neutral axis
+ can be:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kx</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ Which might be a graph something like this:<br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with maximum K"
+ src="Kgraph2.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ Note how the CMY values are fairly low up to 93% of the
+ white-&gt;black L* curve (the low levels of CMY are helping set the
+ neutral color), and then they jump up. This is because we've reach
+ the point where black on it's own, isn't as dark as the color that
+ can be achieved using CMY and K. Because the K has a dominant effect
+ on the hue of the black, the levels of CMY are often fairly volatile
+ in this region.<br>
+ <br>
+ Any K curve we specify must lie between the black curves of the
+ above two graphs.<br>
+ <br>
+ Let's say we'd like to chose a moderate black curve, one that aims
+ for about equal levels of CMY and K. We should also aim for it to be
+ fairly smooth, since this will minimize visual artefacts caused by
+ the limited fidelity that profile LUT tables are able to represent
+ inside the profile.<br>
+ <br>
+ <img style="width: 340px; height: 258px;" alt="-k parameters"
+ src="Kparams.jpg"><br>
+ <br>
+ <br>
+ For minimum discontinuities we should aim for the curve to finish at
+ the point it has to reach to satisfy the total ink limit at 87%
+ curve and 93% black. For a first try we can simply set a straight
+ line to that point: <br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp 0 0 .93 .87 1.0</a> <a
+ href="xicclu.html#l">-l290</a> <a href="xicclu.html#f">-fif</a> <a
+ href="xicclu.html#i">-ir</a> <a href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with kp 0 0 1.0 1.0 1.0 -l290"
+ src="Kgraph3.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ The black "curve" hits the 93%/87% mark well, but is a bit too far
+ above CMY, so we'll try making the black curve concave:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 0.65</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with -kp 0 .05 1 .9 1 -l290"
+ src="Kgraph4.jpg" style="width: 250px; height: 249px;"><br>
+ <br>
+ This looks just about perfect, so the the curve parameters can now
+ be used to generate our real profile:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#k">-kp </a><a href="xicclu.html#k">0 0 .93
+ .87 0.65</a> <a href="colprof.html#S">-S</a><a
+ href="colprof.html#S"> sRGB.icm</a> <a href="colprof.html#c">-cmt</a>
+ <a href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterB</a><br>
+ <br>
+ and the resulting B2A table black curve can be checked using xicclu:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#f">-fb</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterB.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph5.jpg"><br>
+ <br>
+ <br>
+ <hr style="margin-left: 0px; margin-right: auto; width: 20%; height:
+ 2px;"><br>
+ <span style="font-weight: bold;">Examples of other inkings:<br>
+ <br>
+ </span>A smoothed zero black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 .7 .93 .87
+ 1.0</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph6.jpg"><br>
+ <br>
+ A low black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 0.15</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph7.jpg"><br>
+ <br>
+ <br>
+ A high black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 1.2</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph8.jpg"><br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <h4>Overriding the ink limit<br>
+ </h4>
+ Normally the total ink limit will be read from the <span
+ style="font-weight: bold;">PrinterB.ti3</span> file, and will be
+ set at a level 10% lower than the number used in creating the test
+ chart values using <a href="targen.html#l">targen -l</a>. If you
+ want to override this with a lower limit, then use the <a
+ href="colprof.html#l">-l flag</a>.<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
+ <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#k">-kr</a> <a href="xicclu.html#l">-l290</a>
+ <a href="colprof.html#p1">PrinterB</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the profile is behaving reasonably.<br>
+ <br>
+ One way of checking that your ink limit is not too high, is to use "<span
+ style="font-weight: bold;">xicc -fif -ia</span>" to check, by
+ setting different ink limits using the <span style="font-weight:
+ bold;">-l</span> option, feeding Lab = 0 0 0 into it, and checking
+ the resulting&nbsp; black point. Starting with the ink limit used
+ with <span style="font-weight: bold;">targen</span> for the test
+ chart, reduce it until the black point starts to be affected. If it
+ is immediately affected by any reduction in the ink limit, then the
+ black point may be improved by increasing the ink limit used to
+ generate the test chart and then re-print and re-measuring it,
+ assuming other aspects such as wetness, smudging, spreading or
+ drying time are not an issue.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <h3><a name="PC1"></a>Calibrating Printers<br>
+ </h3>
+ <span style="font-weight: bold;">Profiling</span> creates a
+ description of how a device behaves, while <span
+ style="font-weight: bold;">calibration</span> on the other hand is
+ intended to <span style="text-decoration: underline;">change</span>
+ how a device behaves. Argyll has the ability to create per-channel
+ device space calibration curves for print devices, that can then be
+ used to improve the behavior of of the device, making a subsequent
+ profile fit the device more easily and also allow day to day
+ correction of device drift without resorting to a full re-profile.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE:</span> Because calibration
+ adds yet another layer to the way color is processed, it is
+ recommended that it not be attempted until the normal profiling
+ workflow is established, understood and verified.<br>
+ <h4><a name="PC2"></a>Calibrated print workflows</h4>
+ There are two main workflows that printer calibration curves can be
+ applied to:<br>
+ <br>
+ <span style="text-decoration: underline;">Workflow <span
+ style="font-weight: bold;">with</span> native calibration
+ capability</span>:<br>
+ <br>
+ Firstly the printer itself may have the capability of using per
+ channel calibration curves. In this situation, the calibration
+ process will be largely independent of profiling. Firstly the
+ printer is configured to have both its color management and
+ calibration disabled (the latter perhaps achieved by loading linear
+ calibration curves), and a print calibration test chart that
+ consists of per channel color wedges is printed. The calibration
+ chart is read and the resulting .ti3 file converted into calibration
+ curves by processing it using <span style="font-weight: bold;">printcal</span>.
+ The calibration is then installed into the printer. Subsequent
+ profiling will be performed on the <span style="text-decoration:
+ underline;">calibrated</span> printer (ie. the profile test chart
+ will have the calibration curves applied to it by the printer, and
+ the resulting ICC profile will represent the behavior of the
+ calibrated printer.)<br>
+ <br>
+ <span style="text-decoration: underline;">Workflow <span
+ style="font-weight: bold;">without</span> native calibration
+ capability</span>:<br>
+ <br>
+ The second workflow is one in which the printer has no calibration
+ capability itself. In this situation, the calibration process will
+ have to be applied using the ICC color management tools, so careful
+ coordination with profiling is needed. Firstly the printer is
+ configured to have its color management disabled, and a print
+ calibration test chart that consists of per channel color wedges is
+ printed. The calibration chart is converted into calibration curves
+ by reading it and then processing the resultant .ti3 using <span
+ style="font-weight: bold;">printcal</span>,. During the subsequent
+ <span style="text-decoration: underline;">profiling</span>, the
+ calibration curves will need to be applied to the profile test chart
+ in the process of using <span style="font-weight: bold;">printtarg</span>.
+ Once the the profile has been created, then in subsequent printing
+ the calibration curves will need to be applied to an image being
+ printed either explicitly when using <span style="font-weight:
+ bold;">cctiff</span> to apply color profiles <span
+ style="text-decoration: underline;">and</span> calibration, <span
+ style="font-weight: bold;">OR</span> by creating a version of the
+ profile that has had the calibration curves incorporated into it
+ using the <span style="font-weight: bold;">applycal</span> tool.
+ The latter is useful when some CMM (color management module) other
+ than <span style="font-weight: bold;">cctiff </span>is being used.<br>
+ <br>
+ Once calibration aim targets for a particular device and mode
+ (screening, paper etc.) have been established, then the printer can
+ be re-calibrated at any time to bring its per channel behavior back
+ into line if it drifts, and the new calibration curves can be
+ installed into the printer, or re-incorporated into the profile.
+ &nbsp;
+ <h4><a name="PC3"></a>Creating a print calibration test chart</h4>
+ The first step is to create a print calibration test chart. Since
+ calibration only creates per-channel curves, only single channel
+ step wedges are required for the chart. The main choice is the
+ number of steps in each wedge. For simple fast calibrations perhaps
+ as few as 20 steps per channel may be enough, but for a better
+ quality of calibration something like 50 or more steps would be a
+ better choice.<br>
+ <br>
+ Let's consider two devices in our examples, "PrinterA" which is an
+ "RGB" printer device, and "PrinterB" which is CMYK. In fact there is
+ no such thing as a real RGB printer, since printers use white media
+ and the colorant must subtract from the light reflected on it to
+ create color, but the printer itself turns the incoming RGB into the
+ native print colorspace, so for this reason we are careful to tell
+ targen to use the "Print RGB" colorspace, so that it knows to create
+ step wedges from media white to full colorant values.<br>
+ <br>
+ For instance, to create a 50 steps per channel calibration test
+ chart for our RGB and CMYK devices, the following would be
+ sufficient:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#s">-s50</a>
+ <a href="targen.html#e">-e3</a> <a href="targen.html#f">-f0</a> <a
+ href="targen.html#p1">PrinterA_c</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#s">-s50</a>
+ <a href="targen.html#e">-e4</a> <a href="targen.html#f">-f0</a> <a
+ href="targen.html#p1">PrinterB_c</a><br>
+ <a href="targen.html#p1"></a><br>
+ For an outline of how to then print and read the resulting test
+ chart, see&nbsp; <a href="Scenarios.html#PP2b">Printing a print
+ profile test chart</a>, and <a href="Scenarios.html#PP3">Reading
+ a print test chart using an instrument</a>. Note that the printer
+ must be in an un-profiled and un-calibrated mode when doing this
+ print. Having done this, there will be a PrinterA.ti3 or
+ PrinterB.ti3 file containing the step wedge calibration chart
+ readings.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you are
+ calibrating a raw printer driver, and there is considerable dot
+ gain, then you may want to use the <a href="targen.html#p">-p</a>
+ parameter to adjust the test chart point distribution to spread them
+ more evenly in perceptual space, giving more accurate control over
+ the calibration. Typically this will be a value greater than one for
+ a device that has dot gain, e.g. values of 1.5, 2.0 or 2.5 might be
+ good places to start. You can do a preliminary calibration and use
+ the verbose output of printcal to recommend a suitable value for <span
+ style="font-weight: bold;">-p</span>.<br>
+ <h4><a name="PC4"></a>Creating a printer calibration<br>
+ </h4>
+ The <a href="printcal.html">printcal</a> tool turns a calibration
+ chart <a href="File_Formats.html#.ti3">.ti3</a> file into a <a
+ href="File_Formats.html#.cal">.cal</a> file. It has three main
+ operating modes:- Initial calibration, Re-Calibration, and
+ Verification. (A fourth mode, "Imitation" is very like Initial
+ Calibration, but is used for establishing a calibration target that
+ a similar printer can attempt to imitate.)<br>
+ <br>
+ The distinction between Initial Calibration and Re-Calibration is
+ that in the initial calibration we establish the "aim points" or
+ response we want out of the printer after calibration. There are
+ three basic parameters to set this for each channel: Maximum level,
+ minimum level, and curve shape.<br>
+ <br>
+ By default the maximum level will be set using a heuristic which
+ attempts to pick the point when there is diminishing returns for
+ applying more colorant. This can be overridden using the <span
+ style="font-weight: bold;">-x# percent</span> option, where <span
+ style="font-weight: bold;">#</span> represents the choice of
+ channel this will be applied to. The parameter is the percentage of
+ device maximum. <br>
+ <br>
+ The minimum level defaults to 0, but can be overridden using the <span
+ style="font-weight: bold;">-n# deltaE</span> option. A minimum of
+ 0 means that zero colorant will correspond to the natural media
+ color, but it may be desirable to set a non-pure media color using
+ calibration for the purposes of emulating some other media. The
+ parameter is in Delta E units.<br>
+ <br>
+ The curve shape defaults to being perceptually uniform, which means
+ that even steps of calibrated device value result in perceptually
+ even color steps. In some situations it may be desirable to alter
+ this curve (for instance when non color managed output needs to be
+ sent to the calibrated printer), and a simple curve shape target can
+ be set using the <span style="font-weight: bold;">-t# percent</span>
+ parameter. This affects the output value at 50% input value, and
+ represents the percentage of perceptual output. By default it is 50%
+ perceptual output for 50% device input.<br>
+ <br>
+ Once a device has been calibrated, it can be re-calibrated to the
+ same aim target.<br>
+ <br>
+ Verification uses a calibration test chart printed through the
+ calibration, and compares the achieved response to the aim target.<br>
+ <br>
+ The simplest possible way of creating the <span style="font-weight:
+ bold;">PrinterA.cal</span> file is:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterA_c</a><br>
+ <br>
+ For more detailed information, you can add the <span
+ style="font-weight: bold;">-v</span> and <span
+ style="font-weight: bold;">-p</span> flags:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterB_c</a><br>
+ <br>
+ (You will need to select the plot window and hit a key to advance
+ past each plot).<br>
+ <br>
+ For re-calibration, the name of the previous calibration file will
+ need to be supplied, and a new calibration<br>
+ file will be created:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#r">-r</a> <a href="colprof.html#p1">PrinterB_c_old</a>
+ <a href="colprof.html#p2">PrinterB_c_new</a><br>
+ <br>
+ Various aim points are normally set automatically by <span
+ style="font-weight: bold;">printcal</span>, but these can be
+ overridden using the <a href="colprof.html#x">-x</a>, <a
+ href="colprof.html#n">-n</a> and <a href="colprof.html#t">-t</a>
+ options. e.g. say we wanted to set the maximum ink for Cyan to 80%
+ and Black to 95%, we might use:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#x">-xc 80</a>
+ <a href="colprof.html#x">-xk 95</a> <a href="colprof.html#p2">PrinterB_c</a><br>
+ <br>
+ <a href="colprof.html#p2"></a>
+ <h4><a name="PC5"></a>Using a printer calibration</h4>
+ The resulting calibration curves can be used with the following
+ other Argyll tools:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="printtarg.html#K">printtarg</a>&nbsp;&nbsp;&nbsp;&nbsp;
To
apply
@@ -2661,10 +2617,8 @@ chart,
-
-
-
- and/or to have it included in .ti3 file.<br>
+
+ and/or to have it included in .ti3 file.<br>
&nbsp;&nbsp;&nbsp; <a href="cctiff.html#p2">cctiff</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
To
apply
@@ -2730,10 +2684,8 @@ an
-
-
-
- image file.<br>
+
+ image file.<br>
&nbsp;&nbsp;&nbsp; <a href="applycal.html#p1">applycal</a>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2791,10 +2743,8 @@ an
-
-
-
- To incorporate calibration into an ICC profile.<br>
+
+ To incorporate calibration into an ICC profile.<br>
&nbsp;&nbsp;&nbsp; <a href="chartread.html#I">chartread</a>&nbsp;&nbsp;
To
override
@@ -2860,405 +2810,396 @@ a
-
-
-
- profile chart.<br>
- <br>
- <br>
- In a workflow <span style="font-weight: bold;">with</span> native
- calibration capability, the calibration curves would be used with
- printarg during subsequent <span style="font-weight: bold;">profiling</span>
- so that any ink limit calculations will reflect final device values,
- while not otherwise using the calibration within the ICC workflow:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
- href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
- <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#I">-I
- PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
- <br>
- This will cause the .ti2 and resulting .ti3 and ICC profiles to
- contain the calibration curves, allowing all the tools to be able to
- compute final device value ink limits. The calibration curves must
- also of course be installed into the printer. The means to do this
- is currently outside the scope of Argyll (ie. either the print
- system needs to be able to understand Argyll CAL format files, or
- some tool will be needed to convert Argyll CAL files into the
- printer calibration format).<br>
- <br>
- <br>
- In a workflow <span style="font-weight: bold;">without</span>
- native calibration capability, the calibration curves would be used
- with printarg to <span style="text-decoration: underline;">apply</span>
- the calibration to the test patch samples during subsequent <span
- style="font-weight: bold;">profiling</span>, as well as embedding
- it in the resulting .ti3 to allow all the tools to be able to
- compute final device value ink limits:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
- href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
- <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#K">-K
- PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
- <a href="cctiff.html#p4"></a><br>
- To apply calibration to an ICC profile, so that a calibration
- unaware CMM can be used:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="applycal.html">applycal</a> <a
- href="applycal.html#p1">PrinterA.cal</a> <a
- href="applycal.html#p2">PrinterA.icm</a> <a
- href="applycal.html#p3">PrinterA_cal.icm</a><br>
- <br>
- To apply color management and calibration to a raster image:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a>
- <a href="cctiff.html#p1">Source.icm</a> <a
- href="cctiff.html#p1">PrinterA.icm</a> <a
- href="cctiff.html#p2">PrinterA_c.cal</a>
- <a href="cctiff.html#p3">infile.tif</a> <a
- href="cctiff.html#p4">outfile.tif</a><br>
- <br>
- or<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a>
- <a href="cctiff.html#p1">Source.icm</a> <a
- href="cctiff.html#p1">PrinterA_c.icm</a>
- <a href="cctiff.html#p3">infile.tif</a> <a
- href="cctiff.html#p4">outfile.tif</a><br>
- <br>
- [ Note that cctiff will also process JPEG raster images. ]<br>
- <br>
- Another useful tool is <a href="synthcal.html">synthcal</a>, that
- allows creating linear or synthetic calibration files for disabling
- calibration or testing.<br>
- Similarly, <a href="fakeread.html">fakeread</a> also supports
- applying calibration curves and embedding them in the resulting .ti3
- file<br>
- <br>
- If you want to create a pre-conditioning profile for use with <a
- href="targen.html#c">targen -c</a>, then use the PrinterA.icm
- profile, <b>NOT</b> PrinterA_c.icm that has calibration curves
- applied.<br>
- <h4><a name="PC6"></a>How profile ink limits are handled when
- calibration is being used.</h4>
- Even though the profiling process is carried out on top of the
- linearized device, and the profiling is generally unaware of the
- underlying non-linearized device values, an exception is made in the
- calculation of ink limits during profiling. This is made possible by
- including the calibration curves in the profile charts .ti2 and
- subsequent .ti3 file and resulting ICC profile <span
- style="font-weight: bold;">'targ'</span> text tag, by way of the <span
- style="font-weight: bold;">printtarg</span> <span
- style="font-weight: bold;">-I</span> or <span style="font-weight:
- bold;">-K</span> options. This is done on the assumption that the
- physical quantity of ink is what's important in setting the ink
- limit, and that the underlying non-linearized device values
- represent such a physical quantity.<br>
- <br>
- <br>
- <hr size="2" width="100%">
- <h3><a name="LP1"></a>Linking Profiles</h3>
- Two device profiles can be linked together to create a device link
- profile, than encapsulates a particular device to device transform.
- Often this step is not necessary, as many systems and tools will
- link two device profiles "on the fly", but creating a device link
- profile gives you the option of using "smart CMM" techniques, such
- as true gamut mapping, improved inverse transform accuracy, tailored
- black generation and ink limiting.<br>
- <br>
- The overall process is to link the input space and output space
- profiles using <a href="collink.html">collink</a>, creating a
- device to device link profile. The device to device link profile can
- then be used by cctiff (or other ICC device profile capable tools),
- to color correct a raster files.<br>
- <br>
- Three examples will be given here, showing the three different modes
- than <span style="font-weight: bold;">collink</span> supports.<br>
- <br>
- In <a href="collink.html#s">simple mode</a>, the two profiles are
- linked together in a similar fashion to other <span
- style="font-weight: bold;">CMMs</span> simply using the forward
- and backwards color transforms defined by the profiles. Any gamut
- mapping is determined by the content of the tables within the two
- profiles, together with the particular intent chosen. Typically the
- same intent will be used for both the source and destination
- profile:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#s">-s</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#so">-op</a>
- <a href="collink.html#p1">SouceProfile.icm</a> <a
- href="collink.html#p2">DestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- <br>
- In <a href="collink.html#g">gamut mapping mode</a>, the
- pre-computed intent mappings inside the profiles are not used, but
- instead the gamut mapping between source and destination is tailored
- to the specific gamuts of the two profiles, and the intent parameter
- supplied to <span style="font-weight: bold;">collink</span>.
- Additionally, source and destination viewing conditions should be
- provided, to allow the color appearance space conversion to work as
- intended. The colorimetric B2A table in the destination profile is
- used, and this will determine any black generation and ink limiting:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#g">-g</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
- <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
- <a href="collink.html#p2">DestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- [ If your viewing environment for the display and print doesn't
- match the ones implied by the <a href="colprof.html#c">-cmt</a> and
- <a href="colprof.html#d">-dpp</a> options, leave them out, and
- evaluate what, if any appearance transformation is appropriate for
- your environment at a later stage. ]<br>
- <br>
- In <a href="collink.html#G">inverse output table gamut mapping mode</a>,
- the pre-computed intent mappings inside the profiles are not used,
- but instead the gamut mapping between source and destination is
- tailored to the specific gamuts of the two profiles, and the intent
- parameter supplied to <span style="font-weight: bold;">collink</span>.
- In addition, the B2A table is <span style="font-weight: bold;">not</span>
- used in the destination profile, but the A2B table is instead
- inverted, leading to improved transform accuracy, and in CMYK
- devices, allowing the ink limiting and black generation parameters
- to be set:<br>
- <br>
- For a CLUT table based RGB printer destination profile, the
- following would be appropriate:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
- <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
- <a href="collink.html#p2">RGBDestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- For a CMYK profile, the total ink limit needs to be specified (a
- typical value being 10% less than the value used in creating the
- device test chart), and the type of black generation also needs to
- be specified:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
- <a href="collink.html#d">-dpp</a> <a href="collink.html#l">-l250</a>
- <a href="collink.html#k">-kr</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
- <a href="collink.html#p2">CMYKDestinationProfile.icm</a> <a
- href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- Note that you should set the source (<a href="collink.html#c">-c</a>)
- and destination (<a href="collink.html#d">-d</a>) viewing conditions
- for the type of device the profile represents, and the conditions
- under which it will be viewed.<br>
- <br>
- <h3><a name="LP3"></a>Image dependent gamut mapping using device
- links<br>
- </h3>
- When images are stored in large gamut colorspaces (such as. L*a*b*,
- ProPhoto, scRGB etc.), then using the colorspace gamut as the source
- gamut for gamut mapping is generally a bad idea, as it leads to
- overly compressed and dull images. The correct approach is to use a
- source gamut that represents the gamut of the images themselves.
- This can be created using tiffgamut, and an example workflow is as
- follows:<br>
- <br>
- <a href="tiffgamut.html">tiffgamut</a> -f80 -pj -cmt ProPhoto.icm
- image.tif<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qh</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#Gp">image.gam</a> <a href="collink.html#si">-ip</a>
- <a href="collink.html#c">-cmt</a> <a href="collink.html#d">-dpp</a>
- <a href="collink.html#p1">ProPhoto.icm</a> <a
- href="collink.html#p2">RGBDestinationProfile.icm</a>
- <a href="collink.html#p3">Source2Destination.icm</a><br>
- <br>
- <a href="cctiff.html">cctiff</a> <a
- href="cctiff.html#p1">Source2Destination.icm</a>
- <a href="cctiff.html#p3">image.tif</a> <a
- href="cctiff.html#p4">printfile.tif</a><br>
- <br>
- The printfile.tif is then send to the printer without color
- management, (i.e. in the same way the printer characterization test
- chart was printed), since it is in the printers native colorspace.<br>
- <br>
- You can adjust how conservatively the image gamut is preserved using
- the tiffgamut -f parameter. Omitting it or using a larger value (up
- to 100) preserves the color gradations of even the lesser used
- colors, at the cost of compressing the gamut more.<br>
- Using a smaller value will preserve the saturation of the most
- popular colors, at the cost of not preserving the color gradations
- of less popular colors.<br>
- <br>
- You can create a gamut that covers a set of source images by
- providing more than one image file name to tiffgamut. This may be
- more efficient for a group of related images, and ensures that
- colors are transformed in exactly the same way for all of the
- images.<br>
- <br>
- An alternative generating a gamut for a specific set of images, is
- to use a general smaller gamut definition (i.e. the sRGB profile),
- or a gamut that represents the typical range of colors you wish to
- preserve.<br>
- <br>
- The arguments to collink should be appropriate for the output device
- type - see the collink examples in the above section.<br>
- <h3><a name="LP2"></a>Soft Proofing Link</h3>
- Often it is desirable to get an idea what a particular devices
- output will look like using a different device. Typically this might
- be trying to evaluate print output using a display. Often it is
- sufficient to use an absolute or relative colorimetric transform
- from the print device space to the display space, but while these
- provide a colorimetric preview of the result, they do not take into
- account the subjective appearance differences due to the different
- device conditions. It can therefore be useful to create a soft proof
- appearance transform using collink:<br>
- <br>
- <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
- <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
- href="collink.html#si">-ila</a> <a href="collink.html#c">-cpp</a>
- <a href="collink.html#d">-dmt</a> <a href="collink.html#l">-t250</a>&nbsp;<a
- href="collink.html#k"></a><a href="collink.html#p1">CMYKDestinationProfile.icm</a>
- <a href="collink.html#p2">MonitorProfile.icm</a> <a
- href="collink.html#p3">SoftProof.icm</a><br>
- <br>
- We use the Luminance matched appearance intent, to preserve the
- subjective apperance of the target device, which takes into account
- the viewing conditions and assumes adaptation to the differences in
- the luminence range, but otherwise not attempting to compress or
- change the gamut.<br>
- <br>
- If your viewing environment for the display and print doesn't match
- the ones implied by the <a href="collink.html#c">-cpp</a> and <a
- href="collink.html#d">-dmt</a> options, then either leave them out
- or substitute values that do match your environment.<br>
- &nbsp;
- <hr size="2" width="100%"><br>
- <h3><a name="TR1"></a>Transforming colorspaces of raster files</h3>
- Although a device profile or device link profile may be useful with
- other programs and systems, Argyll provides the tool <a
- href="cctiff.html">cctiff</a> for directly applying a device to
- device transform to a <a href="File_Formats.html#TIFF">TIFF</a> or
- <a href="File_Formats.html#JPEG">JPEG</a> raster file. The cctiff
- tool is capable of linking an arbitrary sequence of device profiles,
- device links, abstract profiles and calibration curves. Each device
- profile can be preceded by the <span style="font-weight: bold;">-i</span>
- option to indicate the intent that should be used. Both 8 and 16 bit
- per component files can be handled, and up to 8 color channels. The
- color transform is optimized to perform the overall transformation
- rapidly.<br>
- <br>
- If a device link is to be used, the following is a typical example:<br>
- <br>
- <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
- <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
- or<br>
- <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
- <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
- <br>
- <i><br>
- </i>If a source and destination profile are to be used, the
- following would be a typical example:<br>
- <br>
- <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
- <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
- href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
- <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
- or<br>
- <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
- <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
- href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
- <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
- <br>
- <br>
- <hr size="2" width="100%"><br>
- <h3><a name="TV1"></a>Creating Video Calibration 3DLuts</h3>
- Video calibration typically involves trying to make your actual
- display device emulate an ideal video display, one which matches
- what your Video media was intended to be displayed on. An ICC device
- link embodies the machinery to do exactly this, to take device
- values in the target source colorspace and transform them into an
- actual output device colorspace. In the Video and Film industries a
- very similar, but less sophisticated means of doing this is to use
- 3DLuts, which come in a multitude of different format. ICC device
- links have the advantage of being a superset of 3dLuts, encapsulated
- in a standard file format.<br>
- <br>
- To facilitate Video calibration of certain Video systems, ArgyllCMS
- supports some 3DLut output options as part of <a
- href="collink.html">collink</a>.<br>
- <br>
- What follows here is an outline of how to create Video calibration
- 3DLuts using ArgyllCMS. First comes a general discussion of various
- aspects of video device links/3dLuts, and followed with some
- specific advice regarding the systems that ArgyllCMS supports. Last
- is some recommended scenarios for verifying the quality of Video
- calibration achieved.<br>
- <h5>1) How to display test patches.<br>
- </h5>
- Argyll's normal test patch display will be used by default, as long
- as any video encoding range considerations are dealt with (see
- Signal encoding below).<br>
- <br>
- An alternative when working with MadVR V 0.86.9 or latter, is to use
- the madTPG to display the patches in which case the MadVR video
- encoding range setting will operate. This can give some quality
- benefits due to MadVR's use of dithering. To display patches using
+
+ profile chart.<br>
+ <br>
+ <br>
+ In a workflow <span style="font-weight: bold;">with</span> native
+ calibration capability, the calibration curves would be used with
+ printarg during subsequent <span style="font-weight: bold;">profiling</span>
+ so that any ink limit calculations will reflect final device values,
+ while not otherwise using the calibration within the ICC workflow:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
+ href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
+ <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#I">-I
+ PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <br>
+ This will cause the .ti2 and resulting .ti3 and ICC profiles to
+ contain the calibration curves, allowing all the tools to be able to
+ compute final device value ink limits. The calibration curves must
+ also of course be installed into the printer. The means to do this
+ is currently outside the scope of Argyll (ie. either the print
+ system needs to be able to understand Argyll CAL format files, or
+ some tool will be needed to convert Argyll CAL files into the
+ printer calibration format).<br>
+ <br>
+ <br>
+ In a workflow <span style="font-weight: bold;">without</span>
+ native calibration capability, the calibration curves would be used
+ with printarg to <span style="text-decoration: underline;">apply</span>
+ the calibration to the test patch samples during subsequent <span
+ style="font-weight: bold;">profiling</span>, as well as embedding
+ it in the resulting .ti3 to allow all the tools to be able to
+ compute final device value ink limits:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
+ href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
+ <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#K">-K
+ PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <a href="cctiff.html#p4"></a><br>
+ To apply calibration to an ICC profile, so that a calibration
+ unaware CMM can be used:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="applycal.html">applycal</a> <a
+ href="applycal.html#p1">PrinterA.cal</a> <a
+ href="applycal.html#p2">PrinterA.icm</a> <a
+ href="applycal.html#p3">PrinterA_cal.icm</a><br>
+ <br>
+ To apply color management and calibration to a raster image:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="file:///D:/src/argyll/doc/cctiff.html">cctiff</a>
+ <a href="file:///D:/src/argyll/doc/cctiff.html#p1">Source.icm</a> <a
+ href="file:///D:/src/argyll/doc/cctiff.html#p1">PrinterA.icm</a> <a
+ href="file:///D:/src/argyll/doc/cctiff.html#p2">PrinterA_c.cal</a>
+ <a href="file:///D:/src/argyll/doc/cctiff.html#p3">infile.tif</a> <a
+ href="file:///D:/src/argyll/doc/cctiff.html#p4">outfile.tif</a><br>
+ <br>
+ or<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="file:///D:/src/argyll/doc/cctiff.html">cctiff</a>
+ <a href="file:///D:/src/argyll/doc/cctiff.html#p1">Source.icm</a> <a
+ href="file:///D:/src/argyll/doc/cctiff.html#p1">PrinterA_c.icm</a>
+ <a href="file:///D:/src/argyll/doc/cctiff.html#p3">infile.tif</a> <a
+ href="file:///D:/src/argyll/doc/cctiff.html#p4">outfile.tif</a><br>
+ <br>
+ [ Note that cctiff will also process JPEG raster images. ]<br>
+ <br>
+ Another useful tool is <a href="synthcal.html">synthcal</a>, that
+ allows creating linear or synthetic calibration files for disabling
+ calibration or testing.<br>
+ Similarly, <a href="fakeread.html">fakeread</a> also supports
+ applying calibration curves and embedding them in the resulting .ti3
+ file<br>
+ <br>
+ If you want to create a pre-conditioning profile for use with <a
+ href="targen.html#c">targen -c</a>, then use the PrinterA.icm
+ profile, <b>NOT</b> PrinterA_c.icm that has calibration curves
+ applied.<br>
+ <h4><a name="PC6"></a>How profile ink limits are handled when
+ calibration is being used.</h4>
+ Even though the profiling process is carried out on top of the
+ linearized device, and the profiling is generally unaware of the
+ underlying non-linearized device values, an exception is made in the
+ calculation of ink limits during profiling. This is made possible by
+ including the calibration curves in the profile charts .ti2 and
+ subsequent .ti3 file and resulting ICC profile <span
+ style="font-weight: bold;">'targ'</span> text tag, by way of the <span
+ style="font-weight: bold;">printtarg</span> <span
+ style="font-weight: bold;">-I</span> or <span style="font-weight:
+ bold;">-K</span> options. This is done on the assumption that the
+ physical quantity of ink is what's important in setting the ink
+ limit, and that the underlying non-linearized device values
+ represent such a physical quantity.<br>
+ <br>
+ <br>
+ <hr size="2" width="100%">
+ <h3><a name="LP1"></a>Linking Profiles</h3>
+ Two device profiles can be linked together to create a device link
+ profile, than encapsulates a particular device to device transform.
+ Often this step is not necessary, as many systems and tools will
+ link two device profiles "on the fly", but creating a device link
+ profile gives you the option of using "smart CMM" techniques, such
+ as true gamut mapping, improved inverse transform accuracy, tailored
+ black generation and ink limiting.<br>
+ <br>
+ The overall process is to link the input space and output space
+ profiles using <a href="collink.html">collink</a>, creating a
+ device to device link profile. The device to device link profile can
+ then be used by cctiff (or other ICC device profile capable tools),
+ to color correct a raster files.<br>
+ <br>
+ Three examples will be given here, showing the three different modes
+ than <span style="font-weight: bold;">collink</span> supports.<br>
+ <br>
+ In <a href="collink.html#s">simple mode</a>, the two profiles are
+ linked together in a similar fashion to other <span
+ style="font-weight: bold;">CMMs</span> simply using the forward
+ and backwards color transforms defined by the profiles. Any gamut
+ mapping is determined by the content of the tables within the two
+ profiles, together with the particular intent chosen. Typically the
+ same intent will be used for both the source and destination
+ profile:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#s">-s</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#so">-op</a>
+ <a href="collink.html#p1">SouceProfile.icm</a> <a
+ href="collink.html#p2">DestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ <br>
+ In <a href="collink.html#g">gamut mapping mode</a>, the
+ pre-computed intent mappings inside the profiles are not used, but
+ instead the gamut mapping between source and destination is tailored
+ to the specific gamuts of the two profiles, and the intent parameter
+ supplied to <span style="font-weight: bold;">collink</span>.
+ Additionally, source and destination viewing conditions should be
+ provided, to allow the color appearance space conversion to work as
+ intended. The colorimetric B2A table in the destination profile is
+ used, and this will determine any black generation and ink limiting:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#g">-g</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">DestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ [ If your viewing environment for the display and print doesn't
+ match the ones implied by the <a href="colprof.html#c">-cmt</a> and
+ <a href="colprof.html#d">-dpp</a> options, leave them out, and
+ evaluate what, if any appearance transformation is appropriate for
+ your environment at a later stage. ]<br>
+ <br>
+ In <a href="collink.html#G">inverse output table gamut mapping mode</a>,
+ the pre-computed intent mappings inside the profiles are not used,
+ but instead the gamut mapping between source and destination is
+ tailored to the specific gamuts of the two profiles, and the intent
+ parameter supplied to <span style="font-weight: bold;">collink</span>.
+ In addition, the B2A table is <span style="font-weight: bold;">not</span>
+ used in the destination profile, but the A2B table is instead
+ inverted, leading to improved transform accuracy, and in CMYK
+ devices, allowing the ink limiting and black generation parameters
+ to be set:<br>
+ <br>
+ For a CLUT table based RGB printer destination profile, the
+ following would be appropriate:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">RGBDestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ For a CMYK profile, the total ink limit needs to be specified (a
+ typical value being 10% less than the value used in creating the
+ device test chart), and the type of black generation also needs to
+ be specified:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#l">-l250</a>
+ <a href="collink.html#k">-kr</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">CMYKDestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ Note that you should set the source (<a href="collink.html#c">-c</a>)
+ and destination (<a href="collink.html#d">-d</a>) viewing conditions
+ for the type of device the profile represents, and the conditions
+ under which it will be viewed.<br>
+ <br>
+ <h3><a name="LP3"></a>Image dependent gamut mapping using device
+ links<br>
+ </h3>
+ When images are stored in large gamut colorspaces (such as. L*a*b*
+ or ProPhoto, etc.), then using the colorspace gamut as the source
+ gamut for gamut mapping is generally a bad idea, as it leads to
+ overly compressed and dull images. The correct approach is to use a
+ source gamut that represents the gamut of the images themselves.
+ This can be created using tiffgamut, and an example workflow is as
+ follows:<br>
+ <br>
+ <a href="tiffgamut.html">tiffgamut</a> -f80 -pj -cmt ProPhoto.icm
+ image.tif<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qh</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#Gp">image.gam</a> <a href="collink.html#si">-ip</a>
+ <a href="collink.html#c">-cmt</a> <a href="collink.html#d">-dpp</a>
+ <a href="collink.html#p1">ProPhoto.icm</a> <a
+ href="file:///D:/src/argyll/doc/collink.html#p2">RGBDestinationProfile.icm</a>
+ <a href="file:///D:/src/argyll/doc/collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ <a href="file:///D:/src/argyll/doc/cctiff.html">cctiff</a> <a
+ href="file:///D:/src/argyll/doc/cctiff.html#p1">Source2Destination.icm</a>
+ <a href="file:///D:/src/argyll/doc/cctiff.html#p3">image.tif</a> <a
+ href="file:///D:/src/argyll/doc/cctiff.html#p4">printfile.tif</a><br>
+ <br>
+ The printfile.tif is then send to the printer without color
+ management, (i.e. in the same way the printer characterization test
+ chart was printed), since it is in the printers native colorspace.<br>
+ <br>
+ You can adjust how conservatively the image gamut is preserved using
+ the tiffgamut -f parameter. Omitting it or using a larger value (up
+ to 100) preserves the color gradations of even the lesser used
+ colors, at the cost of compressing the gamut more.<br>
+ Using a smaller value will preserve the saturation of the most
+ popular colors, at the cost of not preserving the color gradations
+ of less popular colors.<br>
+ <br>
+ You can create a gamut that covers a set of source images by
+ providing more than one image file name to tiffgamut. This may be
+ more efficient for a group of related images, and ensures that
+ colors are transformed in exactly the same way for all of the
+ images.<br>
+ <br>
+ The arguments to collink should be appropriate for the output device
+ type - see the collink examples in the above section.<br>
+ <h3><a name="LP2"></a>Soft Proofing Link</h3>
+ Often it is desirable to get an idea what a particular devices
+ output will look like using a different device. Typically this might
+ be trying to evaluate print output using a display. Often it is
+ sufficient to use an absolute or relative colorimetric transform
+ from the print device space to the display space, but while these
+ provide a colorimetric preview of the result, they do not take into
+ account the subjective appearance differences due to the different
+ device conditions. It can therefore be useful to create a soft proof
+ appearance transform using collink:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ila</a> <a href="collink.html#c">-cpp</a>
+ <a href="collink.html#d">-dmt</a> <a href="collink.html#l">-t250</a>&nbsp;<a
+ href="collink.html#k"></a><a href="collink.html#p1">CMYKDestinationProfile.icm</a>
+ <a href="collink.html#p2">MonitorProfile.icm</a> <a
+ href="collink.html#p3">SoftProof.icm</a><br>
+ <br>
+ We use the Luminance matched appearance intent, to preserve the
+ subjective apperance of the target device, which takes into account
+ the viewing conditions and assumes adaptation to the differences in
+ the luminence range, but otherwise not attempting to compress or
+ change the gamut.<br>
+ <br>
+ If your viewing environment for the display and print doesn't match
+ the ones implied by the <a href="collink.html#c">-cpp</a> and <a
+ href="collink.html#d">-dmt</a> options, then either leave them out
+ or substitute values that do match your environment.<br>
+ &nbsp;
+ <hr size="2" width="100%"><br>
+ <h3><a name="TR1"></a>Transforming colorspaces of raster files</h3>
+ Although a device profile or device link profile may be useful with
+ other programs and systems, Argyll provides the tool <a
+ href="cctiff.html">cctiff</a> for directly applying a device to
+ device transform to a <a href="File_Formats.html#TIFF">TIFF</a> or
+ <a href="File_Formats.html#JPEG">JPEG</a> raster file. The cctiff
+ tool is capable of linking an arbitrary sequence of device profiles,
+ device links, abstract profiles and calibration curves. Each device
+ profile can be preceded by the <span style="font-weight: bold;">-i</span>
+ option to indicate the intent that should be used. Both 8 and 16 bit
+ per component files can be handled, and up to 8 color channels. The
+ color transform is optimized to perform the overall transformation
+ rapidly.<br>
+ <br>
+ If a device link is to be used, the following is a typical example:<br>
+ <br>
+ <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <br>
+ <i><br>
+ </i>If a source and destination profile are to be used, the
+ following would be a typical example:<br>
+ <br>
+ <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
+ <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
+ href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
+ <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
+ href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <br>
+ <br>
+ <hr size="2" width="100%"><br>
+ <h3><a name="TV1"></a>Creating Video Calibration 3DLuts</h3>
+ Video calibration typically involves trying to make your actual
+ display device emulate an ideal video display, one which matches
+ what your Video media was intended to be displayed on. An ICC device
+ link embodies the machinery to do exactly this, to take device
+ values in the target source colorspace and transform them into an
+ actual output device colorspace. In the Video and Film industries a
+ very similar, but less sophisticated means of doing this is to use
+ 3DLuts, which come in a multitude of different format. ICC device
+ links have the advantage of being a superset of 3dLuts, encapsulated
+ in a standard file format.<br>
+ <br>
+ To facilitate Video calibration of certain Video systems, ArgyllCMS
+ supports some 3DLut output options as part of <a
+ href="collink.html">collink</a>.<br>
+ <br>
+ What follows here is an outline of how to create Video calibration
+ 3DLuts using ArgyllCMS. First comes a general discussion of various
+ aspects of video device links/3dLuts, and followed with some
+ specific advice regarding the systems that ArgyllCMS supports. Last
+ is some recommended scenarios for verifying the quality of Video
+ calibration achieved.<br>
+ <h5>1) How to display test patches.<br>
+ </h5>
+ Argyll's normal test patch display will be used by default, as long
+ as any video encoding range considerations are dealt with (see
+ Signal encoding below).<br>
+ <br>
+ An alternative when working with MadVR V 0.86.9 or latter, is to use
+ the madTPG to display the patches in which case the MadVR video
+ encoding range setting will operate. This can give some quality
+ benefits due to MadVR's use of dithering. To display patches using
MadVR rather than Argyll, start madTPG and then use the option "<b>-d
-
-
-
- madvr</b>" in dispcal, dispread and dispwin. Leave the MadTPG
- "VideoLUT" and "3dluts" buttons in their default&nbsp; (enabled)
- state, as the various tools will automatically take care of
- disabling the 3dLut and/or calibration curves as needed.<br>
- <br>
- Another option is to use a <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a>
- using the option "<b>-dcc</b>" in dispcal, dispread and dispwin.
- Note that the ChromeCast as a test patch source is probably the<b>
- least accurate</b> of your choices, since it up-samples the test
- patch and transforms from RGB to YCC and back, but should be
- accurate within ± 1 bit. You may have to modify any firewall to
- permit port 8081 to be accessed on your machine if it falls back to
- the Default receiver (see <a href="Installing.html">installation
- instructions</a> for your platform).
- <h5>2) White point calibration &amp; neutral axis calibration.</h5>
- A Device Link is capable of embodying all aspects of the
- calibration, including correcting the white point and neutral axis
- behavior of the output device, but making such a Link just from two
- ICC profile requires the use of Absolute Colorimetric intent during
- linking, and this reduces flexibility. In addition, a typical ICC
- device profile may not capture the neutral axis behavior quite as
- well as an explicit calibration, since it doesn't sample the
- displays neutral axis behaviour in quite as much detail. It is often
- desirable therefore, to calibrate the display device so as to have
- the specific white point desired so that one of the white point
- relative linking intents can be used, and to improve the displays
- general neutral axis behavior so that subsequent profiling works to
- best advantage. In summary, there are basically 4 options in
- handling white point &amp; neutral axis calibration:<br>
- <ul>
- <li>Don't bother correcting the white point. Most displays are
- close to the typical D65 target, and our eyes adapt to the white
- automatically unless it is very far from the daylight locus or
- we have something else to refer to. If this approach is taken,
- then display profiling and linking can ignore calibration, and
- one of the non Absolute Colorimetric intents (such as Relative
- Colorimetric) is chosen during profile linking. It is wise to
- make sure that the video card VideoLUTs are set to some known
- state (ie. linear using "dispwin -c" , or set by a an installed
- ICC display profile) though.<br>
- </li>
- <li>Calibrate the white point and linearise the neutral axis using
- the display controls. Many TV's have internal calibration
- controls that allow setting the white point, and possibly the
- neutral axis response. Either a dedicated Video calibration
+
+ madvr</b>" in dispcal, dispread and dispwin. Leave the MadTPG
+ "VideoLUT" and "3dluts" buttons in their default&nbsp; (enabled)
+ state, as the various tools will automatically take care of
+ disabling the 3dLut and/or calibration curves as needed.<br>
+ <br>
+ Another option is to use a <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a>
+ using the option "<b>-dcc</b>" in dispcal, dispread and dispwin.
+ Note that the ChromeCast as a test patch source is probably the<b>
+ least accurate</b> of your choices, since it up-samples the test
+ patch and transforms from RGB to YCC and back, but should be
+ accurate within ± 1 bit. You may have to modify any firewall to
+ permit port 8081 to be accessed on your machine if it falls back to
+ the Default receiver (see <a href="Installing.html">installation
+ instructions</a> for your platform).
+ <h5>2) White point calibration &amp; neutral axis calibration.</h5>
+ A Device Link is capable of embodying all aspects of the
+ calibration, including correcting the white point and neutral axis
+ behavior of the output device, but making such a Link just from two
+ ICC profile requires the use of Absolute Colorimetric intent during
+ linking, and this reduces flexibility. In addition, a typical ICC
+ device profile may not capture the neutral axis behavior quite as
+ well as an explicit calibration, since it doesn't sample the
+ displays neutral axis behaviour in quite as much detail. It is often
+ desirable therefore, to calibrate the display device so as to have
+ the specific white point desired so that one of the white point
+ relative linking intents can be used, and to improve the displays
+ general neutral axis behavior so that subsequent profiling works to
+ best advantage. In summary, there are basically 4 options in
+ handling white point &amp; neutral axis calibration:<br>
+ <ul>
+ <li>Don't bother correcting the white point. Most displays are
+ close to the typical D65 target, and our eyes adapt to the white
+ automatically unless it is very far from the daylight locus or
+ we have something else to refer to. If this approach is taken,
+ then display profiling and linking can ignore calibration, and
+ one of the non Absolute Colorimetric intents (such as Relative
+ Colorimetric) is chosen during profile linking. It is wise to
+ make sure that the video card VideoLUTs are set to some known
+ state (ie. linear using "dispwin -c" , or set by a an installed
+ ICC display profile) though.<br>
+ </li>
+ <li>Calibrate the white point and linearise the neutral axis using
+ the display controls. Many TV's have internal calibration
+ controls that allow setting the white point, and possibly the
+ neutral axis response. Either a dedicated Video calibration
package could be used, or ArgyllCMS <a href="dispcal.html">dispcal</a>'s
@@ -3274,30 +3215,28 @@ a
-
-
-
- interactive adjustment mode can be used to set the white point.
- Note that while adjusting the neutral axis for neutrality may
- help, the Device Link will override the transfer curve
- characteristic of the calibrated display, so aiming for a
- transfer curve approximately the same as the target and
- reasonably perceptually linear is all that is required. If this
- approach is taken, then display profiling and linking can ignore
- calibration, and one of the non Absolute Colorimetric intents is
- chosen during profile linking. It is wise to make sure that the
- video card VideoLUTs are set to some known state&nbsp; though.</li>
- <li>[<b>Recommended</b>] Calibrate the white point and neutral
- axis using ArgyllCMS <a href="dispcal.html">dispcal</a>. Since
- the Device Link will override the calibrated transfer curve
- characteristic of the display, there there may be no point in
- doing much more than a medium calibration, and choosing a
- standard that has a straight segment from black, such as L*a*b*,
- sRGB, Rec709 or SMPTE240 curve. The exact shape of the
- calibration curve is not critically important, as the profiling
- and 3dLut will set the final response. If this approach is
- taken, then the resulting calibration file should be provided to
- dispread as the <a href="dispcal.html#k">-k parameter</a> or <a
+
+ interactive adjustment mode can be used to set the white point.
+ Note that while adjusting the neutral axis for neutrality may
+ help, the Device Link will override the transfer curve
+ characteristic of the calibrated display, so aiming for a
+ transfer curve approximately the same as the target and
+ reasonably perceptually linear is all that is required. If this
+ approach is taken, then display profiling and linking can ignore
+ calibration, and one of the non Absolute Colorimetric intents is
+ chosen during profile linking. It is wise to make sure that the
+ video card VideoLUTs are set to some known state&nbsp; though.</li>
+ <li>[<b>Recommended</b>] Calibrate the white point and neutral
+ axis using ArgyllCMS <a href="dispcal.html">dispcal</a>. Since
+ the Device Link will override the calibrated transfer curve
+ characteristic of the display, there there may be no point in
+ doing much more than a medium calibration, and choosing a
+ standard that has a straight segment from black, such as L*a*b*,
+ sRGB, Rec709 or SMPTE240 curve. The exact shape of the
+ calibration curve is not critically important, as the profiling
+ and 3dLut will set the final response. If this approach is
+ taken, then the resulting calibration file should be provided to
+ dispread as the <a href="dispcal.html#k">-k parameter</a> or <a
href="dispcal.html#K">-K parameter</a>.&nbsp; See also below <b>Choice
@@ -3310,478 +3249,476 @@ a
-
-
-
- of where to apply display per channel calibration curves.</b></li>
- <li>Choose one of the Absolute Colorimetric intents in collink
- (ie. -i aw). This greatly reduces flexibility, and may not be
- quite as accurate as an explicit calibration.</li>
- </ul>
- If an explicit calibration is used, then it is a good idea to add
- some test points down the neutral axis when profiling (targen <a
- href="targen.html#g">-g parameter</a>). <br>
- <br>
- <b>3) Choice of where to apply display per channel calibration
- curves</b><br>
- <br>
- If calibration curves are going to be used, then it needs to be
- decided where they will be applied in the video processing chain.
- There are two options:<br>
- <br>
- <b>a)</b> Install the calibration curves in the playback system. On
- a PC the display, this can be done by loading the calibration curves
- into the Video Card temporarily using "dispwin calibration.cal", or
- installing the ICC profile into the system persistently using
- something like "<a href="dispwin.html#I">dispwin -I profile.icm</a>",<br>
- or when using MadVR 0.86.9 or latter by creating a 3dLut with
- appended calibration curves using <a href="collink#H">-H
- display.cal</a>.<br>
- <br>
- <b>b)</b> The calibration can be incorporated into the Device
- Link/3dLUT by providing it to collink as the <a
- href="collink.html#a">-a display.cal</a>. This is the only option
- if the video display path does not have some separate facility to
- handle calibration curves. Note that if the playback system has
- graphic card VideoLUTs then they will have to be set to a defined
- consistent state such as linear. When using MadVR 0.86.9 or latter
- this will be done automatically since the -a option will append a
- linear set of calibration curves to the 3dLut.<br>
- <br>
- The choice is dictated by a number of considerations:<br>
- <ul>
- <li>Does the video playback path have a facility for installing
- the calibration curves ? If playing back system is a PC, then
- typically the Graphics Card supports 1D VideoLUTs, thereby
- making a) a possible choice.<br>
- </li>
- <li>Does the video playback <u>always</u> play back through the
- Video Card VideoLUTs ? Some systems do not apply VIdeoLUTs to
- things like overlay plane rendering. If not, then you need to
- choose b), but also make sure that if it does use the Video Card
- VideoLUTs in some situations, that they are set to linear (ie.
- dispcal -c). One way of determining when the VideoLUTs get used
- or not is to load a distinct calibration such as "strange.cal"
- provided in the <b>ref</b> folder, and check visually if it is
- affecting the video or not, ie. "dispcal strange.cal". Note that
- using MadVR 0.86.9 or latter in combination with a 3dLut with
- appended calibration curves will apply the calibration even with
- overlay plane rendering.<br>
- </li>
- <li>Do you want/need other applications to share the calibration
- curves or profile or not ? If you do, then it is desirable to
- choose a).</li>
- <li>Quality considerations. VideoLUTs may or may not be of greater
- depth than the standard 8 bit per color component frame buffer.
- If they are, and the video path passes that extra depth through
- to the display, and the display is capable of using that extra
- depth, then a) may be a desirable choice from a quality point of
- view. You can get some idea whether this is the case by running
- "dispcal -R". If the VideoLUT depth is not better than 8 bits,
- then it may be more desirable to choose b), since renders like
- MadVR can use dithering to give better than 8 bits precision in
- the video playback.<br>
- </li>
- </ul>
- <h5>4) Output device calibration and profiling.</h5>
- Output device profiling should basically follow the guide above in <a
- href="#PM1b">Adjusting and Calibrating a displays</a> and <a
- href="#PM1">Profiling Displays</a>. The assumption is that either
- you are calibrating/profiling your computer display for video, or
- your TV is connected to the computer you are creating
- calibrations/profiles on, and that the connection between the PC and
- TV display is such that full range RGB signals are being used, or
- that the Video card has automatically or manually been configured to
- scale full range RGB values to Video levels for the TV. If the
- latter is not possible, then use the -E options on dispcal and
- dispread. (See <b>Signal encoding</b> bellow for more details on
- this). It may also improve the accuracy of the display profile if
- you use the <a href="dispread.html#Z">dispread -Z</a> option to
- quantize the test values to the precision of the display
- system.&nbsp; Don't use the -E options on dispcal and dispread, nor
- the -Z option on dispread if you are using MadVR to display test
- patches using the "-d madvr" option.<br>
- <br>
- Once the profile has been created, it is possible to then use the
- resulting Device Link/3DLut with signal encoding other than full
- range or Video level RGB. <br>
- <h5>5) Target colorspace<br>
- </h5>
- In practical terms, there are five common Video and Digital Cinema
- encoding colorspaces. <br>
- <br>
- For Standard Definition:<br>
- <br>
- &nbsp;&nbsp;&nbsp; EBU 3213 or "PAL 576i" primaries.<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE RP 145 or "NTSC 480i" primaries.<br>
- <br>
- For High Definition:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec 709 primaries.<br>
- <br>
- For Ultra High Defintion<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec 2020 primaries.<br>
- <br>
- For Digital Cinema<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE-431-2&nbsp; or "DCI-P3"<br>
- <br>
- PAL and NTSC have historically had poorly specified transfer curve
- encodings, and the Rec 709 HDTV encoding curve is the modern <a
- href="http://www.poynton.com/notes/DVAI/DVAI_TOC_full.html#23">recommendation</a>,
- but the overall interpretation of Video sources may in fact be
- partly determined by the expected standard Video display device
- characteristics (see <b>Viewing conditions adjustment and gamut
- mapping</b> below for more details).<br>
- <br>
- To enable targeting these colorspaces, ArgyllCMS provides 5 ICC
- profiles in the ref directory to use as source
- colorspaces:&nbsp;&nbsp;&nbsp; <br>
- <br>
- &nbsp;&nbsp;&nbsp; EBU3213_PAL.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE_RP145_NTSC.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec709.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; Rec2020.icm<br>
- <br>
- &nbsp;&nbsp;&nbsp; SMPTE431_P3.icm<br>
- <h5>6) Signal encoding</h5>
- Typical PC display output uses full range RGB signals (0 .. 255 in 8
- bit parlance), while typical Video encoding allows some head &amp;
- footroom for overshoot and sync of digitized analog signals, and
- typically uses a 16..235 range in 8 bits. In many cases Video is
- encoded as luma and color difference signals YCbCr (loosely known as
- YUV as well), and this also uses a restricted range 16..235 for Y,
- and 16..240 for Cb and Cr in 8 bit encoding. The extended gamut
- xvYCC encoding uses 16..235 for Y, and 1..254 for Cb and Cr.<br>
- <br>
- The signal encoding comes into play in two situations: 1)
- Calibrating and profiling the display, and 2) Using the resulting
- Device Link/3DLut.<br>
- The encoding may need to be different in these two situations,
- either because different video source devices are being used for
- calibration/profiling and for video playback, or because the video
- playback system uses the Device Link/3DLut at a point in its
- processing pipeline that requires a specific encoding.<br>
- <br>
- For calibration &amp; profiling, the display will be driven by a
- computer system so that dispcal and dispread can be used. By default
- these programs expect to output full range RGB signals, and it is
- assumed that either the display accepts full range signals, or that
- the graphics card or connection path has been setup to convert the
- full range values into Video range signals automatically or
- manually. If this is not the case, then both dispcal and dispread
- have a -E option that will modify them to output Video range RGB
- values.<br>
- <br>
- If MadVR is the target of the calibration and profiling, then there
- is an option to use it to display the calibration and profiling test
- patches (<b>-d madvr</b>). In this case, MadVR should be configured
- appropriately for full range or Video range encoding, and the -E
- flag should <u>not</u> be used with dispcal or dispread, since
- MadVR will be taking care of such conversions.<br>
- <br>
- If a calibration file was created using dispcal -E, then using it in
- dispread will automatically trigger Video level RGB signals during
- profiling. Any time such a Video level calibration is loaded into
- the Graphics card VideoLUTs using dispwin, or the calibration curve
- is converted to a 'vcgt' tag in a profile, the curve will also
- convert full range RGB to Video range RGB. This should be kept in
- mind so that if video playback is being performed with the
- calibration curves installed in the Graphics card VideoLUTs, that
- full range is converted only once to Video range (ie. In this
- situation MadVR output should be set to full range if being played
- back through the calibration curves in hardware, but only if dispcal
- -E has been used). On the other hand, if the calibration curves are
- incorporated into the DeviceLink/3dLUT, then the conversion to Video
- levels has to be done somewhere else in the pipeline, such as using
- MadVR video level output, or by the graphics card, etc.<br>
- <br>
- When creating the Device Link/3dLut, it is often necessary to
- specify one of the video encodings so that it fits in to the
- processing pipeline correctly. For instance the eeColor needs to
- have input and output encoding that suits the HDMI signals passing
- through it, typically Video Range RGB. MadVR needs Video Level RGB
- to match the values being passed through the 3dLut at that point.<br>
- <br>
- There are several version of YCbCr encoding supported as well, even
- though neither the eeColor nor the current version of MadVR need or
- can use them at present.<br>
- <h5>7) Black point mapping</h5>
- <p>Video encoding assumes that the black displayed on a device is a
- perfect black (zero light). No real device has a perfect black,
- and if a colorimetric intent is used then certain image values
- near black will get clipped to the display black point, loosing
- shadow detail. To avoid this, some sort of black point mapping is
- usually desirable. There are two mechanisms available in collink:
- a) Custom EOTF with input and/or output black point mapping, or b)
- using one of the smart gamut mapping intents that does black point
- mapping (e.g. la, p, pa, ms or s).<br>
- </p>
- <h5>8) Viewing conditions adjustment and gamut mapping</h5>
- <p> </p>
- <p>In historical TV systems, there is a viewing conditions
- adjustment being made between the bright studio conditions that TV
- is filmed in, and the typical dim viewing environment that people
- view it in. This is created by the difference between the encoding
- response curve gamma of about 2.0, and a typical CRT response
- curve gamma of 2.4. <br>
- </p>
- <p>In theory Rec709 defines the video encoding, but it seems in
- practice that much video material is adjusted to look as intended
- when displayed on a reference monitor having a display gamma of
- somewhere between 2.2 and 2.4, viewed in a dim viewing
- environment. The modern standard covering the display EOTF
- (Electro-Optical Transfer Curve) is <a
- href="http://www.itu.int/rec/R-REC-BT.1886-0-201103-I">BT.1886</a>,
- which defines a pure power 2.4 curve with an input offset and
- scale applied to account for the black point offset while
- retaining dark shadow tonality. So another means of making the
- viewing adjustment is to use the BT.1886-like EOTF for Rec709
- encoded material. Collink supports this using the <a
- href="collink.html#I">-I b</a>, and allows some control over the
- degree of viewing conditions adjustment by overriding the BT.1886
- gamma&nbsp; using the <a href="collink.html#Ib">-I b:g.g</a>
- parameter. This is the <b>recommended</b> approach to start with,
- since it gives good results with a single parameter.<br>
- </p>
- <p>The addition of a second optional parameter <a
- href="collink.html#Ib">-I b:p.p:g.g</a>
- allows control over the degree of black point offset accounted for
- as an output offset, as opposed to input offset Once the effective
- gamma value has been chosen to suite the viewing conditions and
- set the overall contrast for mid greys, increasing the proportion
- of black offset accounted for in the output of the curve is a way
- of reducing the deep shadow detail, if it is being overly
- emphasized. </p>
- <p> An alternate approach to making this adjustment is to take
- advantage of the viewing conditions adjustment using the CIECAM02
- model available in collink. Some control over the degree of
- viewing conditions adjustment is possible by varying the viewing
- condition parameters. </p>
- <p>A third alternative is to combine the two approaches. The source
- is defined as Rec709 primaries with a BT.1886-like EOTF display in
- dim viewing conditions, and then CIECAM02 is used to adjust for
- the actual display viewing conditions. Once again, control over
- the degree of viewing conditions adjustment is possible by varying
- the viewing condition parameters<br>
- </p>
- <p><br>
- </p>
- <p><b>9) Correcting for any black point inaccuracy in the display
- profile</b><br>
- </p>
- <p>Some video display devices have particularly good black points,
- and any slight raising of the black due to innacuracies in the
- display profile near black can be objectionable. As well as using
- the <a href="targen.html#V">targen -V flag</a> to improve
- accuracy near black during profiling, if the display is known to
- be well behaved (ie. that it's darkest black is actually at RGB
- value 0,0,0), then the <a href="collink.html#b">collink -b</a>
- flag can be used, to force the source RGB 0,0,0 to map to the
- display 0,0,0.<br>
- </p>
- <h5>Putting it all together:</h5>
- In this example we choose to create a display calibration first
- using dispcal, and create a simple matrix profile as well:<br>
- <br>
- &nbsp; <tt>dispcal -v -o -qm -k0 -w 0.3127,0.3290 -gs -o TVmtx.icm
- TV</tt><br>
- <br>
- We are targeting a D65 white point (<tt>-w 0.3127,0.3290)</tt> and
- an sRGB response curve.<br>
- <br>
- If you are using the madTPG you would use:<br>
- <br>
- &nbsp; <tt>dispcal -v -d madvr -o -qm -k0 -w 0.3127,0.3290 -gs -o
- TVmtx.icm TV</tt><br>
- <br>
- Then we need to create a display patch test set. We can use the
- simple matrix to pre-condition the test patches, as this helps
- distribute them where they will be of most benefit. If have
- previously profiled your display, you should use that previous
- profile, or if you decided not to do a dispcal, then the Rec709.icm
- should be used as a substitute. Some per channel and a moderate
- number of full spread patches is used here - more will increase
- profiling accuracy, a smaller number will speed it up. Since the
- video or film material is typically viewed in a darkened viewing
- environment, and often uses a range of maximum brightnesses in
- different scenes, the device behavior in the dark regions of its
- response are often of great importance, and using the <a
- href="targen.html#V">targen -V</a> parameter can help improve the
- accuracy in this region at the expense of slightly lower accuracy in
- lighter regions.<br>
- <br>
- &nbsp; <tt>targen -v -d3 -s30 -g100 -f1000 -cTVmtx.icm -V1.8 TV</tt><br>
- <br>
- The display can then be measured:<br>
- <br>
- &nbsp; <tt>dispread -v -k -Z8 TV.cal TV</tt><br>
- <br>
- or using madTPG:<br>
- <br>
- &nbsp;dispread -v -d madvr -K TV.cal TV<br>
- <br>
- and then a cLUT type ICC profile created. Since we will be using
- collink smart linking, we minimize the B2A table size. We use the
- default colprof -V parameter carried through from targen:<br>
- <br>
- &nbsp; <tt>colprof -v -qh -bl TV</tt><br>
- <br>
- Make sure you check the delta E report at the end of the profile
- creation, to see if the sample data and profile is behaving
- reasonably. Depending on the type of device, and the consistency of
- the readings, average errors of 5 or less, and maximum errors of 15
- or less would normally be expected. If errors are grossly higher
- than this, then this is an indication that something is seriously
- wrong with the device measurement, or profile creation.<br>
- <br>
- If you would like to use the display ICC profile for general color
- managed applications, then you would compute a more complete
- profile:<br>
- <br>
- &nbsp; <tt>colprof -v -qh TV</tt><br>
- <br>
- The recommended approach then is to create a Device Link that uses a
- BT.1886 black point and viewing conditions adjustment, say one of
- the following:<br>
- <br>
- <tt>&nbsp; collink -v -Ib:2.4 -b -G -ir Rec709.icm TV.icm
- HD.icm&nbsp;&nbsp; # dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib&nbsp;&nbsp;&nbsp;&nbsp; -b -G -ir
- Rec709.icm TV.icm HD.icm&nbsp;&nbsp; # dim conditions - good
- default</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib:2.1 -b -G -ir Rec709.icm TV.icm
- HD.icm&nbsp;&nbsp; # mid to dim conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib:2.0 -b -G -ir Rec709.icm TV.icm
- HD.icm&nbsp;&nbsp; # mid to light conditions</tt><br>
- <br>
- or you could do it using pure CIECAM02 adjustment and a black point
- mapping:<br>
- <br>
- <tt>&nbsp; collink -v -ctv -dmd -da:1 -G -ila Rec709.icm TV.icm
- HD.icm&nbsp; # very dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -ctv -dmd -da:3 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -ctv -dmd -da:7 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # mid to dim conditions - good default</tt><tt><br>
- </tt><tt> &nbsp; collink -v -ctv -dmd -da:15 -G -ila Rec709.icm
- TV.icm HD.icm # mid conditions</tt><br>
- <br>
- or using both to model a reference video display system that is
- adapted to your viewing conditions:<br>
- <tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:5&nbsp; -G -ila
- Rec709.icm TV.icm HD.icm # very dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:10 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:18 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp; # mid to dark conditions</tt><tt><br>
- </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:30 -G -ila Rec709.icm
- TV.icm HD.icm&nbsp;&nbsp; # mid to dark conditions</tt><br>
- <br>
- None of the above examples incorporate the calibration curves, so it
- is assumed that the calibration curves would be installed so that
- the Video Card applies calibration, ie:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <tt>dispwin TV.cal</tt><br>
- <br>
- or the simple matrix profile installed:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <tt>dispwin -I TVmtx.icm</tt><br>
- <br>
- or a the more complete display profile could be installed:<br>
- <br>
- &nbsp; dispwin -I TV.icm<br>
- <br>
- See also <a href="dispprofloc.html">here</a> for information on how
- to make sure the calibration is loaded on each system start. If not,
- then you will want to incorporate the calibration in the Device
- Link/3dlut by using collink "-a TV.cal".<br>
- <br>
- If the video path needs Video Level RGB encoding but does not
- provide a means to do this, then you will want to include the <b>-E</b>
- flag in the dispcal and dispread command lines above.<br>
- <br>
- Below are specific recommendation for the eeColor and MadVR that
- include the flags to create the .3dlut and encode the input and
- output values appropriately, but only illustrate using the
- recommended BT.1886 black point and viewing conditions adjustments,
- rather than illustrating CIECAM02 etc. use.<br>
- <br>
- For faster exploration of different collink option, you could omit
- the "colprof -bl" option, and use collink "-g" instead of "-G",
- since this<br>
- will greatly speed up collink. Once you are happy with the link
- details, you can then generate a higher quality link/3dLut using
- "collink -G ..".<br>
- <br>
- You can also increase the precision of the device profile by
- increasing the number of test patches measured (ie. up to a few
- thousand, depending on how long you are prepared to wait for the
- measurement to complete, and how stable your display and instrument
- are).<br>
- <br>
- Alternatives to relative colorimetric rendering ("-i r") or
- luminance matched appearance ("-i la") used in the examples above
- and below, are, perceptual ("-i p") which will ensure that the
- source gamut is compressed rather than clipped by the display, or
- even a saturation rendering ("-i ms"), which will expand the gamut
- of the source to the full range of the output.<br>
- <br>
- <br>
- <b>eeColor</b><br>
- <br>
- For PC use, where the encoding is full range RGB:<br>
- <br>
- &nbsp; <tt>collink -v -3e -Ib -b -G -ir -a TV.cal Rec709.icm TV.icm
- HD.icm </tt><br>
- <br>
- For correct operation both the 3DLut HD.txt and the per channel
- input curves HD-first1dred.txt, HD-first1dgreen.txt and
- HD-first1dblue.txt. the latter by copying them over the default
- input curve files uploaded by the TruVue application.<br>
- <br>
- See <a
- href="http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms">&lt;http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms&gt;</a>
- for some more details.<br>
- <br>
- Where the eeColor is connected from a Video source using HDMI, it
- will probably be processing TV RGB levels, or YCbCr encoded signals
- that it converts to/from RGB internally, so<br>
- <br>
- &nbsp; <tt>collink -v -3e -et -Et -Ib -b -G -ir -a TV.cal
- Rec709.icm TV.icm HD.icm </tt><br>
- <br>
- in this case just the HD.txt file needs installing on the eeColor,
- but make sure that the original linear "first1*.txt files are
- re-installed, or install the ones generated by collink, which will
- be linear for -e t mode.<br>
- <br>
- <b>MadVR</b><br>
- <br>
- MadVR 0.86.9 or latter has a number of features to support accurate
- profiling and calibration, and is the recommended version to
- use.&nbsp; It converts from the media colorspace to the 3dLut input
- space automatically with the type of source being played, but has
- configuration for to 5 3dLuts, each one optimized for a particular
- source color space. The advantage of building and installing several
- 3dLuts is that unnecessary gamut clipping can be avoided.<br>
- <br>
- If you are just building one 3dLut then Rec709 source is a good one
- to pick.<br>
- <br>
- If you want to share the VideoLUT calibration curves between your
- normal desktop and MadVR, then it is recommended that you install
- the display ICC profile and use the -H option:<br>
- <br>
- <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -H
- TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+ of where to apply display per channel calibration curves.</b></li>
+ <li>Choose one of the Absolute Colorimetric intents in collink
+ (ie. -i aw). This greatly reduces flexibility, and may not be
+ quite as accurate as an explicit calibration.</li>
+ </ul>
+ If an explicit calibration is used, then it is a good idea to add
+ some test points down the neutral axis when profiling (targen <a
+ href="targen.html#g">-g parameter</a>). <br>
+ <br>
+ <b>3) Choice of where to apply display per channel calibration
+ curves</b><br>
+ <br>
+ If calibration curves are going to be used, then it needs to be
+ decided where they will be applied in the video processing chain.
+ There are two options:<br>
+ <br>
+ <b>a)</b> Install the calibration curves in the playback system. On
+ a PC the display, this can be done by loading the calibration curves
+ into the Video Card temporarily using "dispwin calibration.cal", or
+ installing the ICC profile into the system persistently using
+ something like "<a href="dispwin.html#I">dispwin -I profile.icm</a>",<br>
+ or when using MadVR 0.86.9 or latter by creating a 3dLut with
+ appended calibration curves using <a href="collink#H">-H
+ display.cal</a>.<br>
+ <br>
+ <b>b)</b> The calibration can be incorporated into the Device
+ Link/3dLUT by providing it to collink as the <a
+ href="collink.html#a">-a display.cal</a>. This is the only option
+ if the video display path does not have some separate facility to
+ handle calibration curves. Note that if the playback system has
+ graphic card VideoLUTs then they will have to be set to a defined
+ consistent state such as linear. When using MadVR 0.86.9 or latter
+ this will be done automatically since the -a option will append a
+ linear set of calibration curves to the 3dLut.<br>
+ <br>
+ The choice is dictated by a number of considerations:<br>
+ <ul>
+ <li>Does the video playback path have a facility for installing
+ the calibration curves ? If playing back system is a PC, then
+ typically the Graphics Card supports 1D VideoLUTs, thereby
+ making a) a possible choice.<br>
+ </li>
+ <li>Does the video playback <u>always</u> play back through the
+ Video Card VideoLUTs ? Some systems do not apply VIdeoLUTs to
+ things like overlay plane rendering. If not, then you need to
+ choose b), but also make sure that if it does use the Video Card
+ VideoLUTs in some situations, that they are set to linear (ie.
+ dispcal -c). One way of determining when the VideoLUTs get used
+ or not is to load a distinct calibration such as "strange.cal"
+ provided in the <b>ref</b> folder, and check visually if it is
+ affecting the video or not, ie. "dispcal strange.cal". Note that
+ using MadVR 0.86.9 or latter in combination with a 3dLut with
+ appended calibration curves will apply the calibration even with
+ overlay plane rendering.<br>
+ </li>
+ <li>Do you want/need other applications to share the calibration
+ curves or profile or not ? If you do, then it is desirable to
+ choose a).</li>
+ <li>Quality considerations. VideoLUTs may or may not be of greater
+ depth than the standard 8 bit per color component frame buffer.
+ If they are, and the video path passes that extra depth through
+ to the display, and the display is capable of using that extra
+ depth, then a) may be a desirable choice from a quality point of
+ view. You can get some idea whether this is the case by running
+ "dispcal -R". If the VideoLUT depth is not better than 8 bits,
+ then it may be more desirable to choose b), since renders like
+ MadVR can use dithering to give better than 8 bits precision in
+ the video playback.<br>
+ </li>
+ </ul>
+ <h5>4) Output device calibration and profiling.</h5>
+ Output device profiling should basically follow the guide above in <a
+ href="#PM1b">Adjusting and Calibrating a displays</a> and <a
+ href="#PM1">Profiling Displays</a>. The assumption is that either
+ you are calibrating/profiling your computer display for video, or
+ your TV is connected to the computer you are creating
+ calibrations/profiles on, and that the connection between the PC and
+ TV display is such that full range RGB signals are being used, or
+ that the Video card has automatically or manually been configured to
+ scale full range RGB values to Video levels for the TV. If the
+ latter is not possible, then use the -E options on dispcal and
+ dispread. (See <b>Signal encoding</b> bellow for more details on
+ this). It may also improve the accuracy of the display profile if
+ you use the <a href="dispread.html#Z">dispread -Z</a> option to
+ quantize the test values to the precision of the display
+ system.&nbsp; Don't use the -E options on dispcal and dispread, nor
+ the -Z option on dispread if you are using MadVR to display test
+ patches using the "-d madvr" option.<br>
+ <br>
+ Once the profile has been created, it is possible to then use the
+ resulting Device Link/3DLut with signal encoding other than full
+ range or Video level RGB. <br>
+ <h5>5) Target colorspace<br>
+ </h5>
+ In practical terms, there are five common Video and Digital Cinema
+ encoding colorspaces. <br>
+ <br>
+ For Standard Definition:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; EBU 3213 or "PAL 576i" primaries.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE RP 145 or "NTSC 480i" primaries.<br>
+ <br>
+ For High Definition:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec 709 primaries.<br>
+ <br>
+ For Ultra High Defintion<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec 2020 primaries.<br>
+ <br>
+ For Digital Cinema<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE-431-2&nbsp; or "DCI-P3"<br>
+ <br>
+ PAL and NTSC have historically had poorly specified transfer curve
+ encodings, and the Rec 709 HDTV encoding curve is the modern <a
+ href="http://www.poynton.com/notes/DVAI/DVAI_TOC_full.html#23">recommendation</a>,
+ but the overall interpretation of Video sources may in fact be
+ partly determined by the expected standard Video display device
+ characteristics (see <b>Viewing conditions adjustment and gamut
+ mapping</b> below for more details).<br>
+ <br>
+ To enable targeting these colorspaces, ArgyllCMS provides 5 ICC
+ profiles in the ref directory to use as source
+ colorspaces:&nbsp;&nbsp;&nbsp; <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; EBU3213_PAL.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE_RP145_NTSC.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec709.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Rec2020.icm<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; SMPTE431_P3.icm<br>
+ <h5>6) Signal encoding</h5>
+ Typical PC display output uses full range RGB signals (0 .. 255 in 8
+ bit parlance), while typical Video encoding allows some head &amp;
+ footroom for overshoot and sync of digitized analog signals, and
+ typically uses a 16..235 range in 8 bits. In many cases Video is
+ encoded as luma and color difference signals YCbCr (loosely known as
+ YUV as well), and this also uses a restricted range 16..235 for Y,
+ and 16..240 for Cb and Cr in 8 bit encoding. The extended gamut
+ xvYCC encoding uses 16..235 for Y, and 1..254 for Cb and Cr.<br>
+ <br>
+ The signal encoding comes into play in two situations: 1)
+ Calibrating and profiling the display, and 2) Using the resulting
+ Device Link/3DLut.<br>
+ The encoding may need to be different in these two situations,
+ either because different video source devices are being used for
+ calibration/profiling and for video playback, or because the video
+ playback system uses the Device Link/3DLut at a point in its
+ processing pipeline that requires a specific encoding.<br>
+ <br>
+ For calibration &amp; profiling, the display will be driven by a
+ computer system so that dispcal and dispread can be used. By default
+ these programs expect to output full range RGB signals, and it is
+ assumed that either the display accepts full range signals, or that
+ the graphics card or connection path has been setup to convert the
+ full range values into Video range signals automatically or
+ manually. If this is not the case, then both dispcal and dispread
+ have a -E option that will modify them to output Video range RGB
+ values.<br>
+ <br>
+ If MadVR is the target of the calibration and profiling, then there
+ is an option to use it to display the calibration and profiling test
+ patches (<b>-d madvr</b>). In this case, MadVR should be configured
+ appropriately for full range or Video range encoding, and the -E
+ flag should <u>not</u> be used with dispcal or dispread, since
+ MadVR will be taking care of such conversions.<br>
+ <br>
+ If a calibration file was created using dispcal -E, then using it in
+ dispread will automatically trigger Video level RGB signals during
+ profiling. Any time such a Video level calibration is loaded into
+ the Graphics card VideoLUTs using dispwin, or the calibration curve
+ is converted to a 'vcgt' tag in a profile, the curve will also
+ convert full range RGB to Video range RGB. This should be kept in
+ mind so that if video playback is being performed with the
+ calibration curves installed in the Graphics card VideoLUTs, that
+ full range is converted only once to Video range (ie. In this
+ situation MadVR output should be set to full range if being played
+ back through the calibration curves in hardware, but only if dispcal
+ -E has been used). On the other hand, if the calibration curves are
+ incorporated into the DeviceLink/3dLUT, then the conversion to Video
+ levels has to be done somewhere else in the pipeline, such as using
+ MadVR video level output, or by the graphics card, etc.<br>
+ <br>
+ When creating the Device Link/3dLut, it is often necessary to
+ specify one of the video encodings so that it fits in to the
+ processing pipeline correctly. For instance the eeColor needs to
+ have input and output encoding that suits the HDMI signals passing
+ through it, typically Video Range RGB. MadVR needs Video Level RGB
+ to match the values being passed through the 3dLut at that point.<br>
+ <br>
+ There are several version of YCbCr encoding supported as well, even
+ though neither the eeColor nor the current version of MadVR need or
+ can use them at present.<br>
+ <h5>7) Black point mapping</h5>
+ <p>Video encoding assumes that the black displayed on a device is a
+ perfect black (zero light). No real device has a perfect black,
+ and if a colorimetric intent is used then certain image values
+ near black will get clipped to the display black point, loosing
+ shadow detail. To avoid this, some sort of black point mapping is
+ usually desirable. There are two mechanisms available in collink:
+ a) Custom EOTF with input and/or output black point mapping, or b)
+ using one of the smart gamut mapping intents that does black point
+ mapping (e.g. la, p, pa, ms or s).<br>
+ </p>
+ <h5>8) Viewing conditions adjustment and gamut mapping</h5>
+ <p> </p>
+ <p>In historical TV systems, there is a viewing conditions
+ adjustment being made between the bright studio conditions that TV
+ is filmed in, and the typical dim viewing environment that people
+ view it in. This is created by the difference between the encoding
+ response curve gamma of about 2.0, and a typical CRT response
+ curve gamma of 2.4. <br>
+ </p>
+ <p>In theory Rec709 defines the video encoding, but it seems in
+ practice that much video material is adjusted to look as intended
+ when displayed on a reference monitor having a display gamma of
+ somewhere between 2.2 and 2.4, viewed in a dim viewing
+ environment. The modern standard covering the display EOTF
+ (Electro-Optical Transfer Curve) is <a
+ href="http://www.itu.int/rec/R-REC-BT.1886-0-201103-I">BT.1886</a>,
+ which defines a pure power 2.4 curve with an input offset and
+ scale applied to account for the black point offset while
+ retaining dark shadow tonality. So another means of making the
+ viewing adjustment is to use the BT.1886-like EOTF for Rec709
+ encoded material. Collink supports this using the <a
+ href="collink.html#I">-I b</a>, and allows some control over the
+ degree of viewing conditions adjustment by overriding the BT.1886
+ gamma&nbsp; using the <a href="collink.html#Ib">-I b:g.g</a>
+ parameter. This is the <b>recommended</b> approach to start with,
+ since it gives good results with a single parameter.<br>
+ </p>
+ <p>The addition of a second optional parameter <a
+ href="file:///D:/src/argyll/doc/collink.html#Ib">-I b:p.p:g.g</a>
+ allows control over the degree of black point offset accounted for
+ as an output offset, as opposed to input offset Once the effective
+ gamma value has been chosen to suite the viewing conditions and
+ set the overall contrast for mid greys, increasing the proportion
+ of black offset accounted for in the output of the curve is a way
+ of reducing the deep shadow detail, if it is being overly
+ emphasized. </p>
+ <p> An alternate approach to making this adjustment is to take
+ advantage of the viewing conditions adjustment using the CIECAM02
+ model available in collink. Some control over the degree of
+ viewing conditions adjustment is possible by varying the viewing
+ condition parameters. </p>
+ <p>A third alternative is to combine the two approaches. The source
+ is defined as Rec709 primaries with a BT.1886-like EOTF display in
+ dim viewing conditions, and then CIECAM02 is used to adjust for
+ the actual display viewing conditions. Once again, control over
+ the degree of viewing conditions adjustment is possible by varying
+ the viewing condition parameters<br>
+ </p>
+ <p><br>
+ </p>
+ <p><b>9) Correcting for any black point inaccuracy in the display
+ profile</b><br>
+ </p>
+ <p>Some video display devices have particularly good black points,
+ and any slight raising of the black due to innacuracies in the
+ display profile near black can be objectionable. As well as using
+ the <a href="targen.html#V">targen -V flag</a> to improve
+ accuracy near black during profiling, if the display is known to
+ be well behaved (ie. that it's darkest black is actually at RGB
+ value 0,0,0), then the <a href="collink.html#b">collink -b</a>
+ flag can be used, to force the source RGB 0,0,0 to map to the
+ display 0,0,0.<br>
+ </p>
+ <h5>Putting it all together:</h5>
+ In this example we choose to create a display calibration first
+ using dispcal, and create a simple matrix profile as well:<br>
+ <br>
+ &nbsp; <tt>dispcal -v -o -qm -k0 -w 0.3127,0.3290 -gs -o TVmtx.icm
+ TV</tt><br>
+ <br>
+ We are targeting a D65 white point (<tt>-w 0.3127,0.3290)</tt> and
+ an sRGB response curve.<br>
+ <br>
+ If you are using the madTPG you would use:<br>
+ <br>
+ &nbsp; <tt>dispcal -v -d madvr -o -qm -k0 -w 0.3127,0.3290 -gs -o
+ TVmtx.icm TV</tt><br>
+ <br>
+ Then we need to create a display patch test set. We can use the
+ simple matrix to pre-condition the test patches, as this helps
+ distribute them where they will be of most benefit. If have
+ previously profiled your display, you should use that previous
+ profile, or if you decided not to do a dispcal, then the Rec709.icm
+ should be used as a substitute. Some per channel and a moderate
+ number of full spread patches is used here - more will increase
+ profiling accuracy, a smaller number will speed it up. Since the
+ video or film material is typically viewed in a darkened viewing
+ environment, and often uses a range of maximum brightnesses in
+ different scenes, the device behavior in the dark regions of its
+ response are often of great importance, and using the <a
+ href="targen.html#V">targen -V</a> parameter can help improve the
+ accuracy in this region at the expense of slightly lower accuracy in
+ lighter regions.<br>
+ <br>
+ &nbsp; <tt>targen -v -d3 -s30 -g100 -f1000 -cTVmtx.icm -V1.8 TV</tt><br>
+ <br>
+ The display can then be measured:<br>
+ <br>
+ &nbsp; <tt>dispread -v -k -Z8 TV.cal TV</tt><br>
+ <br>
+ or using madTPG:<br>
+ <br>
+ &nbsp;dispread -v -d madvr -K TV.cal TV<br>
+ <br>
+ and then a cLUT type ICC profile created. Since we will be using
+ collink smart linking, we minimize the B2A table size. We use the
+ default colprof -V parameter carried through from targen:<br>
+ <br>
+ &nbsp; <tt>colprof -v -qh -bl TV</tt><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the sample data and profile is behaving
+ reasonably. Depending on the type of device, and the consistency of
+ the readings, average errors of 5 or less, and maximum errors of 15
+ or less would normally be expected. If errors are grossly higher
+ than this, then this is an indication that something is seriously
+ wrong with the device measurement, or profile creation.<br>
+ <br>
+ If you would like to use the display ICC profile for general color
+ managed applications, then you would compute a more complete
+ profile:<br>
+ <br>
+ &nbsp; <tt>colprof -v -qh TV</tt><br>
+ <br>
+ The recommended approach then is to create a Device Link that uses a
+ BT.1886 black point and viewing conditions adjustment, say one of
+ the following:<br>
+ <br>
+ <tt>&nbsp; collink -v -Ib:2.4 -b -G -ir Rec709.icm TV.icm
+ HD.icm&nbsp;&nbsp; # dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib&nbsp;&nbsp;&nbsp;&nbsp; -b -G -ir
+ Rec709.icm TV.icm HD.icm&nbsp;&nbsp; # dim conditions - good
+ default</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib:2.1 -b -G -ir Rec709.icm TV.icm
+ HD.icm&nbsp;&nbsp; # mid to dim conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib:2.0 -b -G -ir Rec709.icm TV.icm
+ HD.icm&nbsp;&nbsp; # mid to light conditions</tt><br>
+ <br>
+ or you could do it using pure CIECAM02 adjustment and a black point
+ mapping:<br>
+ <br>
+ <tt>&nbsp; collink -v -ctv -dmd -da:1 -G -ila Rec709.icm TV.icm
+ HD.icm&nbsp; # very dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -ctv -dmd -da:3 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -ctv -dmd -da:7 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # mid to dim conditions - good default</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -ctv -dmd -da:15 -G -ila Rec709.icm
+ TV.icm HD.icm # mid conditions</tt><br>
+ <br>
+ or using both to model a reference video display system that is
+ adapted to your viewing conditions:<br>
+ <tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:5&nbsp; -G -ila
+ Rec709.icm TV.icm HD.icm # very dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:10 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # dim conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:18 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp; # mid to dark conditions</tt><tt><br>
+ </tt><tt> &nbsp; collink -v -Ib -c md -dmd -da:30 -G -ila Rec709.icm
+ TV.icm HD.icm&nbsp;&nbsp; # mid to dark conditions</tt><br>
+ <br>
+ None of the above examples incorporate the calibration curves, so it
+ is assumed that the calibration curves would be installed so that
+ the Video Card applies calibration, ie:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <tt>dispwin TV.cal</tt><br>
+ <br>
+ or the simple matrix profile installed:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <tt>dispwin -I TVmtx.icm</tt><br>
+ <br>
+ or a the more complete display profile could be installed:<br>
+ <br>
+ &nbsp; dispwin -I TV.icm<br>
+ <br>
+ See also <a href="dispprofloc.html">here</a> for information on how
+ to make sure the calibration is loaded on each system start. If not,
+ then you will want to incorporate the calibration in the Device
+ Link/3dlut by using collink "-a TV.cal".<br>
+ <br>
+ If the video path needs Video Level RGB encoding but does not
+ provide a means to do this, then you will want to include the <b>-E</b>
+ flag in the dispcal and dispread command lines above.<br>
+ <br>
+ Below are specific recommendation for the eeColor and MadVR that
+ include the flags to create the .3dlut and encode the input and
+ output values appropriately, but only illustrate using the
+ recommended BT.1886 black point and viewing conditions adjustments,
+ rather than illustrating CIECAM02 etc. use.<br>
+ <br>
+ For faster exploration of different collink option, you could omit
+ the "colprof -bl" option, and use collink "-g" instead of "-G",
+ since this<br>
+ will greatly speed up collink. Once you are happy with the link
+ details, you can then generate a higher quality link/3dLut using
+ "collink -G ..".<br>
+ <br>
+ You can also increase the precision of the device profile by
+ increasing the number of test patches measured (ie. up to a few
+ thousand, depending on how long you are prepared to wait for the
+ measurement to complete, and how stable your display and instrument
+ are).<br>
+ <br>
+ Alternatives to relative colorimetric rendering ("-i r") or
+ luminance matched appearance ("-i la") used in the examples above
+ and below, are, perceptual ("-i p") which will ensure that the
+ source gamut is compressed rather than clipped by the display, or
+ even a saturation rendering ("-i ms"), which will expand the gamut
+ of the source to the full range of the output.<br>
+ <br>
+ <br>
+ <b>eeColor</b><br>
+ <br>
+ For PC use, where the encoding is full range RGB:<br>
+ <br>
+ &nbsp; <tt>collink -v -3e -Ib -b -G -ir -a TV.cal Rec709.icm TV.icm
+ HD.icm </tt><br>
+ <br>
+ For correct operation both the 3DLut HD.txt and the per channel
+ input curves HD-first1dred.txt, HD-first1dgreen.txt and
+ HD-first1dblue.txt. the latter by copying them over the default
+ input curve files uploaded by the TruVue application.<br>
+ <br>
+ See <a
+ href="http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms">&lt;http://www.avsforum.com/t/1464890/eecolor-processor-argyllcms&gt;</a>
+ for some more details.<br>
+ <br>
+ Where the eeColor is connected from a Video source using HDMI, it
+ will probably be processing TV RGB levels, or YCbCr encoded signals
+ that it converts to/from RGB internally, so<br>
+ <br>
+ &nbsp; <tt>collink -v -3e -et -Et -Ib -b -G -ir -a TV.cal
+ Rec709.icm TV.icm HD.icm </tt><br>
+ <br>
+ in this case just the HD.txt file needs installing on the eeColor,
+ but make sure that the original linear "first1*.txt files are
+ re-installed, or install the ones generated by collink, which will
+ be linear for -e t mode.<br>
+ <br>
+ <b>MadVR</b><br>
+ <br>
+ MadVR 0.86.9 or latter has a number of features to support accurate
+ profiling and calibration, and is the recommended version to
+ use.&nbsp; It converts from the media colorspace to the 3dLut input
+ space automatically with the type of source being played, but has
+ configuration for to 5 3dLuts, each one optimized for a particular
+ source color space. The advantage of building and installing several
+ 3dLuts is that unnecessary gamut clipping can be avoided.<br>
+ <br>
+ If you are just building one 3dLut then Rec709 source is a good one
+ to pick.<br>
+ <br>
+ If you want to share the VideoLUT calibration curves between your
+ normal desktop and MadVR, then it is recommended that you install
+ the display ICC profile and use the -H option:<br>
+ <br>
+ <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -H
+ TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-H
@@ -3805,11 +3742,9 @@ a
-
-
-
- TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+ TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-H
@@ -3833,18 +3768,16 @@ a
-
-
-
- TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
- <br>
- For best quality it is better to let MadVR apply the calibration
- curves using dithering, and allow it to set the graphics card to
- linear by using the -a option:<br>
- <br>
- <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -a
- TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+ TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
+ <br>
+ For best quality it is better to let MadVR apply the calibration
+ curves using dithering, and allow it to set the graphics card to
+ linear by using the -a option:<br>
+ <br>
+ <tt>&nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir -a
+ TV.cal Rec709.icm TV.icm HD.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-a
@@ -3868,11 +3801,9 @@ a
-
-
-
- TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
- </tt><tt> </tt><tt><br>
+
+ TV.cal </tt>EBU3213_PAL.icm TV.icm SD_PAL.icm</tt><tt><br>
+ </tt><tt> </tt><tt><br>
</tt><tt> &nbsp;&nbsp;&nbsp; collink -v -3m -et -Et -Ib -b -G -ir </tt><tt><tt>-a
@@ -3896,184 +3827,182 @@ a
-
-
-
- TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
- <br>
- the consequence though is that the appearance of other application
- will shift when MadVR is using the 3dLut and loading the calibration
- curves.<br>
- <br>
- The 3dLut can be used by opening the MadVR settings dialog,
- selecting "calibration" and then selecting "calibrate this display
- by using an external 3DLUT file", and then using the file dialog to
- use it.<br>
- <br>
- If neither the -a no -H options are used, then no calibration curves
- will be appended to the 3dLut, and MadVR will not change the
- VideoLUTs when that 3dLut is in use. It is then up to you to manage
- the graphics card VideoLUTs in some other fashion.<tt><br>
- <br>
- </tt>
- <hr size="2" width="100%"><br>
- <h3><a name="TV2"></a>Verifying Video Calibration</h3>
- <p>Often it is desirable to verify the results of a video
- calibration and profile, and the following gives an outline of how
- to use ArgyllCMS tools to do this. It is only possible to expect
- perfect verification if a colorimetric intent was used during
- linking - currently it's not possible to exactly verify a
- perceptual or CIECAM02 viewing condition adjusted link.<br>
- <br>
- </p>
- <p>The first step is to create a set of test points. This is
- essentially the same as creating a set of test points for the
- purposes of profiling, although it is best not to create exactly
- the same set, so as to explore the colorspace at different
- locatioins. For the purposes here, we'll actually create a regular
- grid test set, since this makes it easier to visualize the
- results, although a less regular set would probably be better for
- numerical evaluation:<br>
- </p>
- <p>&nbsp; targen -v -d3 -e1 -m6 -f0 -W verify<br>
- </p>
- <p>We make sure there is at least one white patch usin g -e1, a 20%
- increment grid using -m6, no full spread patches, and create an
- X3DOM 3d visualization of the point set using the -W flag. It is
- good to take a look at the verifyd.x3d.html file using a Web
- browser. You may want to create several test sets that look at
- particular aspects, ie. neutral axis response, pure colorant
- responses, etc.<br>
- </p>
- <p>Next we create a reference file by simulating the expected
- response of the perfect video display system. Assuming the collink
- options were "-et -Et -Ib -G -ir Rec709.icm TV.icm HD.icm" then we
- would:<tt><tt><br>
- </tt></tt></p>
- <p><tt><tt>&nbsp; copy verify.ti1 ref.ti1<br>
- &nbsp; fakeread -v -b -Z8 TV.icm Rec709.icm ref<br>
- </tt></tt></p>
- <p>You should adjust the parameters as necessary, so that the
- reference matches the link options. For instance, if your link
- options included "-I b:0.2:2.15" then the equivalent fakeread
- option "-b 0.2:2.15:TV.icm" should be used, etc.<br>
- </p>
- <hr size="2" width="20%">
- <p>A sanity check we can make at this point is to see what the
- expected result of the profiling &amp; calibration will be, by
- simulating the reproduction of this test set:<br>
- </p>
- <p><tt>&nbsp; copy verify.ti1 checkA.ti1</tt><tt><br>
- &nbsp; fakeread -v -et -Z8 -p HD.icm -Et TV.icm checkA<br>
- </tt></p>
- <p>If you used collink -a, then the calibration incorporated in the
- device link needs to be undone to match what the display profile
- expects:</p>
- <p><tt>&nbsp; fakeread -v -et -Z8 -p HD.icm -Et -K TV.cal TV.icm
- checkA</tt></p>
- <p><tt>and then you can verify:<br>
- </tt></p>
- <p><tt>&nbsp; colverify -v -n -w -x ref.ti3 checkA.ti3<br>
- </tt></p>
- <p>If you have targeted some other white point rather than video D65
- for the display, then use the -N flag instead of -n to align the
- white points. [ Note that there can be some small discrepancies in
- this case in some parts of the color space if a CIECAM02 linking
- intent was used, due to the slightly different chromatic
- adaptation algorithm it uses compared to the one used by verify to
- match the white points.]<tt><br>
- </tt></p>
- <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x ref.ti3 checkA.ti3</tt><br>
- </p>
- <p>This will give a numerical report of the delta E's, and also
- generate an X3DOM plot of the errors in L*a*b* space. The
- important thing is to take a look at the checkA.x3d.html file, to
- see if gamut clipping is occurring - this is the case if the large
- error vectors are on the sides or top of the gamut. Note that the
- perfect cube device space values become a rather distorted cube
- like shape in the perceptual L*a*b* space. If the vectors are
- small in the bulk of the space, then this indicates that the link
- is likely to be doing the right thing in making the display
- emulate the video colorspace with a BT.1886 like black point
- adjustment. You could also check just the in gamut test points
- using:<br>
- </p>
- <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x -L TV.icm ref.ti3
- checkA.ti3<br>
- <br>
- </tt></p>
- <hr size="2" width="20%">
- <p>You can explicitly compare the gamuts of your video space and
- your display using the gamut tools:<br>
- </p>
- <p><tt>&nbsp; iccgamut -ff -ia Rec709</tt><tt><br>
- </tt><tt> &nbsp; iccgamut -ff -ia TV.icm</tt><tt><br>
- </tt><tt> &nbsp; viewgam -i Rec709.gam TV.gam gamuts</tt><br>
- </p>
- <p>and look at the gamuts.x3d.html file, as well as taking notice of
- % of the video volume that the display intersects. The X3DOM solid
- volume will be the video gamut, while the wire frame is the
- display gamut. If you are not targetting D65 with your display,
- you should use iccgamut <b>-ir</b> instead of <b>-ia</b>, so as
- to align the white points.<br>
- </p>
- <hr size="2" width="20%">
- <p>The main verification check is to actually measure the display
- response and compare it against the reference. Make sure the
- display is setup as you would for video playback and then use
- dispread:<br>
- </p>
- <p><tt>&nbsp; copy verify.ti1 checkB.ti1</tt><tt><br>
- </tt><tt> &nbsp; dispread -v -Z8 checkB</tt><br>
- </p>
- <p>You would add any other options needed (such as <b>-y</b> etc.)
- to set your instrument up properly. If you are using madTPG, then
- configure madVR to use the 3dLut you want to measure as the
- default, and also use the dispread -V flag to make sure that the
- 3dLut is being used for the measurements: [<b>Note</b> that if the
- version of MadVR you are using does not have radio buttons in its
- calibration setup to indicate a default 3dLut, then the 3dLut
- under test should be the only one set - all others should be
- blank. ]<br>
- </p>
- <p><tt>&nbsp; dispread -v -d madvr -V checkB</tt><br>
- </p>
- <p>Verify the same way as above:<br>
- </p>
- <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x ref.ti3 checkB.ti3<br>
- </tt></p>
- <p>If your display does not cover the full gamut of your video
- source, the errors are probably dominated by out of gamut colors.
- You can verify just the in gamut test values by asking verify to
- skip them, and this will give a better notion of the actual device
- link and calibration accuracy:<tt><br>
- </tt></p>
- <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x -L TV.icm ref.ti3
- checkB.ti3</tt></p>
- <p><br>
- </p>
- <p>&nbsp;<br>
- </p>
- <p><br>
- <br>
- </p>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ TV.cal </tt>SMPTE_RP145_NTSC.icm TV.icm SD_NTSC.icm</tt><br>
+ <br>
+ the consequence though is that the appearance of other application
+ will shift when MadVR is using the 3dLut and loading the calibration
+ curves.<br>
+ <br>
+ The 3dLut can be used by opening the MadVR settings dialog,
+ selecting "calibration" and then selecting "calibrate this display
+ by using an external 3DLUT file", and then using the file dialog to
+ use it.<br>
+ <br>
+ If neither the -a no -H options are used, then no calibration curves
+ will be appended to the 3dLut, and MadVR will not change the
+ VideoLUTs when that 3dLut is in use. It is then up to you to manage
+ the graphics card VideoLUTs in some other fashion.<tt><br>
+ <br>
+ </tt>
+ <hr size="2" width="100%"><br>
+ <h3><a name="TV2"></a>Verifying Video Calibration</h3>
+ <p>Often it is desirable to verify the results of a video
+ calibration and profile, and the following gives an outline of how
+ to use ArgyllCMS tools to do this. It is only possible to expect
+ perfect verification if a colorimetric intent was used during
+ linking - currently it's not possible to exactly verify a
+ perceptual or CIECAM02 viewing condition adjusted link.<br>
+ <br>
+ </p>
+ <p>The first step is to create a set of test points. This is
+ essentially the same as creating a set of test points for the
+ purposes of profiling, although it is best not to create exactly
+ the same set, so as to explore the colorspace at different
+ locatioins. For the purposes here, we'll actually create a regular
+ grid test set, since this makes it easier to visualize the
+ results, although a less regular set would probably be better for
+ numerical evaluation:<br>
+ </p>
+ <p>&nbsp; targen -v -d3 -e1 -m6 -f0 -W verify<br>
+ </p>
+ <p>We make sure there is at least one white patch usin g -e1, a 20%
+ increment grid using -m6, no full spread patches, and create an
+ X3DOM 3d visualization of the point set using the -W flag. It is
+ good to take a look at the verifyd.x3d.html file using a Web
+ browser. You may want to create several test sets that look at
+ particular aspects, ie. neutral axis response, pure colorant
+ responses, etc.<br>
+ </p>
+ <p>Next we create a reference file by simulating the expected
+ response of the perfect video display system. Assuming the collink
+ options were "-et -Et -Ib -G -ir Rec709.icm TV.icm HD.icm" then we
+ would:<tt><tt><br>
+ </tt></tt></p>
+ <p><tt><tt>&nbsp; copy verify.ti1 ref.ti1<br>
+ &nbsp; fakeread -v -b -Z8 TV.icm Rec709.icm ref<br>
+ </tt></tt></p>
+ <p>You should adjust the parameters as necessary, so that the
+ reference matches the link options. For instance, if your link
+ options included "-I b:0.2:2.15" then the equivalent fakeread
+ option "-b 0.2:2.15:TV.icm" should be used, etc.<br>
+ </p>
+ <hr size="2" width="20%">
+ <p>A sanity check we can make at this point is to see what the
+ expected result of the profiling &amp; calibration will be, by
+ simulating the reproduction of this test set:<br>
+ </p>
+ <p><tt>&nbsp; copy verify.ti1 checkA.ti1</tt><tt><br>
+ &nbsp; fakeread -v -et -Z8 -p HD.icm -Et TV.icm checkA<br>
+ </tt></p>
+ <p>If you used collink -a, then the calibration incorporated in the
+ device link needs to be undone to match what the display profile
+ expects:</p>
+ <p><tt>&nbsp; fakeread -v -et -Z8 -p HD.icm -Et -K TV.cal TV.icm
+ checkA</tt></p>
+ <p><tt>and then you can verify:<br>
+ </tt></p>
+ <p><tt>&nbsp; colverify -v -n -w -x ref.ti3 checkA.ti3<br>
+ </tt></p>
+ <p>If you have targeted some other white point rather than video D65
+ for the display, then use the -N flag instead of -n to align the
+ white points. [ Note that there can be some small discrepancies in
+ this case in some parts of the color space if a CIECAM02 linking
+ intent was used, due to the slightly different chromatic
+ adaptation algorithm it uses compared to the one used by verify to
+ match the white points.]<tt><br>
+ </tt></p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x ref.ti3 checkA.ti3</tt><br>
+ </p>
+ <p>This will give a numerical report of the delta E's, and also
+ generate an X3DOM plot of the errors in L*a*b* space. The
+ important thing is to take a look at the checkA.x3d.html file, to
+ see if gamut clipping is occurring - this is the case if the large
+ error vectors are on the sides or top of the gamut. Note that the
+ perfect cube device space values become a rather distorted cube
+ like shape in the perceptual L*a*b* space. If the vectors are
+ small in the bulk of the space, then this indicates that the link
+ is likely to be doing the right thing in making the display
+ emulate the video colorspace with a BT.1886 like black point
+ adjustment. You could also check just the in gamut test points
+ using:<br>
+ </p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -N -w -x -L TV.icm ref.ti3
+ checkA.ti3<br>
+ <br>
+ </tt></p>
+ <hr size="2" width="20%">
+ <p>You can explicitly compare the gamuts of your video space and
+ your display using the gamut tools:<br>
+ </p>
+ <p><tt>&nbsp; iccgamut -ff -ia Rec709</tt><tt><br>
+ </tt><tt> &nbsp; iccgamut -ff -ia TV.icm</tt><tt><br>
+ </tt><tt> &nbsp; viewgam -i Rec709.gam TV.gam gamuts</tt><br>
+ </p>
+ <p>and look at the gamuts.x3d.html file, as well as taking notice of
+ % of the video volume that the display intersects. The X3DOM solid
+ volume will be the video gamut, while the wire frame is the
+ display gamut. If you are not targetting D65 with your display,
+ you should use iccgamut <b>-ir</b> instead of <b>-ia</b>, so as
+ to align the white points.<br>
+ </p>
+ <hr size="2" width="20%">
+ <p>The main verification check is to actually measure the display
+ response and compare it against the reference. Make sure the
+ display is setup as you would for video playback and then use
+ dispread:<br>
+ </p>
+ <p><tt>&nbsp; copy verify.ti1 checkB.ti1</tt><tt><br>
+ </tt><tt> &nbsp; dispread -v -Z8 checkB</tt><br>
+ </p>
+ <p>You would add any other options needed (such as <b>-y</b> etc.)
+ to set your instrument up properly. If you are using madTPG, then
+ configure madVR to use the 3dLut you want to measure as the
+ default, and also use the dispread -V flag to make sure that the
+ 3dLut is being used for the measurements: [<b>Note</b> that if the
+ version of MadVR you are using does not have radio buttons in its
+ calibration setup to indicate a default 3dLut, then the 3dLut
+ under test should be the only one set - all others should be
+ blank. ]<br>
+ </p>
+ <p><tt>&nbsp; dispread -v -d madvr -V checkB</tt><br>
+ </p>
+ <p>Verify the same way as above:<br>
+ </p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x ref.ti3 checkB.ti3<br>
+ </tt></p>
+ <p>If your display does not cover the full gamut of your video
+ source, the errors are probably dominated by out of gamut colors.
+ You can verify just the in gamut test values by asking verify to
+ skip them, and this will give a better notion of the actual device
+ link and calibration accuracy:<tt><br>
+ </tt></p>
+ <p><tt>&nbsp; v</tt><tt>erify -v -n -w -x -L TV.icm ref.ti3
+ checkB.ti3</tt></p>
+ <p><br>
+ </p>
+ <p>&nbsp;<br>
+ </p>
+ <p><br>
+ <br>
+ </p>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/SpyderChecker24.jpg b/doc/SpyderChecker24.jpg
deleted file mode 100644
index 022eb11..0000000
--- a/doc/SpyderChecker24.jpg
+++ /dev/null
Binary files differ
diff --git a/doc/afiles b/doc/afiles
index a73a8ba..88f7406 100644
--- a/doc/afiles
+++ b/doc/afiles
@@ -146,7 +146,6 @@ CMP_DT_003.jpg
CMP_Digital_Target-4.jpg
colorchecker.jpg
SpyderChecker.jpg
-SpyderChecker24.jpg
LSDC.jpg
QPcard201.jpg
QPcard202.jpg
diff --git a/doc/chartread.html b/doc/chartread.html
index e9dddaf..4d5b005 100644
--- a/doc/chartread.html
+++ b/doc/chartread.html
@@ -27,7 +27,6 @@ Verbose
-
mode</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#c">-c listno</a><span
@@ -43,7 +42,6 @@ transmission
-
measurement mode<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#d">-d</a><span
@@ -55,7 +53,6 @@ measurement
-
mode (white Y relative results)</span></small><small><span
style="font-family: monospace;"></span></small><small><span
style="font-family: monospace;"><br>
@@ -65,7 +62,6 @@ measurement
-
Display type - instrument specific list to choose from.</span></font><br>
<small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#e">-e</a><span
@@ -76,7 +72,6 @@ measurement
-
mode (absolute results)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#p">-p</a><span
@@ -88,14 +83,13 @@ by
-
patch rather than strip</span></small><br>
<small><span style="font-family: monospace;"></span>&nbsp; <a
style="font-family: monospace;" href="#x">-x [lx]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Take
-
- manually entered values, either L*a*b* (-xl) or XYZ (-xx).</span><br
+ manually entered
+ values, either L*a*b* (-xl) or XYZ (-xx).</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#n">-n</a><span
@@ -106,7 +100,6 @@ Don't
-
save spectral information (default saves spectral)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#l">-l</a><span
@@ -125,7 +118,6 @@ partly
-
read chart<br>
&nbsp;<a href="#I">-I</a>
file.cal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Override
@@ -135,35 +127,30 @@ partly
-
Set filter configuration:<br>
&nbsp;
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
None<br>
&nbsp;
p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
Polarising filter<br>
&nbsp;
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
D65<br>
&nbsp;
u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
U.V. Cut</span></font><small><span style="font-family:
monospace;"></span><span style="font-family: monospace;"></span></small><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
@@ -189,7 +176,6 @@ partly
-
Apply Colorimeter Correction Matrix</span></font><br>
<span style="font-family: monospace;">&nbsp;<a href="#X2">-X
file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -202,7 +188,6 @@ Samples
-
for calibration</span><br>
<small><span style="font-family: monospace;">&nbsp;</span><a style="
font-family: monospace;" href="#Q">-Q observ</a><span
@@ -215,7 +200,6 @@ Samples
-
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span></small><small><span
style="font-family: monospace;">1931_2 </span></small><small><span
style="font-family: monospace;"> (def.)</span></small><small><span
@@ -231,7 +215,6 @@ patch
-
consistency tolerance by ratio (if available)<br>
</span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#S">-S</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -241,7 +224,6 @@ strip
-
&amp; unexpected value warnings</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -249,7 +231,6 @@ Override
-
serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br
style="font-family: monospace;">
<small><span style="font-family: monospace;"></span><small
@@ -262,7 +243,6 @@ Override
-
&nbsp;Base name for input[</span><a style="font-family:
monospace;" href="File_Formats.html#.ti2">.ti2</a><span
style="font-family: monospace;">]/output[</span><a
@@ -409,7 +389,6 @@ Override
allow such a scenario, the <span style="font-weight: bold;">chartread
-
-I</span> parameter allows overriding the .ti2 calibration curves
placed in the resulting .ti3 file with the actual calibration that
was used for that particular print.<br>
@@ -436,15 +415,12 @@ Override
strip instruments (i.e.. Eye-One Pro, Color Munki) when used with
Argyll will automatically recognize a strip when read in the reverse
direction by matching the patch readings against their expected
- values. If the expected values are not known accurately enough, this
- may cause erroneous reverse recognition, so the <span
- style="font-weight: bold;">-<span style="font-weight: bold;">B</span></span>
- flag allows this to be turned off, forcing strips to only be read in
- the forward direction. (Note that the DTP20 always allows
- bi-directional strip reading.) If the randomized patch layout has
- not been used, then&nbsp; bi-directional strip recognition will
- automatically turned off, and a warning issued if the -B flag is not
- used.<br>
+ values. If the randomized patch layout has not been used, or the
+ expected values are not known accurately enough, this may cause
+ erroneous reverse recognition, so the <span style="font-weight:
+ bold;">-<span style="font-weight: bold;">B</span></span> flag
+ allows this to be turned off, forcing strips to only be read in the
+ forward direction.<br>
<br>
<a name="H"></a> The -<span style="font-weight: bold;">H</span>
option turns on high resolution spectral mode, if the instrument
@@ -467,8 +443,10 @@ Override
colorimeters that rely on sensor spectral sensitivity calibration
information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
- Spyder 5</span>).This can improve a colorimeters accuracy for a
- particular type of display.<br>
+ Spyder 5</span>).This
+ can
+ improve
+ a colorimeters accuracy for a particular type of display.<br>
<br>
<a name="T"></a> The -<span style="font-weight: bold;">T ratio</span>
argument modifies the patch consistency tolerance threshold for some
@@ -504,10 +482,7 @@ Override
advisable to also use the <span style="font-weight: bold;">-B</span>
flag if warnings are turned off, since many warnings indicate that
the expected values are not to be relied on. With warnings
- suppressed, greater care must be taken to read the correct strip. If
- the randomized patch layout has not been used, then "wrong strip"
- warnings will automatically be suppressed, and bi-directional strip
- recognition turned off.<br>
+ suppressed, greater care must be taken to read the correct strip.<br>
<br>
<a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
parameter overrides the default serial communications flow control
diff --git a/doc/collink.html b/doc/collink.html
index dc67463..0bb3e77 100644
--- a/doc/collink.html
+++ b/doc/collink.html
@@ -61,8 +61,6 @@
-
-
Verbose<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#A">-A "manufacturer"</a><span
@@ -127,8 +125,6 @@ existing
-
-
profile, rather than link (Debug option)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -177,8 +173,6 @@ clut
-
-
res. set by -q</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#n">-n</a><span
@@ -221,8 +215,6 @@ preserve
-
-
device curves in result</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -290,8 +282,6 @@ Include
-
-
abstract profile in link</span></small><br>
<small><span style="font-family: monospace;"><small><span
style="font-family: monospace;">&nbsp;</span><a
@@ -312,8 +302,6 @@ Include
-
-
Append calibration curves to 3dlut<br style="font-family:
monospace;">
</span> <span style="font-family: monospace;">&nbsp;</span><a
@@ -357,8 +345,6 @@ Mode
-
-
(default)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
style="font-family: monospace;" href="#g">-g [src.gam]</a><span
@@ -405,8 +391,6 @@ Gamut
-
-
Mapping Mode using inverse outprofile A2B [optional source
gamut]</span><br style="font-family: monospace;">
<br style="font-family: monospace;">
@@ -457,8 +441,6 @@ s
-
-
= saturation, a = absolute colorimetric</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -506,8 +488,6 @@ s
-
-
= saturation, a = absolute colorimetric</span><br
style="font-family: monospace;">
<br style="font-family: monospace;">
@@ -558,8 +538,6 @@ a
-
-
Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
aw
@@ -600,8 +578,6 @@ aw
-
-
Absolute Colorimetric (in Jab) with scaling to fit white point<br
style="font-family: monospace;">
</span><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -643,8 +619,6 @@ aa
-
-
Absolute Appearance</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
r
@@ -685,8 +659,6 @@ r
-
-
White Point Matched Appearance [ICC Relative Colorimetric]</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -728,8 +700,6 @@ la
-
-
Luminance matched Appearance</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -771,8 +741,6 @@ p
-
-
Perceptual (Preferred) [ICC Perceptual]<br>
</span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
pa
@@ -812,11 +780,7 @@ pa
-
-
- - Perceptual Appearance</span></small><br>
- <tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- lp - Luminance Preserving Perceptual</tt><br style="font-family:
+ - Perceptual Appearance</span></small><br style="font-family:
monospace;">
<small><span style="font-family: monospace;"></span><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -858,8 +822,6 @@ ms
-
-
Saturation</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
s
@@ -900,8 +862,6 @@ s
-
-
Enhanced Saturation [ICC Saturation]</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -943,8 +903,6 @@ al
-
-
Absolute Colorimetric (Lab)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -978,8 +936,6 @@ al
-
-
rl - White Point Matched Colorimetric (Lab)</span><span
style="font-family: monospace;"></span><br style="font-family:
monospace;">
@@ -995,8 +951,6 @@ al
-
-
Use RGB-&gt;RGB forced black point hack<br style="font-family:
monospace;">
</span> <span style="font-family: monospace;">&nbsp;</span><a
@@ -1043,8 +997,6 @@ either
-
-
an enumerated choice, or a parameter</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -1091,8 +1043,6 @@ either
-
-
an enumerated choice, or a parameter:value change<br>
</span></small><small><span style="font-family: monospace;">&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pp - Practical
@@ -1137,8 +1087,6 @@ either
-
-
&nbsp; pe - Print evaluation environment (CIE 116-1995)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -1179,8 +1127,6 @@ either
-
-
&nbsp; pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
style="font-family: monospace;"></span><span style="font-family:
monospace;"></span><span style="font-family: monospace;"></span><span
@@ -1229,8 +1175,6 @@ either
-
-
mb - Monitor in bright work environment</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
@@ -1290,8 +1234,6 @@ n
-
-
= auto, a = average, m = dim, d = dark,</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1333,8 +1275,6 @@ n
-
-
c = transparency (default average)</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1376,8 +1316,6 @@ Adapted
-
-
white point as XYZ (default media white)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1419,8 +1357,6 @@ Adapted
-
-
white point as x, y</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
a:adaptation&nbsp;
@@ -1461,8 +1397,6 @@ Adaptatation
-
-
luminance in cd.m^2 (default 50.0)</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1505,8 +1439,6 @@ Background
-
-
of image luminance (default 20)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; l:imagewhite&nbsp;
Image white in cd.m^2 if surround = auto (default 250)</span></small><br
@@ -1552,13 +1484,11 @@ light
-
-
% of image luminance (default 0)<br>
</span></small>&nbsp;</span><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
g:glare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare light % of
- ambient (default 5)</span><br style="font-family: monospace;">
+ ambient (default 1)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1585,8 +1515,6 @@ light
-
-
g:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare color as XYZ
(default media white)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1615,8 +1543,6 @@ light
-
-
g:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare
color as x, y</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -1660,8 +1586,6 @@ source
-
-
total ink limit, 0 - 400% (estimate by default)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -1705,8 +1629,6 @@ source
-
-
total ink limit, 0 - 100% (estimate by default)</span><br
style="font-family: monospace;">
<br style="font-family: monospace;">
@@ -1757,8 +1679,6 @@ t
-
-
= transfer K from source to destination, e = retain K of
destination B2A table</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1800,8 +1720,6 @@ z
-
-
= zero K, h = 0.5 K, x = maximum K, r = ramp K (default)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -1846,8 +1764,6 @@ p
-
-
= black level generation curve parameters</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -1893,8 +1809,6 @@ q
-
-
= transfer source K to dual curve limits</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -1943,8 +1857,6 @@ destination
-
-
total ink limit, 0 - 400% (estimate by default)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;</span><a
@@ -1988,8 +1900,6 @@ destination
-
-
total ink limit, 0 - 100% (estimate by default)<br>
&nbsp;<a href="#3">-3 flag</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2022,8 +1932,6 @@ destination
-
-
Create "3DLut" output file as well as devlink<br>
&nbsp;&nbsp;&nbsp;&nbsp;
e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2057,8 +1965,6 @@ destination
-
-
eeColor .txt file</span></small><br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;
m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2080,8 +1986,6 @@ destination
-
-
MadVR .3dlut&nbsp;&nbsp; file</tt><br>
<tt>&nbsp;<a href="#Ib">-I B</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2092,8 +1996,6 @@ destination
-
-
Use BT.1886 source EOTF with technical gamma 2.4</tt><tt><br>
</tt><tt>&nbsp;<a href="#Ib">-I b:g.g</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use
@@ -2105,7 +2007,7 @@ destination
monospace;"></span></small></span></small><br>
<small><span style="font-family: monospace;"><small><span
style="font-family: monospace;"><tt>&nbsp;<a
- href="collink.html#Ib">-I
+ href="file:///D:/src/argyll/doc/collink.html#Ib">-I
g:g.g</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use
effective gamma g.g source EOTF with all output black
@@ -2141,8 +2043,6 @@ destination
-
-
Video encode input as:<br>
&nbsp;<a href="#E">-E flag</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2175,8 +2075,6 @@ destination
-
-
Video encode output as:</span></small><small><span
style="font-family: monospace;"><small><span style="font-family:
monospace;"><br>
@@ -2201,8 +2099,6 @@ destination
-
-
normal RGB 0..1 levels (default)<br>
&nbsp;&nbsp;&nbsp;&nbsp;
t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2225,16 +2121,12 @@ destination
-
-
RGB (16-235)/255 "TV" levels</span></small></span></small><br>
<small><span style="font-family: monospace;"><small><span
style="font-family: monospace;"><small><span
style="font-family: monospace;"><small><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
-
-
T
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2256,8 +2148,6 @@ destination
-
-
RGB (16-235)/255 "TV" levels, clip WTW [Input Only]</span></small></span></small><br>
&nbsp;&nbsp;&nbsp;&nbsp;
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2280,8 +2170,6 @@ destination
-
-
Rec601 YCbCr SD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2304,8 +2192,6 @@ destination
-
-
Rec709 1125/60Hz YCbCr HD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2328,8 +2214,6 @@ destination
-
-
Rec709 1250/50Hz YCbCr HD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2352,8 +2236,6 @@ destination
-
-
Rec2020 YCbCr UHD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2376,8 +2258,6 @@ destination
-
-
Rec2020 Constant Luminance YCbCr UHD (16-235,240)/255 "TV"
levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2401,8 +2281,6 @@ destination
-
-
xvYCC Rec601 YCbCr Rec709 Prims. SD (16-235,240)/255 "TV"
levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2426,8 +2304,6 @@ destination
-
-
xvYCC Rec709 YCbCr Rec709 Prims. HD (16-235,240)/255 "TV"
levels<br>
</span></small>&nbsp;</span></small>&nbsp; <small><span
@@ -2471,8 +2347,6 @@ gamut
-
-
gammap_p.x3d.html and gammap_s.x3d.html diagostics</span></small><small><br>
<span style="font-family: monospace;"></span></small><span
style="font-family: monospace;">&nbsp;<span
@@ -2518,8 +2392,6 @@ ICC
-
-
profile. A </span><small><span style="font-family: monospace;">TIFF
@@ -2557,8 +2429,6 @@ ICC
-
-
or JPEG file with embedded profile may be used here.</span></small><br
style="font-family: monospace;">
&nbsp; <span style="font-family: monospace;"><span
@@ -2604,8 +2474,6 @@ ICC
-
-
profile. </span><span style="font-family: monospace;">A </span><small><span
style="font-family: monospace;">TIFF or JPEG file with embedded
profile may be used here.</span></small><br style="font-family:
@@ -2712,8 +2580,6 @@ ICC
-
-
&nbsp;Override clut res. set by <b>-q</b><br>
<br>
This sets the basic quality of the resulting link, by choosing the
@@ -2902,8 +2768,6 @@ ICC
-
-
&nbsp;<b>p</b> = perceptual, <b>r</b> = relative colorimetric,<br>
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>s</b>
@@ -2994,16 +2858,6 @@ ICC
destination, allowing the apperance parameters to alter the
chromatic mapping.<br>
<br>
- <a name="ilp"></a>The&nbsp; <span style="font-weight: bold;">lp</span>
- intent, Luminance Preserving Perceptual Appearance uses
- compression to make the source gamut fit within the destination
- gamut, but very heavily weights the preservation of the Luminance
- value of the source, which will compromise the preservation of
- saturation. No contrast enhancement is used if the dynamic range
- is reduced. This intent may be of use where preserving the tonal
- distinctions in images is more important than maintaining overall
- colorfulness or contrast.<br>
- <br>
<a name="ims"></a>The <span style="font-weight: bold;">ms</span>
intent, Saturation, uses 3 Dimensional compression and <span
style="text-decoration: underline;">expansion</span> to try and
@@ -3173,8 +3027,6 @@ ICC
-
-
&nbsp; &nbsp;_______&nbsp; enle<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3215,8 +3067,6 @@ ICC
-
-
&nbsp; &nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3257,8 +3107,6 @@ ICC
-
-
&nbsp; /<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3299,8 +3147,6 @@ ICC
-
-
&nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3341,8 +3187,6 @@ ICC
-
-
/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
stle&nbsp; | ------/<br>
@@ -3389,8 +3233,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Black<br>
<br>
</tt>For minimum sensitivity of printed output to the lighting
@@ -3589,8 +3431,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
</b>Full output offset with effective gamma of 2.2<b><br>
</b><b></b><b>-I B</b><b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3601,8 +3441,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
</b>Full input offset (BT.1886 like) with technical gamma of 2.4.
This exactly implements the BT.1886 specification.<b><br>
</b><b>-I G</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3614,8 +3452,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Full output offset with technical gamma of 2.2<br>
<br>
<b>-I b</b><b>:2.3</b><b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3627,8 +3463,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
</b>Full input offset (BT.1886 like) with effective gamma of 2.3<b>
<br>
</b><b> -I g:2.3</b><b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3640,8 +3474,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
</b>Full output offset with effective gamma of 2.3<b><br>
</b><b> -I B:2.35</b><b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3652,8 +3484,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
</b>Full input offset (BT.1886 like) with technical gamma of 2.35<br>
<b> -I G:2.35</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3664,8 +3494,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Full output offset with technical gamma of 2.35<br>
<br>
<b>-I b</b><b>:0.4:2.3</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3679,8 +3507,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Same as above.<b><br>
</b><b> -I B:0.4:2.35</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 60% input
offset, 40% output offset with technical gamma of 2.35 <b><br>
@@ -3699,8 +3525,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
style="font-family: monospace;"><small><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
-
-
T
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3722,15 +3546,11 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
RGB (16-235)/255 "TV" levels, clip WTW
[Input Only]<br>
</span></small></span></small></span></small></span></small>&nbsp;&nbsp;&nbsp;&nbsp;
-
-
x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3751,8 +3571,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
xvYCC Rec601 YCbCr Rec709 Prims. SD (16-235,240)/255 "TV"
levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3776,8 +3594,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
xvYCC Rec709 YCbCr Rec709 Prims. HD (16-235,240)/255 "TV"
levels</span></small></span></small><br>
<br>
@@ -3823,8 +3639,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
normal RGB 0..1 full range levels (default)<br>
&nbsp;&nbsp;&nbsp;&nbsp;
t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3847,8 +3661,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
RGB (16-235)/255 "TV" levels</span></small></span></small><small><span
style="font-family: monospace;"><small><span style="font-family:
monospace;"></span></small></span></small><br>
@@ -3857,8 +3669,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
style="font-family: monospace;"></span></small>&nbsp;&nbsp;&nbsp;&nbsp;
-
-
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3879,8 +3689,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Rec601 YCbCr SD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3903,8 +3711,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Rec709 1125/60Hz YCbCr HD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3927,8 +3733,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Rec709 1250/50Hz YCbCr HD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3951,8 +3755,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Rec2020 YCbCr UHD (16-235,240)/255 "TV" levels<br>
&nbsp;&nbsp;&nbsp;&nbsp;
C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3975,8 +3777,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Rec2020 Constant Luminance YCbCr UHD (16-235,240)/255 "TV"
levels</span></small></span></small><br>
<small><span style="font-family: monospace;"><small><span
@@ -4037,8 +3837,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Usage Scenarios</a> page.<br>
<br>
<br>
diff --git a/doc/colprof.html b/doc/colprof.html
index 755226b..b3b6df2 100644
--- a/doc/colprof.html
+++ b/doc/colprof.html
@@ -46,8 +46,6 @@
-
-
&nbsp; &nbsp; &nbsp; &nbsp; Verbose mode<br>
&nbsp;<a href="#A">-A "manufacturer"</a>&nbsp; Set the
manufacturer description string<br>
@@ -84,8 +82,6 @@
-
-
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Default
intent: Perceptual, Rel. Colorimetric, Saturation, Abs.
Colorimetric</small></tt><tt><br>
@@ -127,8 +123,6 @@
-
-
&nbsp; &nbsp; &nbsp; &nbsp; Don't create input (Device) shaper
curves<br>
</small></tt><tt><small>&nbsp;<a href="#np">-np</a>
@@ -166,8 +160,6 @@
-
-
&nbsp; &nbsp; &nbsp; &nbsp; Don't create output (PCS) shaper
curves<br>
</small></tt><tt><small>&nbsp;<a href="#nc">-nc</a>
@@ -219,8 +211,6 @@ x
-
-
max K, r = ramp K<br>
&nbsp;<a href="#kp">-k p stle stpo enpo enle shape</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -265,8 +255,6 @@ White
-
-
- 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -311,8 +299,6 @@ Wh
-
-
0.0 - Bk 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -357,8 +343,6 @@ Wh
-
-
0.0 - Bk 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -402,8 +386,6 @@ Black
-
-
0.0 - 1.0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -448,8 +430,6 @@ concave,
-
-
1.0-2.0 convex<br>
&nbsp;<a href="#K">-K parameters</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -474,8 +454,6 @@ concave,
-
-
Same as -k, but target is K locus rather than K value itself<br>
&nbsp;<a href="#l">-l <i>tlimit</i></a>&nbsp;&nbsp; &nbsp;
&nbsp; &nbsp;&nbsp; override CMYK total ink limit, 0 - 400%
@@ -527,8 +505,6 @@ cLUT
-
-
x = XYZ cLUT, X = display XYZ cLUT + matrix<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -572,8 +548,6 @@ s
-
-
shaper+matrix, m = matrix only,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -618,8 +592,6 @@ S
-
-
single shaper+matrix<br>
&nbsp;<a href="#u">-u</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
@@ -649,8 +621,6 @@ S
-
-
If input profile, auto scale WP to allow extrapolation</small></tt><tt><br>
</tt><tt> </tt><tt><small><small>&nbsp;<a href="#uc">-uc</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
@@ -697,8 +667,6 @@ and
-
-
primaries to be +ve</tt><tt><br>
&nbsp;<a href="#B">-B X,Y,Z</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -707,8 +675,6 @@ and
-
-
Display Black Point override hack<br>
&nbsp;<a href="#V">-V demphasis</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -723,8 +689,6 @@ and
-
-
Degree of dark region cLUT grid emphasis 1.0-3.0 (default 1.00 =
none)<br>
</tt><tt>&nbsp;</tt><tt><small><small><a href="#f">-f [<i>illum</i>]</a>
@@ -752,8 +716,6 @@ and
-
-
M0, M1, M2, </small></small></tt><tt><small><small><small>A,
C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp ]</small></small></small></tt><tt><br>
</tt><tt><small><small><small><small>&nbsp;<a href="#i">-i <i>illum</i></a>&nbsp;&nbsp;
@@ -778,8 +740,6 @@ and
-
-
&nbsp; &nbsp; &nbsp; &nbsp; Choose illuminant for
computation of CIE XYZ from spectral data &amp; FWA:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -814,8 +774,6 @@ D50M2,
-
-
D65, F5, F8, F10 or file.sp</small></small></small><br>
&nbsp;<a href="#o">-o <i>observ</i></a>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; Choose CIE Observer for spectral data:<br>
@@ -851,8 +809,6 @@ D50M2,
-
-
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </small></tt><tt><small>(def.)</small></tt><tt><small>,
1964_10, S&amp;B 1955_2, shaw, J&amp;V 1978_2<br>
&nbsp;<a href="#r">-r avgdev</a> &nbsp; &nbsp; &nbsp;
@@ -900,8 +856,6 @@ for
-
-
given source<br>
&nbsp;<a href="#S">-S src.icc</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -935,8 +889,6 @@ for
-
-
Apply gamut mapping to output profile perceptual and saturation
B2A table<br>
&nbsp;<a href="#nP">-nP</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -971,8 +923,6 @@ for
-
-
Use colormetric source gamut to make output profile perceptual
table<br>
&nbsp;<a href="#nS">-nS</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1007,8 +957,6 @@ for
-
-
Use colormetric source gamut to make output profile saturation
table<br>
&nbsp;<a href="#g">-g src.gam</a>
@@ -1051,8 +999,6 @@ for
-
-
Override gamut mapping intent for output profile saturation
table:<br>
</small></tt><tt><small> &nbsp; &nbsp; &nbsp;
@@ -1103,12 +1049,7 @@ for
-
-
- pa - Perceptual Appearance</small></tt><br>
- <tt><tt><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- lp - Luminance Preserving Perceptual</small></tt><br>
+ pa - Perceptual Appearance</small></tt><tt><br>
</tt><tt> </tt><tt><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1141,8 +1082,6 @@ for
-
-
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ms - Saturation<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; s - Enhanced Saturation [ICC
@@ -1169,8 +1108,6 @@ for
-
-
rl - White Point Matched Colorimetric (Lab)<br>
&nbsp;<a href="#c">-c viewcond</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1204,8 +1141,6 @@ for
-
-
set input viewing conditions for output profile CIECAM02 gamut
mapping,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1240,8 +1175,6 @@ for
-
-
either an enumerated choice, or a parameter<br>
&nbsp;<a href="#d">-d viewcond</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1275,8 +1208,6 @@ for
-
-
set output viewing conditions for output profile CIECAM02, gamut
mapping<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1311,8 +1242,6 @@ for
-
-
either an enumerated choice, or a parameter:value change<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1346,8 +1275,6 @@ for
-
-
Also sets out of gamut clipping CAM space.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1381,8 +1308,6 @@ for
-
-
Enumerated Viewing Conditions:<br>
</small></tt><tt><small>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp;&nbsp; &nbsp; pp - Practical Reflection Print (ISO-3664
@@ -1445,8 +1370,6 @@ for
-
-
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; c = transparency (default average)<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
@@ -1493,10 +1416,8 @@ for
-
-
g:glare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare light % of
- ambient (default 5)</span><br style="font-family:
+ ambient (default 1)</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
@@ -1542,8 +1463,6 @@ for
-
-
Create gamut gammap_p.x3d.html and gammap_s.x3d.html diagostics<br>
</small></tt><tt><small>&nbsp;<a href="#O">-O outputfile</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
@@ -1578,8 +1497,6 @@ Override
-
-
the default output filename &amp; extension.</small></tt><tt><br>
</tt><tt> </tt><tt><small>&nbsp;<a href="#p1"><i>inoutfile</i></a>
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Base name for
@@ -1734,8 +1651,6 @@ the
-
-
device and CIE/spectral sample data and calibration curves used to
create a profile is stored in the <span style="font-weight: bold;">'targ'</span>
text tag in the resulting ICC profile. To suppress this and make the
@@ -1770,8 +1685,6 @@ the
-
-
</span>flag. <span style="font-weight: bold;">Note</span> that this
will then preclude final calibrated device value ink limits from
being computed for the resulting profile in subsequent use (ie. <a
@@ -1841,8 +1754,6 @@ the
-
-
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
&nbsp;_______&nbsp; enle<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1877,8 +1788,6 @@ the
-
-
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1912,8 +1821,6 @@ the
-
-
|&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1947,8 +1854,6 @@ the
-
-
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1982,8 +1887,6 @@ the
-
-
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; /<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
stle&nbsp; | ------/<br>
@@ -2025,8 +1928,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Black<br>
</tt> <br>
For minimum sensitivity of printed output to the lighting spectrum,
@@ -2105,7 +2006,7 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
point for input devices by avoiding clipping of values above the
white point that can occur in L*a*b* based cLUT input profiles. A <b>disadvantage</b>
of this type of profile is that it can be a lot less robust if given
- a test patch set that is sparse, or too unevenly spaced. By default
+ a test patch set that is sparse, or too evenly spaced. By default
cLUT XYZ PCS Display profiles will also have a set of dummy matrix
tags included in them, for better compatibility with other systems.
The dummy matrix deliberately interchanges Red, Green and Blue
@@ -2284,8 +2185,6 @@ White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb
-
-
Violet</span> spectral content, otherwise FWA compensation won't
work properly. This means you ideally need to measure your
illuminant spectrum using an instrument that can measure down to
diff --git a/doc/dispcal.html b/doc/dispcal.html
index d66caf5..ff96ff2 100644
--- a/doc/dispcal.html
+++ b/doc/dispcal.html
@@ -1,28 +1,28 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>dispcal</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/dispcal</b></h2>
- <h3>Summary</h3>
- Given calibration target information [white point, maximum
- brightness, and response curve ("gamma")], display a series of test
- patches on the display, and using the colorimetric values read,
- create a calibration lookup tables that make the display meet the
- desired target. The type of instrument is determined by the
- communication port selected. Emission and display measurement
- instruments are supported.<br>
- <h3>Usage</h3>
- <font size="-1"><span style="font-family: monospace;">dispcal
- [-options]</span><i style="font-family: monospace;"> inoutfile</i><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#v">-v [n]</a><span
- style="font-family: monospace;">
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispcal</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispcal</b></h2>
+ <h3>Summary</h3>
+ Given calibration target information [white point, maximum
+ brightness, and response curve ("gamma")], display a series of test
+ patches on the display, and using the colorimetric values read,
+ create a calibration lookup tables that make the display meet the
+ desired target. The type of instrument is determined by the
+ communication port selected. Emission and display measurement
+ instruments are supported.<br>
+ <h3>Usage</h3>
+ <font size="-1"><span style="font-family: monospace;">dispcal
+ [-options]</span><i style="font-family: monospace;"> inoutfile</i><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v [n]</a><span
+ style="font-family: monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -70,18 +70,18 @@
-
- Verbose mode<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#display">-display displayname</a><span
- style="font-family: monospace;"> [X11 only] Choose X11 display
- name<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [X11 only]Choose the display from the following list (default
- 1),<br>
+
+ Verbose mode<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [X11 only] Choose X11 display
+ name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [X11 only]Choose the display from the following list (default
+ 1),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
and
optionally
@@ -137,9 +137,9 @@ for
-
- VideoLUT access.</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ VideoLUT access.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Choose
the
@@ -195,8 +195,8 @@ list
-
- 1)</span></font><br>
+
+ 1)</span></font><br>
<span style="font-family: monospace;">&nbsp;<a href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -243,9 +243,9 @@ list
-
- Display via a web server at port (default 8080)</span><br>
- <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
+
+ Display via a web server at port (default 8080)</span><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -276,8 +276,8 @@ list
-
- [MSWin] Display via MadVR Video Renderer</span><br>
+
+ [MSWin] Display via MadVR Video Renderer</span><br>
<tt>&nbsp;</tt><tt><a href="#dcc">-dcc[:n]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -288,13 +288,13 @@ list
-
- </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"></span>&nbsp; <span style="font-family: monospace;"></span></font><small
- style="font-family: monospace;"><span style="font-family:
+
+ </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span>&nbsp; <span style="font-family: monospace;"></span></font><small
+ style="font-family: monospace;"><span style="font-family:
monospace;"></span><a style="font-family: monospace;" href="#c">-c
@@ -342,37 +342,37 @@ list
-
- listno</a><span style="font-family: monospace;"> &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set communication port from
- the following list (default 1)<br>
- </span></small><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#r">-r</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Report on the calibrated display then
- exit</span></font><font size="-1"><span style="font-family:
- monospace;"></span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"><br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#R">-R</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Report on the uncalibrated display then
- exit</span></font><font size="-1"><span style="font-family:
- monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#m">-m</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; </span></font><font size="-1"><span
- style="font-family: monospace;">Skip</span><span
- style="font-family: monospace;"> adjustment of the monitor
- controls</span></font><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
- href="#o">-o [profile.icm]</a>&nbsp;&nbsp;&nbsp;&nbsp; Create
- fast matrix/shaper profile [different filename to outfile.icm]<br>
+
+ listno</a><span style="font-family: monospace;"> &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set communication port from
+ the following list (default 1)<br>
+ </span></small><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#r">-r</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Report on the calibrated display then
+ exit</span></font><font size="-1"><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#R">-R</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Report on the uncalibrated display then
+ exit</span></font><font size="-1"><span style="font-family:
+ monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#m">-m</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; </span></font><font size="-1"><span
+ style="font-family: monospace;">Skip</span><span
+ style="font-family: monospace;"> adjustment of the monitor
+ controls</span></font><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#o">-o [profile.icm]</a>&nbsp;&nbsp;&nbsp;&nbsp; Create
+ fast matrix/shaper profile [different filename to outfile.icm]<br>
&nbsp;<a href="#O">-O description</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -420,8 +420,8 @@ list
-
- Fast ICC Profile Description string (Default "outfile")<br>
+
+ Fast ICC Profile Description string (Default "outfile")<br>
&nbsp;<a href="#u">-u</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Update
previous
@@ -477,12 +477,12 @@ ICC
-
- profile VideoLUTs</span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span><br style="font-family:
- monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#q">-q [lmh]</a><span
+
+ profile VideoLUTs</span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#q">-q [lmh]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -530,8 +530,8 @@ ICC
-
- Quality - Low, Medium (def), High<br>
+
+ Quality - Low, Medium (def), High<br>
&nbsp;<a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -568,10 +568,10 @@ ICC
-
- Use telephoto mode (ie. for a projector) (if available)<br>
- &nbsp;</span></font><font size="-1"><span style="font-family:
- monospace;"><a href="#y">-y X</a>
+
+ Use telephoto mode (ie. for a projector) (if available)<br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><a href="#y">-y X</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -619,12 +619,12 @@ ICC
-
- Display type - instrument specific list to choose from.</span></font><font
- size="-1"><span style="font-family: monospace;"><br
- style="font-family: monospace;">
- </span><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#t">-t [temp]</a><span
+
+ Display type - instrument specific list to choose from.</span></font><font
+ size="-1"><span style="font-family: monospace;"><br
+ style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t [temp]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
White
Daylight
@@ -680,10 +680,10 @@ in
-
- deg. K (deflt.)<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
+
+ deg. K (deflt.)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
href="#T">-T [temp]</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
White
Black
@@ -739,11 +739,11 @@ temperaturee
-
- in deg. K</span></font><br style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#w">-w x,y</a><span
+
+ in deg. K</span></font><br style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#w">-w x,y</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -791,11 +791,11 @@ temperaturee
-
- Set the target white point as chromaticity coordinates</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#b">-b bright</a><span
+
+ Set the target white point as chromaticity coordinates</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#b">-b bright</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -843,11 +843,11 @@ temperaturee
-
- Set the target white brightness in cd/m^2</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#g">-g gamma</a><span
+
+ Set the target white brightness in cd/m^2</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#g">-g gamma</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -895,9 +895,9 @@ temperaturee
-
- Set the target response curve gamma (Def. 2.4)</span><br
- style="font-family: monospace;">
+
+ Set the target response curve gamma (Def. 2.4)</span><br
+ style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -945,9 +945,9 @@ temperaturee
-
- Use "-gl" for L*a*b* curve</span><br style="font-family:
- monospace;">
+
+ Use "-gl" for L*a*b* curve</span><br style="font-family:
+ monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -995,8 +995,8 @@ temperaturee
-
- &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Use "-gs" for sRGB curve<br>
+
+ &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Use "-gs" for sRGB curve<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Use
"-g709"
@@ -1052,8 +1052,8 @@ use
-
- -a as well!)<br>
+
+ -a as well!)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1101,9 +1101,9 @@ use
-
- Use "-g240" for SMPTE 240M curve </span></font><font size="-1"><span
- style="font-family: monospace;">(should use -a as well!)</span></font><br>
+
+ Use "-g240" for SMPTE 240M curve </span></font><font size="-1"><span
+ style="font-family: monospace;">(should use -a as well!)</span></font><br>
<font size="-1"><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1151,7 +1151,7 @@ use
-
+
Use "-G2.4 -f0" for BT.1886</span></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1192,13 +1192,13 @@ use
-
- <br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#G">-G gamma</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Set the target response curve actual technical gamma<br>
+
+ <br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#G">-G gamma</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Set the target response curve actual technical gamma<br>
&nbsp;<a href="#f">-f [degree]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Amount
of
@@ -1254,8 +1254,8 @@ output
-
- offset (default all output offset)<br>
+
+ offset (default all output offset)<br>
&nbsp;<a href="#a">-a ambient</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1303,17 +1303,17 @@ output
-
- Use viewing condition adjustment for ambient in Lux<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#k">-k factor</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Amount to try and correct black point hue. Default 1.0, LCD
- default 0.0<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#A">-A rate</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Rate of blending from neutral to black point. Default 4.0<br>
+
+ Use viewing condition adjustment for ambient in Lux<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#k">-k factor</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Amount to try and correct black point hue. Default 1.0, LCD
+ default 0.0<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#A">-A rate</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Rate of blending from neutral to black point. Default 4.0<br>
&nbsp;<a href="#bhack">-b</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1322,10 +1322,10 @@ output
-
- Use forced black point hack<br>
- </span></font> <font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
+
+ Use forced black point hack<br>
+ </span></font> <font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
href="#B">-B bkbright</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1373,12 +1373,12 @@ output
-
- Set the target black brightness in cd/m^2</span></font><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#e">-e [n]</a><span
+
+ Set the target black brightness in cd/m^2</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#e">-e [n]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1426,12 +1426,12 @@ output
-
- Run n verify passes on final curves<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#z">-<font size="-1">z</font></a><span style="font-family:
- monospace;">
+
+ Run n verify passes on final curves<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#z">-<font size="-1">z</font></a><span style="font-family:
+ monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1479,13 +1479,13 @@ output
-
- Run only verify pass on installed calibration curves</span></font><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;<a href="#P">-P
- ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
- and scale it</span><br style="font-family: monospace;">
+
+ Run only verify pass on installed calibration curves</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;<a href="#P">-P
+ ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
+ and scale it</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ho,vi:
0.0
@@ -1541,8 +1541,8 @@ center,
-
- = right/bottom etc.</span><br style="font-family: monospace;">
+
+ = right/bottom etc.</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ss:
0.5
@@ -1598,9 +1598,9 @@ normal,
-
- = double etc.<br>
- </span></font><font size="-1"><span style="font-family:
+
+ = double etc.<br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1635,10 +1635,10 @@ normal,
-
- ss,vs: = optional horizontal, vertical scale.</span></font><br>
- <font size="-1"><span style="font-family: monospace;"> &nbsp;<a
- href="#F">-F</a>
+
+ ss,vs: = optional horizontal, vertical scale.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;"> &nbsp;<a
+ href="#F">-F</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1686,11 +1686,11 @@ normal,
-
- Fill whole screen with black background</span></font><font
- size="-1"><span style="font-family: monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
+
+ Fill whole screen with black background</span></font><font
+ size="-1"><span style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1717,13 +1717,13 @@ normal,
-
- </span></font><small><span style="font-family: monospace;">Video
- encode output as (16-235)/255 "TV" levels</span></small><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#n">-n</a><span
+
+ </span></font><small><span style="font-family: monospace;">Video
+ encode output as (16-235)/255 "TV" levels</span></small><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#n">-n</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
[X11
@@ -1779,14 +1779,14 @@ on
-
- test window<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#J">-J</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Run instrument calibration first<br>
- </span></font><font size="-1"><span style="font-family:
+
+ test window<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#J">-J</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Run instrument calibration first<br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1834,18 +1834,18 @@ on
-
- Disable initial calibration of instrument if possible</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#H">-H</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
- available)<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;"></span><span style="font-family: monospace;"><br>
- &nbsp;</span></font><font size="-1"><span style="font-family:
- monospace;"><span style="text-decoration: underline;"></span><a
+
+ Disable initial calibration of instrument if possible</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
+ available)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"><br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><span style="text-decoration: underline;"></span><a
href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1893,9 +1893,9 @@ on
-
- Apply Colorimeter Correction Matrix</span></font><br>
- <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Use
Colorimeter
@@ -1946,14 +1946,14 @@ Calibration
-
- Spectral Samples for calibration</span><font size="-1"><span
- style="font-family: monospace;"><br>
- </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
- style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
- colorimeter data:</span><br style="font-family: monospace;">
+
+ Spectral Samples for calibration</span><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
+ colorimeter data:</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2001,11 +2001,11 @@ Calibration
-
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
- style="font-family: monospace;">(def.)</span></small><small><span
- style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
- J&amp;V 1978_2, 1964_10c<br>
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
+ style="font-family: monospace;">(def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2, 1964_10c<br>
&nbsp;<a href="#I">-I b|w</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2053,8 +2053,8 @@ Calibration
-
- Drift compensation, Black: -Ib, White: -Iw, Both: -Ibw</span></small><br>
+
+ Drift compensation, Black: -Ib, White: -Iw, Both: -Ibw</span></small><br>
<small><span style="font-family: monospace;"><tt>&nbsp;<a href="#YR">-Y
@@ -2071,7 +2071,7 @@ Calibration
-
+
R:<i>rate</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2088,36 +2088,36 @@ Calibration
-
- Override measured refresh rate with rate Hz<br>
- </tt>&nbsp;</span></small><font size="-1"><span
- style="font-family: monospace;"></span><a style=" font-family:
- monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode (if
- available).</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
- <font size="-1">p</font></a><span style="font-family:
- monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
- the display</span></font><br>
- <small><span style="font-family: monospace;"> </span></small><font
- size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#C">-C "command"</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is set</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#M">-M "command"</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is measured</span></font><font
- size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ Override measured refresh rate with rate Hz<br>
+ </tt>&nbsp;</span></small><font size="-1"><span
+ style="font-family: monospace;"></span><a style=" font-family:
+ monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode (if
+ available).</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
+ <font size="-1">p</font></a><span style="font-family:
+ monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
+ the display</span></font><br>
+ <small><span style="font-family: monospace;"> </span></small><font
+ size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#C">-C "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is set</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#M">-M "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is measured</span></font><font
+ size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
serial
@@ -2173,12 +2173,12 @@ none,
-
- h = HW, x = Xon/Xoff</span></font><font size="-1"><span
- style="font-family: monospace;"></span></font><br>
- <font size="-1"><span style="font-family: monospace;"> </span></font><font
- size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#D">-D [level]</a><span
+
+ h = HW, x = Xon/Xoff</span></font><font size="-1"><span
+ style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;"> </span></font><font
+ size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D [level]</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2226,12 +2226,12 @@ none,
-
- Print debug diagnostics to stderr</span></font><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#p1"><i>inoutfile</i></a><span
+
+ Print debug diagnostics to stderr</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p1"><i>inoutfile</i></a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2279,79 +2279,79 @@ none,
-
- </span><span style="font-family: monospace;">Base name for created
- or updated </span></font><font size="-1"><a style="font-family:
- monospace;" href="cal_format.html">.cal</a><span
- style="font-family: monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;">&nbsp; and <a
- href="File_Formats.html#ICC">.icm</a> output files</span></font><br>
- <br>
- <h3>Comments<br>
- </h3>
- This is the tool is used for adjusting and calibrating a display to
- reach specified target behaviour, and optionally profiling it.&nbsp;
- For best results on a CRT, you should run this against a neutral
- grey desktop background, and avoid having any bright images or
- windows on the screen at the time you run dispcal. You could also
- use the <span style="font-weight: bold;">-B</span> option to black
- the whole screen out, although this will make it impossible to
- control dispcal unless you have more than one display.<br>
- <br>
- <a name="v"></a> The <b>-v</b> flag reports progress information,
- as well as other statistics about the progress of calibration. A
- numerical argument greater than 1 gives greater verbosity. 2 will
- give per step adjustment and repeat information, while 3 will give
- even greater technical detail.<br>
- <br>
- <a name="display"></a>When running on a UNIX based system that used
- the X11 Windowing System, <b>dispcal</b> will by default use the
- $DISPLAY environment variable to determine which local or remote
- display and screen to read from. This can be overridden by supplying
- an X11 display name to the <span style="font-weight: bold;">-display</span>
- option. Note that if Xinerama is active, you can't select the screen
- using $DISPLAY or -display, you have to select it using the <span
- style="font-weight: bold;">-d</span> parameter.<br>
- <br>
- <a name="d"></a> By default the main display will be the location of
- the test window. If the system has more than one display or screen,
- an alternate display/screen can be selected with the <span
- style="font-weight: bold;">-d</span> parameter. If you invoke <span
- style="font-weight: bold;">dispcal</span> so as to display the
- usage information (i.e. "dispcal -?" or "dispcal --"), then the
- discovered displays/screens will be listed. Multiple displays may
- not be listed, if they appear as a single display to the operating
- system (ie. the multi-display support is hidden in the video card
- driver). On UNIX based system that used the X11 Windowing System,
- the <span style="font-weight: bold;">-d</span> parameter will
- override the screen specified by the $DISPLAY or parameter.<br>
- <br>
- <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
- display are not accessible (i.e. no hardware calibration
- capability), <span style="font-weight: bold;">dispcal</span> will
- will issue a warning, but continue creating a calibration based on
- the display "as-is" rather than its native response. See the <a
- href="dispcal.html#o">-o</a> flag for an explanation of the
- implications of having no access to the VideoLUTs.<br>
- <br>
- On X11 the inability to access VideoLUTs could be because you are
- trying to access a remote display, and the remote display doesn't
- support the XF86VidMode extension, or perhaps you are running
- multiple monitors using NVidia TwinView, or MergedFB, and trying to
- access anything other than the primary monitor. TwinView and
- MergedFB don't properly support the XF86VidMode extension for
- multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
- to test whether the VideoLUTs are accessible for a particular
- display. See also below, on how to select a different display for
- VideoLUT access. Also note that dispcal will fail if the Visual
- depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
- 256 entries per color component, so the Visual generally needs to be
- 24 bits, 8 bits per color component.<br>
- <br>
- <a name="dnm"></a>Because of the difficulty cause by TwinView and
- MergedFB in X11 based systems, you can optionally specify a separate
- display number after the display that is going to be used to present
- test patches, for accessing the VideoLUT hardware. This must be
+
+ </span><span style="font-family: monospace;">Base name for created
+ or updated </span></font><font size="-1"><a style="font-family:
+ monospace;" href="cal_format.html">.cal</a><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;">&nbsp; and <a
+ href="File_Formats.html#ICC">.icm</a> output files</span></font><br>
+ <br>
+ <h3>Comments<br>
+ </h3>
+ This is the tool is used for adjusting and calibrating a display to
+ reach specified target behaviour, and optionally profiling it.&nbsp;
+ For best results on a CRT, you should run this against a neutral
+ grey desktop background, and avoid having any bright images or
+ windows on the screen at the time you run dispcal. You could also
+ use the <span style="font-weight: bold;">-B</span> option to black
+ the whole screen out, although this will make it impossible to
+ control dispcal unless you have more than one display.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag reports progress information,
+ as well as other statistics about the progress of calibration. A
+ numerical argument greater than 1 gives greater verbosity. 2 will
+ give per step adjustment and repeat information, while 3 will give
+ even greater technical detail.<br>
+ <br>
+ <a name="display"></a>When running on a UNIX based system that used
+ the X11 Windowing System, <b>dispcal</b> will by default use the
+ $DISPLAY environment variable to determine which local or remote
+ display and screen to read from. This can be overridden by supplying
+ an X11 display name to the <span style="font-weight: bold;">-display</span>
+ option. Note that if Xinerama is active, you can't select the screen
+ using $DISPLAY or -display, you have to select it using the <span
+ style="font-weight: bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a> By default the main display will be the location of
+ the test window. If the system has more than one display or screen,
+ an alternate display/screen can be selected with the <span
+ style="font-weight: bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispcal</span> so as to display the
+ usage information (i.e. "dispcal -?" or "dispcal --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed, if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or parameter.<br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
+ display are not accessible (i.e. no hardware calibration
+ capability), <span style="font-weight: bold;">dispcal</span> will
+ will issue a warning, but continue creating a calibration based on
+ the display "as-is" rather than its native response. See the <a
+ href="dispcal.html#o">-o</a> flag for an explanation of the
+ implications of having no access to the VideoLUTs.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
+ <a name="dnm"></a>Because of the difficulty cause by TwinView and
+ MergedFB in X11 based systems, you can optionally specify a separate
+ display number after the display that is going to be used to present
+ test patches, for accessing the VideoLUT hardware. This must be
specified as a single string, e.g. <span style="font-weight: bold;">-d
@@ -2399,273 +2399,273 @@ none,
-
- 1,2</span> . Some experimentation may be needed using <a
- href="dispwin.html">dispwin</a> on such systems, to discover what
- screen has access to the VideoLUT hardware, and which screens the
- test patches appear on. You may be able to calibrate one screen, and
- then share the calibration with another screen. Profiling can be
- done independently to calibration on each screen.<br>
- <br>
- <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
- <span style="font-weight: bold;">-dweb:port</span> starts a
- standalone web server on your machine, which then allows a local or
- remote web browser to display the the color test patches. By default
- port <span style="font-weight: bold;">8080</span> is used, but this
- can be overridden by appending a <span style="font-weight: bold;">:</span>
- and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
- The URL will be <span style="font-weight: bold;">http://</span>
- then name of the machine or its I.P. address followed by a colon and
- the port number - e.g something like <span style="font-weight:
- bold;">http://192.168.0.1:8080</span>. If you use the verbose
- option (<span style="font-weight: bold;">-v</span>) then a likely
- URL will be printed once the server is started, or you could run <span
- style="font-weight: bold;">ipconfig</span> (MSWin) or <span
- style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
- and identify an internet address for your machine that way. <b>JavaScript</b>
- needs to be enabled in your web browser for this to work. You may
- have to modify any firewall to permit port 8080 to be accessed on
- your machine.<br>
- <br>
- Note that if you use this method of displaying test patches, that
- there is no access to the display VideoLUTs and that the colors will
- be displayed with 8 bit per component precision, and any
- screen-saver or power-saver will not be disabled. You will also be
- at the mercy of any color management applied by the web browser, and
- may have to carefully review and configure such color management.
- See the <a href="#o">-o</a> flag for an explanation of the
- implications of having no access to the VideoLUTs.<br>
- <br>
- <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
- [MSWin only] causes test patches to be displayed using the MadVR
- video renderer. Note that will have to start <b>MadTPG</b> before
- running dispcal, and that while you can adjust the "Test Pattern
- Configuration" controls, you should <u>not</u> normally alter the
- "Existing Calibration" controls, as dispcal will set these
- appropriately. <br>
- <br>
- <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
- causes test patches to be displayed using and available <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
- your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
- local network. Note that the ChromeCast as a test patch source is
- probably the<b> least accurate</b> of your choices, since it
- up-samples the test patch and transforms from RGB to YCC and back,
- but should be accurate within ± 1 bit. You may have to modify any
- firewall to permit port 8081 to be accessed on your machine if it
+
+ 1,2</span> . Some experimentation may be needed using <a
+ href="dispwin.html">dispwin</a> on such systems, to discover what
+ screen has access to the VideoLUT hardware, and which screens the
+ test patches appear on. You may be able to calibrate one screen, and
+ then share the calibration with another screen. Profiling can be
+ done independently to calibration on each screen.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>JavaScript</b>
+ needs to be enabled in your web browser for this to work. You may
+ have to modify any firewall to permit port 8080 to be accessed on
+ your machine.<br>
+ <br>
+ Note that if you use this method of displaying test patches, that
+ there is no access to the display VideoLUTs and that the colors will
+ be displayed with 8 bit per component precision, and any
+ screen-saver or power-saver will not be disabled. You will also be
+ at the mercy of any color management applied by the web browser, and
+ may have to carefully review and configure such color management.
+ See the <a href="#o">-o</a> flag for an explanation of the
+ implications of having no access to the VideoLUTs.<br>
+ <br>
+ <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
+ [MSWin only] causes test patches to be displayed using the MadVR
+ video renderer. Note that will have to start <b>MadTPG</b> before
+ running dispcal, and that while you can adjust the "Test Pattern
+ Configuration" controls, you should <u>not</u> normally alter the
+ "Existing Calibration" controls, as dispcal will set these
+ appropriately. <br>
+ <br>
+ <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
+ causes test patches to be displayed using and available <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
+ your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
+ local network. Note that the ChromeCast as a test patch source is
+ probably the<b> least accurate</b> of your choices, since it
+ up-samples the test patch and transforms from RGB to YCC and back,
+ but should be accurate within ± 1 bit. You may have to modify any
+ firewall to permit port 8081 to be accessed on your machine if it
falls back to the Default receiver (see <a href="Installing.html">installation
-
- instructions</a> for your platform).<br>
- <br>
- <a name="c"></a> <span style="font-weight: bold;">-c</span> The
- instrument is assumed to communicate through a USB or serial
- communication port, and the port can be selected with the <b>-c</b>
- option, if the instrument is not connected to the first port. If you
- invoke <span style="font-weight: bold;">dispcal</span> so as to
- display the usage information (i.e. "dispcal -?" or "dispcal --"),
- then the discovered USB and serial ports will be listed. On
- UNIX/Linux, a list of all possible serial ports are shown, but not
- all of them may actually be present on your system.<br>
- <br>
- <a name="r"></a> The -<span style="font-weight: bold;">r</span> and
- <span style="font-weight: bold;"><a name="R"></a>-R </span>flags
- perform a quick measurement of current display behaviour, reports
- and then exits. If the <span style="font-weight: bold;">-r</span>
- flag is used the measurement are taken using the currently loaded
- calibration (Video LUT) curves, and in the case of MadVR renderer
- test patch display the Color Management 3dLut. If <span
- style="font-weight: bold;">-R</span> is use, then the uncalibrated
- ("raw" or "native") behaviour is measured (ie. no VideoLut or CM).
- Reported are: <br>
- <br>
- &nbsp;&nbsp;&nbsp; Black Brightness in cd/m^2<br>
- &nbsp;&nbsp;&nbsp; White Brightness in cd/m^2<br>
- &nbsp;&nbsp;&nbsp; The approximate Gamma<br>
- &nbsp;&nbsp;&nbsp; The white point x,y chromaticity co-ordinates<br>
- &nbsp;&nbsp;&nbsp; The correlated color temperature in Kelvin, and
- the CIEDE200 to the Black Body locus.<br>
- &nbsp;&nbsp;&nbsp; The correlated Daylight temperature in Kelvin,
- and the CIEDE200 to the Daylight locus.<br>
- &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin, and the
- CIEDE200 to the Black Body locus.<br>
- &nbsp;&nbsp;&nbsp; The visual Daylight temperature in Kelvin, and
- the CIEDE200 to the Daylight locus.<br>
- &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin<br>
- (for <span style="font-weight: bold;">-R </span>"raw":)<br>
- &nbsp;&nbsp;&nbsp; The apparent VideoLUT entry number of significant
- bits.<br>
- <br>
- Note that the correlated color temperature is the temperature of a
- black body radiator that has the closest color to the white point
- measured using the traditional CIE 1960 UCS space color difference
- formula. The correlated daylight temperature is a similar thing,
- except the CIE daylight locus is used. The visual color temperature
- values are calculated similarly to the correlated color
- temperatures, but using the modern CIEDE2000 color difference
- formula to calculate a better visual approximation to the closest
- temperature to the displays white point. There will be no difference
- between the UCS and CIEDE2000 temperatures if the display white
- point actually lies on the particular locus.<br>
- <br>
- <a name="m"></a> The -<span style="font-weight: bold;">m</span>
- option skips the usual process of adjusting the display monitor
- contrast, brightness and white point controls, and skips straight to
- calibration.<br>
- <br>
- <a name="o"></a><span style="font-weight: bold;">-o [</span><span
- style="font-style: italic;">profile.icm</span><span
- style="font-weight: bold;">]</span> Normally <span
- style="font-weight: bold;">dispcal</span> creates just a
- calibration file, which can then be used for subsequent
- characterization using <a href="dispread.html">dispread</a> and
- profiling using <a href="colprof.html">colprof</a>. If the <span
- style="font-weight: bold;">-o</span> flag is used, <span
- style="font-weight: bold;">dispcal</span> will also create a
- shaper/matrix profile. By default it will create a profile named <span
- style="font-weight: bold;">inoutfile.icm</span>, but a differently
- named file can be created or updated by specifying the name after
- the <span style="font-weight: bold;">-o</span> flag. If the <span
- style="font-weight: bold;">-u</span> flag is used with <span
- style="font-weight: bold;">-o</span>, then the ICC profile <span
- style="font-weight: bold;">vcgt</span> calibration curves will be
- updated.<br>
- <br>
- Note that if VideoLUT access is not possible for the display, that
- hardware calibration is not possible. dispcal will create
- calibration curves anyway with a warning, and if a profile is
- created, it will not contain a 'vcgt' tag, but instead will have the
- calibration curves incorporated into the profile itself. If
- calibration parameters are chosen that change the displays white
- point or brightness, then this will result in a slightly unusual
- profile that has a white point that does not correspond with
- R=G=B=1.0. Some systems may not cope properly with this type of
- profile. See the <a href="Scenarios.html#PM7">tutorial</a> for a
- further explanation.<br>
- <br>
- <a name="O"></a>The <b>-O</b> parameter allows setting of the
- shaper/matrix profile description tag. The parameter should be a
- string that describes the device and profile. With most command line
- shells, it will be necessary to enclose the parameter with double
- quotes, so that spaces and other special characters are included in
- the parameter, and not mistaken for the start of another flag, or as
- a final command line parameter. Many programs that deal with ICC
- profiles use the description tag to identify a profile, rather than
- the profile filename, so using a descriptive string is important in
- being able to find a profile. By default, the profile file name will
- be used as the description.<br>
- <br>
- <a name="u"></a><span style="font-weight: bold;">-u</span> Normally
- <span style="font-weight: bold;">dispcal</span> creates a new
- calibration file and optional profile, based on the requested
- targets and the response of the display. This can take a fair amount
- of time, particularly if a high quality level has been selected, so
- to speed up the process of keeping a display in calibration the <span
- style="font-weight: bold;">-u</span> flag can be used. This uses
- the same calibration targets as the previous calibration but does a
- smaller number of refinement passes, enough to improve the accuracy
- of the calibration to account for drift in the device. If the <span
- style="font-weight: bold;">-o</span> flag is used as well, then
- the ICC profile <span style="font-weight: bold;"></span>will have
- its vcgt tag updated with the new calibration. This keeps the
- profile up to date with the display. Normally <span
- style="font-weight: bold;">dispcal -u</span> will use the same
- quality level that was specified in the previous calibration, but
- this can be overridden using the <span style="font-weight: bold;">-q</span>
- flag. Any options that attempt to change the calibration target (ie.
- white point, brightness, gamma etc.) will be ignored. Adjustment of
- the display monitor controls is skipped. A profile cannot be updated
- if the display does not support hardware calibration (no VideoLUT
- access).<br>
- <br>
- <a name="q"></a>&nbsp; Quality - Low, Medium (def), High. The <span
- style="font-weight: bold;">-q</span> flag determines how much time
- and effort to go to in calibrating the display. The higher the
- quality, the more test readings will be done, the more refinement
- passes will be done, the tighter will be the accuracy tolerance, and
- the more detailed will be the calibration of the display. The result
- will ultimately be limited by the accuracy of the instrument, the
- repeatability of the display and instrument, and the resolution of
- the Video Lookup table entries and Digital or Analogue output
- (RAMDAC).<br>
- <br>
- <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
- allows measuring in telephoto mode, using instruments that support
- this mode, e.g. the ColorMunki. Telephoto mode is one for taking
- emissive measurements from a distance (ie. telespectometer,
- tele-colorimeter) mode, and typically would be used for measuring
- projector type displays. If a device does not support a specific
- telephoto mode, then the normal emissive mode may be suitable for
- measuring projectors.<br>
- <br>
- <a name="y"></a>&nbsp; The <span style="font-weight: bold;">-y</span>
- flag allows setting the Display Type. The selection typically
- determines two aspects of of the instrument operation: <span
- style="font-weight: bold;">1)</span> It may set the measuring mode
- to suite <a
- href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
- style="font-weight: bold;">refresh</span> or <span
- style="font-weight: bold;">non-refresh</span> displays</a>.
- Typically only LCD (Liquid Crystal) displays have a non-refresh
- nature. <span style="font-weight: bold;">2)</span> It may select an
- instrument calibration matrix suitable for a particular display
- type. The selections available depends on the type and model of
- instrument, and a list of the options for the discovered instruments
- will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
- information. For more details on what particular instruments support
- and how this works, see <a href="instruments.html">Operation of
- particular instruments</a>. <b>3)</b> Any installed CCSS files
- (if applicable), or CCMX files. These files are typically created
- using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
- href="oeminst.html">oeminst</a>. The default and Base Calibration
- types will be indicated in the usage.<br>
- <br>
- <a name="t"></a><span style="text-decoration: underline;"></span> <span
- style="font-weight: bold;">-t</span> Set the target white point
- locus to the equivalent of a Daylight spectrum of the given
- temperature in degrees Kelvin. By default the white point target
- will be the native white of the display, and it's color temperature
- and delta E to the daylight spectrum locus will be shown during
- monitor adjustment, and adjustments will be recommended to put the
- display white point directly on the Daylight locus. If a Daylight
- color temperature is given as an argument to <span
- style="font-weight: bold;">-t</span>, then this will become the
- target of the adjustment, and the recommended adjustments will be
- those needed to make the monitor white point meet the target.
- Typical&nbsp; values might be 5000 for matching printed output, or
- 6500, which gives a brighter, bluer look. A white point temperature
- different to that native to the display may limit the maximum
- brightness possible.<br>
- <br>
- <a name="T"></a><span style="text-decoration: underline;"></span> <span
- style="font-weight: bold;">-T</span>&nbsp; Same functionality as
- the <span style="font-weight: bold;">-t</span> option, except the
- white point locus will be the Black Body, or Planckian locus, rather
- than the Daylight locus. While these two white point loci are quite
- close, they are subtly different. If a temperature is given as an
- argument, this will become the Black Body target temperature during
- adjustment.<br>
- <br>
- <a name="w"></a><span style="font-weight: bold;">-w</span>&nbsp; An
- alternative to specifying a&nbsp; white point target in Daylight or
- Black Body degrees Kevin, is to specify it in chromaticity
- co-ordinates. This allows the white point to be a color other than
- one on the Daylight or Black Body. Note that the x,y numbers must be
- specified as a single string (no space between the numbers and the
- comma).<br>
- <br>
- <a name="b"></a><span style="font-weight: bold;">-b</span>&nbsp; Set
- the target brightness of white in cd/m^2. If this number cannot be
- reached, the brightest output possible is chosen, consistent with
- matching the white point target. Note that many of the instruments
- are not particularly accurate when assessing the absolute display
- brightness in cd/m^2. <span style="font-weight: bold;">NOTE</span>
- that some LCD screens behave a little strangely near their absolute
- white point, and may therefore exhibit odd behavior at values just
- below white. It may be advisable in such cases to set a brightness
- slightly less than the maximum such a display is capable of.<br>
- <br>
+
+ instructions</a> for your platform).<br>
+ <br>
+ <a name="c"></a> <span style="font-weight: bold;">-c</span> The
+ instrument is assumed to communicate through a USB or serial
+ communication port, and the port can be selected with the <b>-c</b>
+ option, if the instrument is not connected to the first port. If you
+ invoke <span style="font-weight: bold;">dispcal</span> so as to
+ display the usage information (i.e. "dispcal -?" or "dispcal --"),
+ then the discovered USB and serial ports will be listed. On
+ UNIX/Linux, a list of all possible serial ports are shown, but not
+ all of them may actually be present on your system.<br>
+ <br>
+ <a name="r"></a> The -<span style="font-weight: bold;">r</span> and
+ <span style="font-weight: bold;"><a name="R"></a>-R </span>flags
+ perform a quick measurement of current display behaviour, reports
+ and then exits. If the <span style="font-weight: bold;">-r</span>
+ flag is used the measurement are taken using the currently loaded
+ calibration (Video LUT) curves, and in the case of MadVR renderer
+ test patch display the Color Management 3dLut. If <span
+ style="font-weight: bold;">-R</span> is use, then the uncalibrated
+ ("raw" or "native") behaviour is measured (ie. no VideoLut or CM).
+ Reported are: <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Black Brightness in cd/m^2<br>
+ &nbsp;&nbsp;&nbsp; White Brightness in cd/m^2<br>
+ &nbsp;&nbsp;&nbsp; The approximate Gamma<br>
+ &nbsp;&nbsp;&nbsp; The white point x,y chromaticity co-ordinates<br>
+ &nbsp;&nbsp;&nbsp; The correlated color temperature in Kelvin, and
+ the CIEDE200 to the Black Body locus.<br>
+ &nbsp;&nbsp;&nbsp; The correlated Daylight temperature in Kelvin,
+ and the CIEDE200 to the Daylight locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin, and the
+ CIEDE200 to the Black Body locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual Daylight temperature in Kelvin, and
+ the CIEDE200 to the Daylight locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin<br>
+ (for <span style="font-weight: bold;">-R </span>"raw":)<br>
+ &nbsp;&nbsp;&nbsp; The apparent VideoLUT entry number of significant
+ bits.<br>
+ <br>
+ Note that the correlated color temperature is the temperature of a
+ black body radiator that has the closest color to the white point
+ measured using the traditional CIE 1960 UCS space color difference
+ formula. The correlated daylight temperature is a similar thing,
+ except the CIE daylight locus is used. The visual color temperature
+ values are calculated similarly to the correlated color
+ temperatures, but using the modern CIEDE2000 color difference
+ formula to calculate a better visual approximation to the closest
+ temperature to the displays white point. There will be no difference
+ between the UCS and CIEDE2000 temperatures if the display white
+ point actually lies on the particular locus.<br>
+ <br>
+ <a name="m"></a> The -<span style="font-weight: bold;">m</span>
+ option skips the usual process of adjusting the display monitor
+ contrast, brightness and white point controls, and skips straight to
+ calibration.<br>
+ <br>
+ <a name="o"></a><span style="font-weight: bold;">-o [</span><span
+ style="font-style: italic;">profile.icm</span><span
+ style="font-weight: bold;">]</span> Normally <span
+ style="font-weight: bold;">dispcal</span> creates just a
+ calibration file, which can then be used for subsequent
+ characterization using <a href="dispread.html">dispread</a> and
+ profiling using <a href="colprof.html">colprof</a>. If the <span
+ style="font-weight: bold;">-o</span> flag is used, <span
+ style="font-weight: bold;">dispcal</span> will also create a
+ shaper/matrix profile. By default it will create a profile named <span
+ style="font-weight: bold;">inoutfile.icm</span>, but a differently
+ named file can be created or updated by specifying the name after
+ the <span style="font-weight: bold;">-o</span> flag. If the <span
+ style="font-weight: bold;">-u</span> flag is used with <span
+ style="font-weight: bold;">-o</span>, then the ICC profile <span
+ style="font-weight: bold;">vcgt</span> calibration curves will be
+ updated.<br>
+ <br>
+ Note that if VideoLUT access is not possible for the display, that
+ hardware calibration is not possible. dispcal will create
+ calibration curves anyway with a warning, and if a profile is
+ created, it will not contain a 'vcgt' tag, but instead will have the
+ calibration curves incorporated into the profile itself. If
+ calibration parameters are chosen that change the displays white
+ point or brightness, then this will result in a slightly unusual
+ profile that has a white point that does not correspond with
+ R=G=B=1.0. Some systems may not cope properly with this type of
+ profile. See the <a href="Scenarios.html#PM7">tutorial</a> for a
+ further explanation.<br>
+ <br>
+ <a name="O"></a>The <b>-O</b> parameter allows setting of the
+ shaper/matrix profile description tag. The parameter should be a
+ string that describes the device and profile. With most command line
+ shells, it will be necessary to enclose the parameter with double
+ quotes, so that spaces and other special characters are included in
+ the parameter, and not mistaken for the start of another flag, or as
+ a final command line parameter. Many programs that deal with ICC
+ profiles use the description tag to identify a profile, rather than
+ the profile filename, so using a descriptive string is important in
+ being able to find a profile. By default, the profile file name will
+ be used as the description.<br>
+ <br>
+ <a name="u"></a><span style="font-weight: bold;">-u</span> Normally
+ <span style="font-weight: bold;">dispcal</span> creates a new
+ calibration file and optional profile, based on the requested
+ targets and the response of the display. This can take a fair amount
+ of time, particularly if a high quality level has been selected, so
+ to speed up the process of keeping a display in calibration the <span
+ style="font-weight: bold;">-u</span> flag can be used. This uses
+ the same calibration targets as the previous calibration but does a
+ smaller number of refinement passes, enough to improve the accuracy
+ of the calibration to account for drift in the device. If the <span
+ style="font-weight: bold;">-o</span> flag is used as well, then
+ the ICC profile <span style="font-weight: bold;"></span>will have
+ its vcgt tag updated with the new calibration. This keeps the
+ profile up to date with the display. Normally <span
+ style="font-weight: bold;">dispcal -u</span> will use the same
+ quality level that was specified in the previous calibration, but
+ this can be overridden using the <span style="font-weight: bold;">-q</span>
+ flag. Any options that attempt to change the calibration target (ie.
+ white point, brightness, gamma etc.) will be ignored. Adjustment of
+ the display monitor controls is skipped. A profile cannot be updated
+ if the display does not support hardware calibration (no VideoLUT
+ access).<br>
+ <br>
+ <a name="q"></a>&nbsp; Quality - Low, Medium (def), High. The <span
+ style="font-weight: bold;">-q</span> flag determines how much time
+ and effort to go to in calibrating the display. The higher the
+ quality, the more test readings will be done, the more refinement
+ passes will be done, the tighter will be the accuracy tolerance, and
+ the more detailed will be the calibration of the display. The result
+ will ultimately be limited by the accuracy of the instrument, the
+ repeatability of the display and instrument, and the resolution of
+ the Video Lookup table entries and Digital or Analogue output
+ (RAMDAC).<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Telephoto mode is one for taking
+ emissive measurements from a distance (ie. telespectometer,
+ tele-colorimeter) mode, and typically would be used for measuring
+ projector type displays. If a device does not support a specific
+ telephoto mode, then the normal emissive mode may be suitable for
+ measuring projectors.<br>
+ <br>
+ <a name="y"></a>&nbsp; The <span style="font-weight: bold;">-y</span>
+ flag allows setting the Display Type. The selection typically
+ determines two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
+ href="oeminst.html">oeminst</a>. The default and Base Calibration
+ types will be indicated in the usage.<br>
+ <br>
+ <a name="t"></a><span style="text-decoration: underline;"></span> <span
+ style="font-weight: bold;">-t</span> Set the target white point
+ locus to the equivalent of a Daylight spectrum of the given
+ temperature in degrees Kelvin. By default the white point target
+ will be the native white of the display, and it's color temperature
+ and delta E to the daylight spectrum locus will be shown during
+ monitor adjustment, and adjustments will be recommended to put the
+ display white point directly on the Daylight locus. If a Daylight
+ color temperature is given as an argument to <span
+ style="font-weight: bold;">-t</span>, then this will become the
+ target of the adjustment, and the recommended adjustments will be
+ those needed to make the monitor white point meet the target.
+ Typical&nbsp; values might be 5000 for matching printed output, or
+ 6500, which gives a brighter, bluer look. A white point temperature
+ different to that native to the display may limit the maximum
+ brightness possible.<br>
+ <br>
+ <a name="T"></a><span style="text-decoration: underline;"></span> <span
+ style="font-weight: bold;">-T</span>&nbsp; Same functionality as
+ the <span style="font-weight: bold;">-t</span> option, except the
+ white point locus will be the Black Body, or Planckian locus, rather
+ than the Daylight locus. While these two white point loci are quite
+ close, they are subtly different. If a temperature is given as an
+ argument, this will become the Black Body target temperature during
+ adjustment.<br>
+ <br>
+ <a name="w"></a><span style="font-weight: bold;">-w</span>&nbsp; An
+ alternative to specifying a&nbsp; white point target in Daylight or
+ Black Body degrees Kevin, is to specify it in chromaticity
+ co-ordinates. This allows the white point to be a color other than
+ one on the Daylight or Black Body. Note that the x,y numbers must be
+ specified as a single string (no space between the numbers and the
+ comma).<br>
+ <br>
+ <a name="b"></a><span style="font-weight: bold;">-b</span>&nbsp; Set
+ the target brightness of white in cd/m^2. If this number cannot be
+ reached, the brightest output possible is chosen, consistent with
+ matching the white point target. Note that many of the instruments
+ are not particularly accurate when assessing the absolute display
+ brightness in cd/m^2. <span style="font-weight: bold;">NOTE</span>
+ that some LCD screens behave a little strangely near their absolute
+ white point, and may therefore exhibit odd behavior at values just
+ below white. It may be advisable in such cases to set a brightness
+ slightly less than the maximum such a display is capable of.<br>
+ <br>
<a name="g"></a><span style="font-weight: bold;">-g gamma</span>&nbsp;
Set
@@ -2714,14 +2714,14 @@ Set
-
- the target response curve gamma. This is normally an exponential
- curve (output = input ^gamma), and defaults to 2.4 on MSWindows and
- Macintosh OS X 10.6 or latter and Linux/Unix (which is typical of a
- CRT type displays real response), and 1.8 on a Macintosh (prior to
- OS X 10.6). Four pre-defined curves can be used as well: the sRGB
- colorspace response curve, which is an exponent curve with a
- straight segment at the dark end and an overall response of
+
+ the target response curve gamma. This is normally an exponential
+ curve (output = input ^gamma), and defaults to 2.4 on MSWindows and
+ Macintosh OS X 10.6 or latter and Linux/Unix (which is typical of a
+ CRT type displays real response), and 1.8 on a Macintosh (prior to
+ OS X 10.6). Four pre-defined curves can be used as well: the sRGB
+ colorspace response curve, which is an exponent curve with a
+ straight segment at the dark end and an overall response of
approximately gamma 2.2 (<span style="font-weight: bold;">-gs</span>),
the
@@ -2770,65 +2770,65 @@ the
-
- L* curve, which is the response of the CIE L*a*b* perceptual
- colorspace (<span style="font-weight: bold;">-gl</span>). the REC
- 709 video standard response curve (<span style="font-weight: bold;">-g709</span>)
- and the SMPTE 240M video standard response curve (<span
- style="font-weight: bold;">-g240</span>) <br>
- <br>
- <span style="font-weight: bold;">Note</span> that a real display
- can't reproduce any of these ideal curves, since it will have a
- non-zero black point, whereas all the ideal curves assume zero light
- at zero input. In the case of a gamma curve target, dispcal uses an
- actual technical power curve shape that aims for the same relative
- output at 50% input as the ideal gamma power curve. To allow for the
- non-zero black level of a real display, by default <span
- style="font-weight: bold;">dispcal</span> will offset the target
- curve values so that zero input gives the actual black level of the
- display (output offset). This ensures that the target curve better
- corresponds to the typical natural behavior of displays, but it may
- not be the most visually even progression from display minimum, but
- this behavior can be changed using the <span style="font-weight:
- bold;">-f</span> option (see below).<br>
- <br>
- <span style="font-weight: bold;">Also note</span> that many color
- spaces are encoded with, and labelled as having a gamma of
- approximately<span style="font-weight: bold;"> 2.2</span> (ie. sRGB,
- REC 709, SMPTE 240M, Macintosh OS X 10.6), but are actually intended
- to be displayed on a display with a typical CRT gamma of <span
- style="font-weight: bold;">2.4</span> viewed in a darkened
- environment. This is because this <span style="font-weight: bold;">2.2</span>
- gamma is a source gamma encoding in bright viewing conditions such
- as a television studio, while typical display viewing conditions are
- quite dark by comparison, and a contrast expansion of (approx.)
- gamma 1.1 is desirable to make the images look as intended. So if
- you are displaying images encoded to the sRGB standard, or
- displaying video through the calibration, just setting the gamma
- curve to sRGB or REC 709 (respectively) is probably <span
- style="font-weight: bold;">not what you want!</span> What you
- probably want to do, is to set the gamma curve to about gamma 2.4,
- so that the contrast range is expanded appropriately, or <span
- style="text-decoration: underline; font-weight: bold;">alternatively</span>
- use sRGB or REC 709 or a gamm of 2.2 but <span style="font-weight:
- bold;">also</span> use the <span style="font-weight: bold;">-a</span>
- parameter to specify the actual ambient viewing conditions, so that
- <span style="font-weight: bold;">dispcal</span> can make an
- appropriate contrast enhancement. If your instrument is capable of
- measuring ambient light levels, then you can do so during the
- interactive display control adjustment. See
- &lt;http://www.color.org/sRGB.xalter&gt; for details of how sRGB is
- intended to be used.<br>
- <br>
- It is hard to know whether Apple Macintosh computers prior to OS X
- 10.6 should also have such an adjustment, since it is not really
- possible to know whether colors labelled as being in such a
- colorspace are actually encoded in that gamma with the expectation
- that they will be displayed on a display with that actual response,
- or whether they are intended to be displayed on a display that
- contrast expands by a power 1.1.&nbsp; Both situations might be the
- case, depending on how source material is created!<br>
- <br>
+
+ L* curve, which is the response of the CIE L*a*b* perceptual
+ colorspace (<span style="font-weight: bold;">-gl</span>). the REC
+ 709 video standard response curve (<span style="font-weight: bold;">-g709</span>)
+ and the SMPTE 240M video standard response curve (<span
+ style="font-weight: bold;">-g240</span>) <br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that a real display
+ can't reproduce any of these ideal curves, since it will have a
+ non-zero black point, whereas all the ideal curves assume zero light
+ at zero input. In the case of a gamma curve target, dispcal uses an
+ actual technical power curve shape that aims for the same relative
+ output at 50% input as the ideal gamma power curve. To allow for the
+ non-zero black level of a real display, by default <span
+ style="font-weight: bold;">dispcal</span> will offset the target
+ curve values so that zero input gives the actual black level of the
+ display (output offset). This ensures that the target curve better
+ corresponds to the typical natural behavior of displays, but it may
+ not be the most visually even progression from display minimum, but
+ this behavior can be changed using the <span style="font-weight:
+ bold;">-f</span> option (see below).<br>
+ <br>
+ <span style="font-weight: bold;">Also note</span> that many color
+ spaces are encoded with, and labelled as having a gamma of
+ approximately<span style="font-weight: bold;"> 2.2</span> (ie. sRGB,
+ REC 709, SMPTE 240M, Macintosh OS X 10.6), but are actually intended
+ to be displayed on a display with a typical CRT gamma of <span
+ style="font-weight: bold;">2.4</span> viewed in a darkened
+ environment. This is because this <span style="font-weight: bold;">2.2</span>
+ gamma is a source gamma encoding in bright viewing conditions such
+ as a television studio, while typical display viewing conditions are
+ quite dark by comparison, and a contrast expansion of (approx.)
+ gamma 1.1 is desirable to make the images look as intended. So if
+ you are displaying images encoded to the sRGB standard, or
+ displaying video through the calibration, just setting the gamma
+ curve to sRGB or REC 709 (respectively) is probably <span
+ style="font-weight: bold;">not what you want!</span> What you
+ probably want to do, is to set the gamma curve to about gamma 2.4,
+ so that the contrast range is expanded appropriately, or <span
+ style="text-decoration: underline; font-weight: bold;">alternatively</span>
+ use sRGB or REC 709 or a gamm of 2.2 but <span style="font-weight:
+ bold;">also</span> use the <span style="font-weight: bold;">-a</span>
+ parameter to specify the actual ambient viewing conditions, so that
+ <span style="font-weight: bold;">dispcal</span> can make an
+ appropriate contrast enhancement. If your instrument is capable of
+ measuring ambient light levels, then you can do so during the
+ interactive display control adjustment. See
+ &lt;http://www.color.org/sRGB.xalter&gt; for details of how sRGB is
+ intended to be used.<br>
+ <br>
+ It is hard to know whether Apple Macintosh computers prior to OS X
+ 10.6 should also have such an adjustment, since it is not really
+ possible to know whether colors labelled as being in such a
+ colorspace are actually encoded in that gamma with the expectation
+ that they will be displayed on a display with that actual response,
+ or whether they are intended to be displayed on a display that
+ contrast expands by a power 1.1.&nbsp; Both situations might be the
+ case, depending on how source material is created!<br>
+ <br>
<a name="G"></a><span style="font-weight: bold;">-G gamma</span>&nbsp;
As
@@ -2877,99 +2877,99 @@ As
-
- explained above, the gamma value provided to the <span
- style="font-weight: bold;">-g</span> option is used to set and
- actual response curve that makes an allowance for the non-zero black
- of the actual display, and will have the same relative output at 50%
- input as the ideal gamma power curve, and so best matches typical
- expectations. The <span style="font-weight: bold;">-G</span> option
- is an alternative that allows the <span style="font-weight: bold;">actual</span>
- power to be specified instead, meaning that when combined with the
- displays non-zero black value, the response at 50% input will
- probably not match that of the ideal power curve with that gamma
- value.<br>
- <br>
- <a name="f"></a><span style="font-weight: bold;">-f [degree]</span>:
- As explained in for the <span style="font-weight: bold;">-g</span>
- and <span style="font-weight: bold;">-G</span> options, real
- displays do not have a zero black response, while all the target
- response curves do, so this has to be allowed for in some way. The
- default way of handling this (equivalent to -f 1.0)&nbsp; is to
- allow for this at the output of the ideal response curve, by
- offsetting and scaling the output values.<span style="font-weight:
- bold;"></span> This defined a curve that will match the responses
- that many other systems provide and may be a better match to the
- natural response of the display, but will give a less visually even
- response from black<span style="font-weight: bold;"></span>. The
- other alternative is to offset and scale the input values into the
- ideal response curve so that zero input gives the actual non-zero
- display response. This ensures the most visually even progression
- from display minimum, but might be hard to achieve since it is
- different to the naturally response of a display. A subtlety is to
- provide a split between how much of the offset is accounted for as
- input to the ideal response curve, and how much is accounted for at
- the output, and this can be done by providing a parameter <span
- style="font-weight: bold;">-f degree</span>, where the degree is
- 0.0 accounts for it all as input offset, and 1.0 accounts for all of
- it as output offset. If <span style="font-weight: bold;">-f</span>
- is used without a specified degree, a degree of 0.0 is assumed, the
- opposite of the default. <span style="font-weight: bold;">Note</span>
- that using all input offset (degree == 0.0) is equivalent to the use
- of the <span style="font-weight: bold;">BT.1886</span> transfer
- function.<br>
- <br>
- <a name="a"></a><span style="font-weight: bold;">-a ambient</span>:
- As explained for the <span style="font-weight: bold;">-g</span>
- parameter, often colors are encoded in a situation with viewing
- conditions that are quite different to the viewing conditions of a
- typical display, with the expectation that this difference in
- viewing conditions will be allowed for in the way the display is
- calibrated. The <span style="font-weight: bold;">-a</span> option
- is a way of doing this. By default <span style="font-weight: bold;">dispcal</span>
- will not make any allowances for viewing conditions, but will
- calibrate to the specified response curve, but if the <span
- style="font-weight: bold;">-a</span> option is used, or the
- ambient level is measured during the interactive display controls
- portion of the calibration, an appropriate viewing conditions
- adjustment will be performed. For a gamma value or sRGB, the
- original viewing conditions will be assumed to be that of the sRGB
- standard viewing conditions, while for REC 709 and SMPTE 240M they
- will be assumed to be television studio viewing conditions. By
- specifying or measuring the ambient lighting for your display, a
- viewing conditions adjustment based on the CIECAM02 color appearance
- model will be made for the brightness of&nbsp; your display and the
- contrast it makes with your ambient light levels. <br>
- <br>
- <a name="k"></a><span style="font-weight: bold;">-k factor</span>:
- Normally this will be set automatically, based on the measured black
- level of the display. A <span style="font-weight: bold;">-k</span>
- factor of 1.0 will make all colors down the neutral axis (R=G=B)
- have the same hue as the chosen white point. Near the black point,
- red, green or blue can only be added, not subtracted from zero, so
- the process of making the near black colors have the desired hue,
- will <span style="font-weight: bold;">lighten</span> them to some
- extent. For a device with a good contrast ratio or a black point
- that has nearly the same hue as the white, this should not affect
- the contrast ratio too severely. If the device contrast ratio is not
- so good, and the native black hue is noticeably different to that of
- the chosen white point (which is often the case for <span
- style="font-weight: bold;">LCD</span> type displays, or <span
- style="font-weight: bold;">CRT</span> type displays with one
- channel which has a poor level of black), this could have a
- noticeably detrimental effect on an already limited contrast ratio,
- and result in a black that is not as good as it can be, and a lower
- <span style="font-weight: bold;">-k</span> factor should be used. <span
- style="font-weight: bold;">-k</span> values can range between 0.0
- (no correction of black) to 1.0 (full correction of black). If less
- than full correction is chosen, then the resulting calibration
- curves will have the target white point down most of the curve, but
- will then blend over to the native or compromise black point that is
- blacker, but not of the right hue. The rate of this blend can be
- controlled with the <span style="font-weight: bold;">-A</span>
- parameter (see below). For applications where maximum contrast ratio
- is important (such as <b>Video</b>), use <b>-k0</b>. <br>
- <br>
+
+ explained above, the gamma value provided to the <span
+ style="font-weight: bold;">-g</span> option is used to set and
+ actual response curve that makes an allowance for the non-zero black
+ of the actual display, and will have the same relative output at 50%
+ input as the ideal gamma power curve, and so best matches typical
+ expectations. The <span style="font-weight: bold;">-G</span> option
+ is an alternative that allows the <span style="font-weight: bold;">actual</span>
+ power to be specified instead, meaning that when combined with the
+ displays non-zero black value, the response at 50% input will
+ probably not match that of the ideal power curve with that gamma
+ value.<br>
+ <br>
+ <a name="f"></a><span style="font-weight: bold;">-f [degree]</span>:
+ As explained in for the <span style="font-weight: bold;">-g</span>
+ and <span style="font-weight: bold;">-G</span> options, real
+ displays do not have a zero black response, while all the target
+ response curves do, so this has to be allowed for in some way. The
+ default way of handling this (equivalent to -f 1.0)&nbsp; is to
+ allow for this at the output of the ideal response curve, by
+ offsetting and scaling the output values.<span style="font-weight:
+ bold;"></span> This defined a curve that will match the responses
+ that many other systems provide and may be a better match to the
+ natural response of the display, but will give a less visually even
+ response from black<span style="font-weight: bold;"></span>. The
+ other alternative is to offset and scale the input values into the
+ ideal response curve so that zero input gives the actual non-zero
+ display response. This ensures the most visually even progression
+ from display minimum, but might be hard to achieve since it is
+ different to the naturally response of a display. A subtlety is to
+ provide a split between how much of the offset is accounted for as
+ input to the ideal response curve, and how much is accounted for at
+ the output, and this can be done by providing a parameter <span
+ style="font-weight: bold;">-f degree</span>, where the degree is
+ 0.0 accounts for it all as input offset, and 1.0 accounts for all of
+ it as output offset. If <span style="font-weight: bold;">-f</span>
+ is used without a specified degree, a degree of 0.0 is assumed, the
+ opposite of the default. <span style="font-weight: bold;">Note</span>
+ that using all input offset (degree == 0.0) is equivalent to the use
+ of the <span style="font-weight: bold;">BT.1886</span> transfer
+ function.<br>
+ <br>
+ <a name="a"></a><span style="font-weight: bold;">-a ambient</span>:
+ As explained for the <span style="font-weight: bold;">-g</span>
+ parameter, often colors are encoded in a situation with viewing
+ conditions that are quite different to the viewing conditions of a
+ typical display, with the expectation that this difference in
+ viewing conditions will be allowed for in the way the display is
+ calibrated. The <span style="font-weight: bold;">-a</span> option
+ is a way of doing this. By default <span style="font-weight: bold;">dispcal</span>
+ will not make any allowances for viewing conditions, but will
+ calibrate to the specified response curve, but if the <span
+ style="font-weight: bold;">-a</span> option is used, or the
+ ambient level is measured during the interactive display controls
+ portion of the calibration, an appropriate viewing conditions
+ adjustment will be performed. For a gamma value or sRGB, the
+ original viewing conditions will be assumed to be that of the sRGB
+ standard viewing conditions, while for REC 709 and SMPTE 240M they
+ will be assumed to be television studio viewing conditions. By
+ specifying or measuring the ambient lighting for your display, a
+ viewing conditions adjustment based on the CIECAM02 color appearance
+ model will be made for the brightness of&nbsp; your display and the
+ contrast it makes with your ambient light levels. <br>
+ <br>
+ <a name="k"></a><span style="font-weight: bold;">-k factor</span>:
+ Normally this will be set automatically, based on the measured black
+ level of the display. A <span style="font-weight: bold;">-k</span>
+ factor of 1.0 will make all colors down the neutral axis (R=G=B)
+ have the same hue as the chosen white point. Near the black point,
+ red, green or blue can only be added, not subtracted from zero, so
+ the process of making the near black colors have the desired hue,
+ will <span style="font-weight: bold;">lighten</span> them to some
+ extent. For a device with a good contrast ratio or a black point
+ that has nearly the same hue as the white, this should not affect
+ the contrast ratio too severely. If the device contrast ratio is not
+ so good, and the native black hue is noticeably different to that of
+ the chosen white point (which is often the case for <span
+ style="font-weight: bold;">LCD</span> type displays, or <span
+ style="font-weight: bold;">CRT</span> type displays with one
+ channel which has a poor level of black), this could have a
+ noticeably detrimental effect on an already limited contrast ratio,
+ and result in a black that is not as good as it can be, and a lower
+ <span style="font-weight: bold;">-k</span> factor should be used. <span
+ style="font-weight: bold;">-k</span> values can range between 0.0
+ (no correction of black) to 1.0 (full correction of black). If less
+ than full correction is chosen, then the resulting calibration
+ curves will have the target white point down most of the curve, but
+ will then blend over to the native or compromise black point that is
+ blacker, but not of the right hue. The rate of this blend can be
+ controlled with the <span style="font-weight: bold;">-A</span>
+ parameter (see below). For applications where maximum contrast ratio
+ is important (such as <b>Video</b>), use <b>-k0</b>. <br>
+ <br>
<a name="A"></a><span style="font-weight: bold;">-A rate</span>:&nbsp;
If
@@ -3018,641 +3018,641 @@ If
-
- the black point is not being set completely to the same hue as the
- white point (ie. because the <span style="font-weight: bold;">-k</span>
- factor is less than 1.0), then the resulting calibration curves will
- have the target white point down most of the curve, but will then
- blend over to the native or compromise black point that is blacker,
- but not of the right hue. The rate of this blend can be controlled
- with the <span style="font-weight: bold;">-A</span> parameter. The
- default value 4.0, which results in a target that switches from the
- white point target to the black, moderately close to the black
- point. While this typically gives a good visual result with the
- target neutral hue being maintained to the point where the crossover
- to the black hue is not visible, it may be asking too much of some
- displays (typically LCD type displays), and there may be some visual
- effects due to inconsistent color with viewing angle. For this
- situation a smaller value may give a better visual result (e.g. try
- values of 3.0 or 2.0. A value of 1.0 will set a pure linear blend
- from white point to black point). If there is too much coloration
- near black, try a larger value, e.g. 6.0 or 8.0.<br>
- <br>
- <a name="bhack"></a>The <b>-b</b> flag forces source 0,0,0 to map
- to destination 0,0,0. This may be useful with displays that have a
- very dark black point, and with an instrument is unable to measure
- it precisely, and where it is known in some other way that the
- display is <u>very well behaved</u> from black (i.e. that it has no
- "dead zone" above zero device input). Using this option with a
- display that is <u>not</u> well behaved, may result in a loss of
- shadow detail. This will override any <b>-k</b> factor.<br>
- <br>
- <a name="B"></a><span style="font-weight: bold;">-B</span>&nbsp; Set
- the target brightness of black in cd/m^2 (i.e. the absolute Y
- value). Setting too high a value may give strange results as it
- interacts with trying to achieve the target "advertised" gamma curve
- shape. You could try using -f 1 if this causes a problem.<br>
- <br>
- <a name="e"></a><span style="font-weight: bold;">-e [n]</span> Run <span
- style="font-weight: bold;">n</span> verify passes on the final
- curves. This is an extra set of instrument readings, that can be
- used to estimate how well the device will match the targets with the
- computed calibration curves. Note that the usefulness of the
- verification is sometimes limited by the repeatability of the device
- &amp; instrument readings. This is often evident for CRT displays,
- which (due to their refresh rate) flicker. More than one
- verification pass can be done by providing the parameter <span
- style="font-weight: bold;">n</span>, and by then comparing the
- successive verifications, some idea of the repeatability can be
- ascertained. The verification uses a fixed number of semi-random
- test values to test the calibration.<br>
- <br>
- <a name="z"></a><span style="font-weight: bold;">-z</span> Run
- verify pass on the display as it is currently setup (currently
- installed LUT curves). This will use the usual input parameters to
- establish the expected (target) characteristic. <span
- style="font-weight: bold;">Note</span> that if the initial
- calibration was modified due to it being out of gamut of the
- display, verify will show the resulting discrepancy. You can use <a
- href="dispwin.html">dispwin</a> to load a <span
- style="font-weight: bold;">.cal</span> file into the display
- before running dispcal <span style="font-weight: bold;">-z</span>.
- Note that if you set an Ambient light level interactively during the
- calibration, you need to enter the same number that was measured and
- set using the <span style="font-weight: bold;">-a</span> parameter
- for verify.<br>
- <br>
- <a name="P"></a> The <span style="font-weight: bold;">-P</span>
- parameter allows you to position and size the test patch window. By
- default it is places in the center of the screen, and sized
- appropriately for the type of instrument, or 10% of the width of the
- display if the display size is unknown.. The <span
- style="font-weight: bold;">ho</span> and <span
- style="font-weight: bold;">vo</span> values govern the horizontal
- and vertical offset respectively. A value of 0.0 positions the
- window to the far left or top of the screen, a value of 0.5
- positions it in the center of the screen (the default), and 1.0
- positions it to the far right or bottom of the screen. If three
- parameters are provided, then the <span style="font-weight: bold;">ss</span>
- parameter is a scale factor for the test window size. A value of 0.5
- for instance, would produce a half sized window. A value of 2.0 will
- produce a double size window. If four parameters are provided, then
- the last two set independent horizontal and vertical scaling
- factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
- specified as a single string (no space between the numbers and the
- comma). For example, to create a double sized test window at the top
- right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
- . To create a window twice as wide as high: <span
- style="font-weight: bold;">-P 1,0,2,1</span>.<br>
- <br>
- <a name="F"></a> The <span style="font-weight: bold;">-F</span>
- flag causes the while screen behind the test window to be masked
- with black. This can aid black accuracy when measuring CRT displays
- or projectors.<br>
- <br>
- <a name="E"></a> The <span style="font-weight: bold;">-E</span>
- flag causes the display test values to be scaled to the Video RGB
- encoding range of (16-235)/255. This also modifies the resulting
- calibration curve behavior downstream of dispcal. If a calibration
- curve created using -E gets installed or converted to an ICC profile
- 'vcgt' tag in the process of creating a profile in dispcal or
- colprof, the incoming full range values will first have the
- calibration curve applied and then be scaled to the Video encoding
- range (16-235)/255.<br>
- <br>
- <a name="n"></a><span style="font-weight: bold;">-n</span> When
- running on a UNIX based system that used the X11 Windowing System, <b>dispcal</b>
- normally selects the override redirect so that the test window will
- appear above any other windows on the display. On some systems this
- can interfere with window manager operation, and the <b>-n</b>
- option turns this behaviour off.<br>
- <br>
- <a name="J"></a> The -<span style="font-weight: bold;">J</span>
- option runs through the black and sensor relative calibration
- routines for the Xrite DTP92 and DTP94 instruments, the black level
- calibration for the Eye-One Display 1, and a CRT frequency
- calibration for the Eye-One Display 2. For the black calibration the
- instrument should be placed on an opaque, black surface, and any
- stray light should be avoided by placing something opaque over the
- instrument. If a Spectrolino is being used, then a white and black
- calibration will always be performed before the instrument can be
- placed on the display, unless the <a href="dispcal.html#N">-N</a>
- flag is used. Generally it is not necessary to do a calibration
- every time an instrument is used, just now and again. There is also
- no point in doing&nbsp; a CRT frequency calibration, as this will be
- done automatically at the commencement of patch reading, and will be
- lost between runs.<br>
- <br>
- <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
- instrument that requires regular calibration will ask for
- calibration on initial start-up. Sometimes this can be awkward if
- the instrument is being mounted in some sort of measuring jig, or
- annoying if several sets of readings are being taken in quick
- succession. The -<span style="font-weight: bold;">N</span>
- suppresses this initial calibration if a valid and not timed out
- previous calibration is recorded in the instrument or on the host
- computer. It is advisable to only use this option on the second and
- subsequent measurements in a single session.<br>
- <br>
- <a name="H"></a> The -<span style="font-weight: bold;">H</span>
- option turns on high resolution spectral mode, if the instrument
- supports it, such as the Eye-One Pro. See <a
- href="instruments.html">Operation of particular instruments</a>
- for more details. This may give better accuracy for display
- measurements.<br>
- <br>
- <a name="X1"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccmx</span></span> option reads
- a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
- from the given file, and applies it to the colorimeter instruments
- readings. This can improve a colorimeters accuracy for a particular
- type of display. A list of contributed <span style="font-weight:
- bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
- <br>
- <a name="X2"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccss</span></span> option reads
- a <a href="File_Formats.html#.ccss">Colorimeter Calibration
- Spectral Sample</a> from the given file, and uses it to set the
- colorimeter instruments calibration. This will only work with
- colorimeters that rely on sensor spectral sensitivity calibration
- information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
- or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
- Spyder 5</span>).This can improve a colorimeters accuracy for a
- particular type of display.<br>
- <br>
- <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
- observer, and is used to compute PCS (Profile Connection Space)
- tristimulus values from spectral readings or using a colorimeter
- that has CCSS capability. The following choices are available:<br>
- <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
- observer. The default.<br>
- &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
- observer.<br>
- &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
- observer<br>
- &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
- observer<br>
- &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
- observer<br>
- &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
- observer that has been adjusted using a 3x3 matrix to better agree
- with the 1931 2 degree observer.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that if you select
- anything other than the default 1931 2 degree observer, that the Y
- values will not be cd/m^2, due to the Y curve not being the CIE 1924
- photopic V(&#955;) luminosity function.<br>
- <br>
- <a name="I"></a> The -<span style="font-weight: bold;">I <span
- style="font-style: italic;">b|w</span></span> options invoke
- instrument black level, and display white level compensation
- (respectively). Instrument black level drift compensation attempts
- to combat instrument black calibration drift by using a display
- black test patch as a reference. If an instrument is not
- acclimatised sufficiently to the measurement conditions, changes in
- temperature can affect the black readings. Display white level drift
- compensation attempts to combat changes in display brightness as it
- warms up by measuring a white patch every so often, and using it to
- normalise all the other readings. If just instrument black drift
- compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
- If just display white level compensation is needed, use <span
- style="font-weight: bold;">-Iw</span>. If both are needed, use <span
- style="font-weight: bold;">-Ibw</span> or <span
- style="font-weight: bold;">-Iwb</span>.<span style="font-weight:
- bold;"> </span><br>
- <br>
- <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
- options overrides calibration of the instrument refresh rate. This
- may be useful if the instrument supports this function and the
- refresh rate cannot be accurately calibrated from the display
- itself.<br>
- <br>
- <a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
- option uses a non-adaptive integration time emission measurement
- mode, if the instrument supports it, such as the Eye-One Pro,
- ColorMunki, i1d3 and K10. By default an adaptive integration time
- measurement mode will be used for emission measurements, but some
- instruments support a fixed integration time mode that can be used
- with display devices. This may give faster measurement times, but
- may also give less accurate low level readings.<br>
- <br>
- <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
- option skips asking the user to place the instrument on the display.
- Normally a grey patch is displayed, and then the user is asked to
- confirm that the instrument is in place, so that readings can
- commence. This flag disables that check. This may be useful in
- automating certain operations.<br>
- <br>
- <a name="C"></a> The -<span style="font-weight: bold;">C</span> <span
- style="font-weight: bold;">"command" </span>option allows a
- method of relaying each test value to some other display than that
- on the system running dispcal (for instance, a photo frame, PDA
- screen etc.), by causing the given command to be invoked to the
- shell, with six arguments. The first three arguments are the RGB
- test color as integers in the range 0 to 255, the second three
- parameters are the RGB test color as floating point numbers in the
- range 0.0 to 1.0. The script or tool should relay the given color to
- the screen in some manner (e.g. by generating a raster file of the
- given color and sending it to the display being profiled), before
- returning. Note that a test window will also be created on the
- system running dispread.<br>
- <br>
- <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
- style="font-weight: bold;">"command" </span>option allows a
- method of gathering each test value from some external source, such
- as an instrument that is not directly supported by Argyll. The given
- command is involked to the shell, with six arguments. The first
- three arguments are the RGB test color as integers in the range 0 to
- 255, the second three parameters are the RGB test color as floating
- point numbers in the range 0.0 to 1.0. The script or tool should
- create a file called <span style="font-weight: bold;">"command.meas</span>"
- that contains the XYZ values for the given RGB (or measured from the
- test window) in cd/m^2 as three numbers separated by spaces, before
- returning. If the command returns a non-zero return value, dispcal
- will abort. Note that a test window will also be created on the
- system running dispcal.<br>
- <br>
- <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
- parameter overrides the default serial communications flow control
- setting. The value <span style="font-weight: bold;">n</span> turns
- all flow control off, <span style="font-weight: bold;">h</span>
- sets hardware handshaking, and <span style="font-weight: bold;">x</span>
- sets Xon/Xoff handshaking. This commend may be useful in workaround
- serial communications issues with some systems and cables. <br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes communications and other
- instrument diagnostics to be printed to stdout. A level can be set
- between 1 .. 9, that may give progressively more verbose
- information, depending on the instrument. This can be useful in
- tracking down why an instrument can't connect.<br>
- <br>
- <a name="p1"></a><span style="font-weight: bold;">inoutfile</span>
- The final parameter on the command line is the base filename for the
- <a href="cal_format.html">.cal</a> file and the optional ICC
- profile. Normally this will be created (or an existing file will be
- overwritten). If the <span style="font-weight: bold;">-u</span>
- flag is used, then these files will be updated. If a different ICC
- profile name needs to be specified, do so as an argument to the <span
- style="font-weight: bold;">-o</span> flag.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that on an X11 system,
- if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
- is set (ie. set it to "yes"), then the presence of the XRandR 1.2
- extension will be ignored, and other extensions such as Xinerama and
- XF86VidMode extension will be used. This may be a way to work around
- buggy XRandR 1.2 implementations.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h2><a name="Adjustment"></a>Discussion and guide to display control
- adjustment:</h2>
- <br>
- The adjustment of the display controls (brightness, contrast, R, G
- &amp; B channel controls etc.) is very dependent on the particular
- monitor. Different types and brands of monitors will have different
- controls, or controls that operate in different ways. Some displays
- have almost no user controls, and so you may well be best skipping
- display adjustment, and going straight to calibration.<br>
- <br>
- Almost all LCD displays lack a real <span style="font-weight:
- bold;">contrast</span> control. Those that do present such a
- control generally fake it by adjusting the video signal. For this
- reason it is usually best to set an LCD's <span style="font-weight:
- bold;">contrast</span> control at its neutral setting (ie. the
- setting at which it doesn't change the video signal). Unfortunately,
- it can be hard to know what this neutral setting is. On some
- displays it is 50%, others 75%. If the LCD display has a "reset to
- factory defaults" mode, then try using this first, as a way of
- setting the <span style="font-weight: bold;">contrast</span>
- control to neutral. The LCD <span style="font-weight: bold;">brightness</span>
- control generally adjusts the level of backlighting the display
- gets, which affects the maximum brightness, and also tends to raise
- or lower the black level in proportion, without changing the
- displays response curve shape or overall contrast ratio. If your LCD
- display has a <span style="font-weight: bold;">backlight</span>
- control as well as a <span style="font-weight: bold;">brightness</span>
- control, then the brightness control is also probably being faked,
- and you are probably better off setting it to it's neutral setting,
- and using the <span style="font-weight: bold;">backlight</span>
- control in place of <span style="font-weight: bold;">brightness</span>
- in the following adjustments.<br>
- <br>
- Some high end displays have the ability to mimic various standard
- colorspaces such as sRGB or AdobeRGB. You could choose to calibrate
- and profile the display in such an emulation mode, although you
- probably don't want to fight the emulations white point and gamma.
- To get the best out of such a display you really want to choose it's
- "Native Gamut" setting, whatever that is called. Note that some
- people have reported bad experiences in trying to use "6-axis custom
- controls" on displays such as the Dell U2410, so attempting to use
- such a mode should be approached with caution. Ideally such a mode
- should be used to give just the underlying native display response,
- but the settings to achieve this may be very difficult to determine,
- and/or it may not be possible, depending on how such a mode distorts
- the RGB signals.<br>
- <br>
- On CRT based displays, the <span style="font-weight: bold;">brightness</span>
- control generally adjusts the black level of the display (sometimes
- called the <span style="font-weight: bold;">offset</span>), and as
- a side effect, tends to change the maximum brightness too. A CRT <span
- style="font-weight: bold;">contrast</span> control generally
- adjusts the maximum brightness (sometimes called <span
- style="font-weight: bold;">gain</span>) without affecting the
- black level a great deal. On a CRT both the <span
- style="font-weight: bold;">brightness</span> and <span
- style="font-weight: bold;">contrast</span> controls will tend to
- affect the shape or gamma of the display response curve.<br>
- <br>
- Many displays have some sort of color temperature adjustment. This
- may be in the form of some pre-set color temperatures, or in the
- form of individual Red, Green and Blue channel gain adjustments.
- Some CRT displays also have R, G &amp; B channel offset adjustments
- that will affect the color temperatures near black, as well as
- affect the individual channels curve shape. The color temperature
- adjustment will generally affect the maximum brightness, and may
- also affect the black level and the shape of the display response
- curves.<br>
- <br>
- Some special (expensive) LCD displays may have a white point
- adjustment that changes the color of the backlight. If you do not
- have one of these types of LCD displays, then attempting to change
- the white point of the display (even if it appears to have a "<span
- style="font-weight: bold;">white point selection</span>" or <span
- style="font-weight: bold;">R/G/B</span> "<span style="font-weight:
- bold;">gain</span>" controls") may not be a good idea, as once
- again these controls are probably being faked by manipulating the
- signal levels. Even if you do manage to change the white point
- significantly, it may do things like change the mid tone color too
- dramatically, or create a display response that is hard to correct
- with calibration, or results in side effects such as quantization
- (banding) or other undesirable effects. You may have to try out
- various controls (and your aim points for the display calibration),
- to decide what is reasonable to attempt on an LCD display.<br>
- <br>
- Due to the variety of controls as well as the interaction between
- them, it can be an iterative process to arrive at a good monitor
- set-up, before proceeding on to calibrating and profiling a display.
- For this reason, <span style="font-weight: bold;">dispcal</span>
- offers a menu of adjustment modes, so that the user can
- interactively and iteratively adjust the display controls to meet
- the desired targets.<br>
- <br>
- &nbsp; 1) Black level (CRT: Brightness)<br>
- &nbsp; 2) White point (Color temperature, R,G,B, Gain/Contrast)<br>
- &nbsp; 3) White level (CRT: Gain/Contrast, LCD:
- Brightness/Backlight)<br>
- &nbsp; 4) Black point (R,G,B, Offset/Brightness)<br>
- &nbsp; 5) Check all<br>
- &nbsp; 6) Measure and set ambient for viewing condition adjustment<br>
- &nbsp; 7) Continue on to calibration<br>
- &nbsp; 8) Exit<br>
- <br>
- There are four basic adjustment modes. Normally one would proceed
- through them in the order above, then perhaps repeat the first
- adjustment, before checking the overall settings. The White point
- and White level modes operate slightly differently, depending on
- whether a white target point has been set using the <span
- style="font-weight: bold;">-t -T</span> or <span
- style="font-weight: bold;">-w</span> options, and on whether a
- brightness target has been set using the <span style="font-weight:
- bold;">-b</span> option.<br>
- <br>
- <br>
- The first mode lets you adjust the black level of a CRT display.
- Given the current white level, it calculates a value that should
- produce a 1% display brightness if the black level is set correctly.
- After doing some initial measurements, it will show the target
- brightness value (in cd/m^2) on one line, and then underneath it
- will show continuously updated readings from the display. The left
- most character will switch from '\' to '/' or back again each time a
- reading is updated. Some instruments can be quite slow in measuring
- dark colors, and it's best to wait for a reading update before
- changing the controls more than once. Underneath the target value is
- displayed the current reading, and to the right of this is a '+',
- '-' or '=' symbol, which gives a hint as to which way to adjust the
- brightness control to improve the match to the target.<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">&nbsp; Adjust CRT brightness to get target level.
- Press space when done.</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp; Target
- 0.60</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; / Current 0.68&nbsp;
- -</span></small><br>
- <br>
- Once happy with the adjustment, press space to go back to the menu.<br>
- <br>
- <br>
- The second mode lets you adjust the color of the white point of the
- display. If a target white point has been set, it will show the
- target brightness value (in cd/m^2) on one line, together with the
- target chromaticity co-ordinates for the white point, and then
- underneath it will show continuously updated readings from the
- display. The left most character will switch from '\' to '/' or back
- again each time a reading is updated. Underneath the target
- brightness value is displayed the current reading, and then the
- current chromaticity co-ordinate values. To the right of this is the
- current delta E of the white point from the target, and further to
- the right are hints '+', '-' or '='&nbsp; as to which direction to
- adjust the individual Red, Green and Blue gain settings to move the
- white point in the direction of the target, and reduce the delta E.
- If the symbol is doubled, then this channel will have the greatest
- effect. If you do not have individual channel gain controls, then
- try choosing amongst color temperature pre-sets, to find one with
- the lowest delta E. Depending on the stability of the display, the
- coarseness of the controls, and the repeatability of the instrument,
- you may not be able to get a perfectly zero delta E.<br>
- <br>
- &nbsp;&nbsp; <small style="font-weight: bold;"><span
- style="font-family: monospace;">Adjust R,G &amp; B gain to get
- target x,y. Press space when done.<br>
- &nbsp;&nbsp; &nbsp; Target B 60.00, x 0.3451, y 0.3516<br>
- &nbsp; / Current B 60.05, x 0.3426, y 0.3506&nbsp; DE&nbsp;
- 1.4&nbsp; R+&nbsp; G+&nbsp; B--</span><span style="font-family:
- monospace;"></span></small><br>
- <br>
- If you did not set a white point target, then the information shown
- is a little different - it will show the initial white point value,
- as well as the color temperature, and the CIEDE2000 of the white
- point to either the Daylight or Black Body locus (depending on
- whether the <span style="font-weight: bold;">-T</span> flag was
- set). The constantly updated values show the same thing, and the
- Red, Green and Blue control hints show the direction to adjust the
- controls to place the white point on the locus. The control that
- will have the most direct effect on the color temperature will be
- the Blue, while the Green will most directly move the white point
- towards or away from the locus, thereby reducing the delta E of the
- white point to the locus (but there is interaction).<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">Adjust R,G &amp; B gain to desired white point.
- Press space when done.</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Initial B 47.25, x
- 0.3417, y 0.3456, CDT 5113 DE&nbsp; 6.9</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">\ Current B 47.38, x 0.3420,
- y 0.3460&nbsp; CDT 5104 DE&nbsp; 6.7&nbsp; R-- G+&nbsp; B-</span></small><br>
- <br>
- &nbsp;The brightness value is just there as a guide to what effect
- the adjustment is having on the overall brightness. Usually the
- white level brightness is adjusted using the next adjustment mode.
- Once happy with the adjustment, press space to go back to the menu.<br>
- <br>
- <br>
- The third mode lets you adjust the brightness of white on the
- display. If you set a target brightness using the <span
- style="font-weight: bold;"><span style="font-weight: bold;">-b</span></span>
- parameter, it will show the target brightness value (in cd/m^2) on
- one line, and then underneath it will show continuously updated
- readings from the display. The left most character will switch from
- '\' to '/' or back again each time a reading is updated. Underneath
- the target value is displayed the current reading, and to the right
- of this is a '+', '-' or '=' symbol, which gives a hint as to which
- way to adjust the CRT contrast or LCD brightness control to improve
- the match to the target.<br>
- <br>
- &nbsp;&nbsp; <small style="font-weight: bold;"><span
- style="font-family: monospace;">Adjust CRT Contrast or LCD
- Brightness to get target level. Press space when done.<br>
- &nbsp;&nbsp; &nbsp; Target 60.00<br>
- &nbsp; / Current 59.96&nbsp; +</span><span style="font-family:
- monospace;"></span></small><br>
- <br>
- If you did not set a brightness target, it will show the initial
- brightness as the target, and the current brightness, which you can
- then set any way you want:<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">Adjust CRT Contrast or LCD Brightness to desired
- level. Press space when done.</span><br style="font-family:
- monospace;">
- <span style="font-family: monospace;">&nbsp; Initial 47.32</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">/ Current 47.54</span></small><br>
- <br>
- Once happy with the adjustment, press space to go back to the menu.<br>
- <br>
- <br>
- The fourth mode lets you adjust the color of the black point of the
- display, if the display has Red, Green and Blue channel offset
- controls. It will show the target 1% brightness value (in cd/m^2) on
- one line, together with the target chromaticity co-ordinates for the
- black point, and then underneath it will show continuously updated
- readings from the display. The left most character will switch from
- '\' to '/' or back again each time a reading is updated. Underneath
- the target brightness value is displayed the current reading, and
- then the current chromaticity co-ordinate values. To the right of
- this is the current delta E of the black point from the target, and
- further to the right are hints '+', '-' or '='&nbsp; as to which
- direction to adjust the individual Red, Green and Blue offset
- settings to move the black point in the right direction. If the
- symbol is doubled, then this channel will have the greatest effect.
- <br>
- <br>
- <span style="font-family: monospace;"><span style="font-weight:
- bold;">&nbsp; Adjust R,G &amp; B offsets to get target x,y.
- Press space when done.<br>
- &nbsp;&nbsp; &nbsp; Target B 0.60, x 0.3451, y 0.3516<br>
- &nbsp; \ Current B 0.62, x 0.2782, y 0.2331&nbsp; DE&nbsp;
- 10.3&nbsp; R+&nbsp; G++ B-</span></span><small
- style="font-weight: bold;"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></small><br>
- <br>
- The 1%&nbsp; brightness value is just there as a guide to what
- effect the adjustment is having on the 1% brightness level. The
- combined channel offsets may have an effect on this in combination
- with the CRT brightness control. Press space to go back to the menu.<br>
- <br>
- <br>
- The fifth selection checks on the overall settings.&nbsp; If targets
- have been set, it will be like:<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">&nbsp; Target Brightness = 50.00, Current = 47.44,
- error = -5.1%<br>
- &nbsp; Target 50% Level&nbsp; = 10.32, Current =&nbsp; 8.10,
- error = -4.4%<br>
- &nbsp; Target Near Black =&nbsp; 0.47, Current =&nbsp; 0.68,
- error =&nbsp; 0.4%<br>
- &nbsp; Target white = x 0.3458, y 0.3586, Current = x 0.3420, y
- 0.3454, error =&nbsp; 7.55 DE<br>
- &nbsp; Target black = x 0.3458, y 0.3586, Current = x 0.2908, y
- 0.2270, error = 29.69 DE</span><span style="font-family:
- monospace;"></span></small><br>
- <br>
- or if no targets are set:<br>
- <br>
- <small style="font-weight: bold;"><span style="font-family:
- monospace;">&nbsp; Current Brightness = 46.28</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Target 50%
- Level&nbsp; = 10.07, Current =&nbsp; 7.52, error = -5.5%</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Target Near Black
- =&nbsp; 0.46, Current =&nbsp; 0.46, error = -0.0%</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Current white = x
- 0.3439, y 0.3466, VCT 5098K DE&nbsp; 3.0</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp; Target black = x
- 0.3439, y 0.3466, Current = x 0.3093, y 0.2165, error = 30.30 DE</span></small><br>
- <br>
- and will then go back to the menu.<br>
- <br>
- The sixth selection <span style="font-weight: bold;">6)</span>
- allows the reading of you ambient lighting conditions if your
- instrument supports such a mode. Doing so will enable the <span
- style="font-weight: bold;">-a</span> option to compensate for your
- viewing conditions in the subsequent calibration. See <a
- href="dispcal.html#a">-a</a>.<br>
- <br>
- Once&nbsp; you're happy with the display set-up, you can either
- proceed on to the rest of the calibration by selecting <span
- style="font-weight: bold;">7)</span>, or exit and re-start by
- selecting <span style="font-weight: bold;">8)</span>. You might
- want to re-start if you want to change the calibration targets.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h2>Other caveats:</h2>
- NOTE that some <span style="font-weight: bold;">LCD</span> screens
- behave a little strangely near their absolute white point, and may
- therefore exhibit odd behavior at values just below white. It may be
- advisable in such cases to set a brightness slightly less than the
- maximum such a display is capable of.<br>
- <br>
- The program attempts to stop any screensaver or powersaver from
- interfering with the measurements, but this may not be effective on
- some systems, so it may be necessary to manually disable the
- screensaver and/or powersaver before commencing the calibration with
- a large number of patches.<br>
- <br>
- The calibration tables produced maintain the maximum level of
- precision available on a system. If the display has VideoLUTs
- available (Video Lookup Tables that the frame buffer values pass
- through on their way to the display) and thier outputs are better
- than 8 bits per component, then the resulting curves can reflect
- this, although few current operating systems and/or display cards
- actually support better than 8 bit per component output.<br>
- <br>
- If calibration curves are created for a display in which VideoLUTs
- are not available, then the resulting calibration file will be
- marked to indicate this, and a subsequent profile created with the
- calibration will not have the calibration converted to the 'vcgt'
- tag, since such a tag can't be loaded into the displays VideoLUTs.<br>
- <br>
- If communications break down with a USB connected instrument, you
- may have to unplug it, and plug it in again to recover operation.<br>
- <br>
- Some systems (Apple OS X in particular) have a special set of user
- interface controls ("Universal Access") that allows altering the
- display in ways designed to assist visually impaired users, by
- increasing contrast etc. This will interfere badly with any attempts
- to calibrate or profile such a system, and must be turned off in
- order to do so. Note that certain magic keyboard sequences can turn
- this on by accident.<br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ the black point is not being set completely to the same hue as the
+ white point (ie. because the <span style="font-weight: bold;">-k</span>
+ factor is less than 1.0), then the resulting calibration curves will
+ have the target white point down most of the curve, but will then
+ blend over to the native or compromise black point that is blacker,
+ but not of the right hue. The rate of this blend can be controlled
+ with the <span style="font-weight: bold;">-A</span> parameter. The
+ default value 4.0, which results in a target that switches from the
+ white point target to the black, moderately close to the black
+ point. While this typically gives a good visual result with the
+ target neutral hue being maintained to the point where the crossover
+ to the black hue is not visible, it may be asking too much of some
+ displays (typically LCD type displays), and there may be some visual
+ effects due to inconsistent color with viewing angle. For this
+ situation a smaller value may give a better visual result (e.g. try
+ values of 3.0 or 2.0. A value of 1.0 will set a pure linear blend
+ from white point to black point). If there is too much coloration
+ near black, try a larger value, e.g. 6.0 or 8.0.<br>
+ <br>
+ <a name="bhack"></a>The <b>-b</b> flag forces source 0,0,0 to map
+ to destination 0,0,0. This may be useful with displays that have a
+ very dark black point, and with an instrument is unable to measure
+ it precisely, and where it is known in some other way that the
+ display is <u>very well behaved</u> from black (i.e. that it has no
+ "dead zone" above zero device input). Using this option with a
+ display that is <u>not</u> well behaved, may result in a loss of
+ shadow detail. This will override any <b>-k</b> factor.<br>
+ <br>
+ <a name="B"></a><span style="font-weight: bold;">-B</span>&nbsp; Set
+ the target brightness of black in cd/m^2 (i.e. the absolute Y
+ value). Setting too high a value may give strange results as it
+ interacts with trying to achieve the target "advertised" gamma curve
+ shape. You could try using -f 1 if this causes a problem.<br>
+ <br>
+ <a name="e"></a><span style="font-weight: bold;">-e [n]</span> Run <span
+ style="font-weight: bold;">n</span> verify passes on the final
+ curves. This is an extra set of instrument readings, that can be
+ used to estimate how well the device will match the targets with the
+ computed calibration curves. Note that the usefulness of the
+ verification is sometimes limited by the repeatability of the device
+ &amp; instrument readings. This is often evident for CRT displays,
+ which (due to their refresh rate) flicker. More than one
+ verification pass can be done by providing the parameter <span
+ style="font-weight: bold;">n</span>, and by then comparing the
+ successive verifications, some idea of the repeatability can be
+ ascertained. The verification uses a fixed number of semi-random
+ test values to test the calibration.<br>
+ <br>
+ <a name="z"></a><span style="font-weight: bold;">-z</span> Run
+ verify pass on the display as it is currently setup (currently
+ installed LUT curves). This will use the usual input parameters to
+ establish the expected (target) characteristic. <span
+ style="font-weight: bold;">Note</span> that if the initial
+ calibration was modified due to it being out of gamut of the
+ display, verify will show the resulting discrepancy. You can use <a
+ href="dispwin.html">dispwin</a> to load a <span
+ style="font-weight: bold;">.cal</span> file into the display
+ before running dispcal <span style="font-weight: bold;">-z</span>.
+ Note that if you set an Ambient light level interactively during the
+ calibration, you need to enter the same number that was measured and
+ set using the <span style="font-weight: bold;">-a</span> parameter
+ for verify.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument, or 10% of the width of the
+ display if the display size is unknown.. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="E"></a> The <span style="font-weight: bold;">-E</span>
+ flag causes the display test values to be scaled to the Video RGB
+ encoding range of (16-235)/255. This also modifies the resulting
+ calibration curve behavior downstream of dispcal. If a calibration
+ curve created using -E gets installed or converted to an ICC profile
+ 'vcgt' tag in the process of creating a profile in dispcal or
+ colprof, the incoming full range values will first have the
+ calibration curve applied and then be scaled to the Video encoding
+ range (16-235)/255.<br>
+ <br>
+ <a name="n"></a><span style="font-weight: bold;">-n</span> When
+ running on a UNIX based system that used the X11 Windowing System, <b>dispcal</b>
+ normally selects the override redirect so that the test window will
+ appear above any other windows on the display. On some systems this
+ can interfere with window manager operation, and the <b>-n</b>
+ option turns this behaviour off.<br>
+ <br>
+ <a name="J"></a> The -<span style="font-weight: bold;">J</span>
+ option runs through the black and sensor relative calibration
+ routines for the Xrite DTP92 and DTP94 instruments, the black level
+ calibration for the Eye-One Display 1, and a CRT frequency
+ calibration for the Eye-One Display 2. For the black calibration the
+ instrument should be placed on an opaque, black surface, and any
+ stray light should be avoided by placing something opaque over the
+ instrument. If a Spectrolino is being used, then a white and black
+ calibration will always be performed before the instrument can be
+ placed on the display, unless the <a href="dispcal.html#N">-N</a>
+ flag is used. Generally it is not necessary to do a calibration
+ every time an instrument is used, just now and again. There is also
+ no point in doing&nbsp; a CRT frequency calibration, as this will be
+ done automatically at the commencement of patch reading, and will be
+ lost between runs.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it, such as the Eye-One Pro. See <a
+ href="instruments.html">Operation of particular instruments</a>
+ for more details. This may give better accuracy for display
+ measurements.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
+ Spyder 5</span>).This can improve a colorimeters accuracy for a
+ particular type of display.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values from spectral readings or using a colorimeter
+ that has CCSS capability. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
+ observer that has been adjusted using a 3x3 matrix to better agree
+ with the 1931 2 degree observer.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you select
+ anything other than the default 1931 2 degree observer, that the Y
+ values will not be cd/m^2, due to the Y curve not being the CIE 1924
+ photopic V(&#955;) luminosity function.<br>
+ <br>
+ <a name="I"></a> The -<span style="font-weight: bold;">I <span
+ style="font-style: italic;">b|w</span></span> options invoke
+ instrument black level, and display white level compensation
+ (respectively). Instrument black level drift compensation attempts
+ to combat instrument black calibration drift by using a display
+ black test patch as a reference. If an instrument is not
+ acclimatised sufficiently to the measurement conditions, changes in
+ temperature can affect the black readings. Display white level drift
+ compensation attempts to combat changes in display brightness as it
+ warms up by measuring a white patch every so often, and using it to
+ normalise all the other readings. If just instrument black drift
+ compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
+ If just display white level compensation is needed, use <span
+ style="font-weight: bold;">-Iw</span>. If both are needed, use <span
+ style="font-weight: bold;">-Ibw</span> or <span
+ style="font-weight: bold;">-Iwb</span>.<span style="font-weight:
+ bold;"> </span><br>
+ <br>
+ <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
+ options overrides calibration of the instrument refresh rate. This
+ may be useful if the instrument supports this function and the
+ refresh rate cannot be accurately calibrated from the display
+ itself.<br>
+ <br>
+ <a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro,
+ ColorMunki, i1d3 and K10. By default an adaptive integration time
+ measurement mode will be used for emission measurements, but some
+ instruments support a fixed integration time mode that can be used
+ with display devices. This may give faster measurement times, but
+ may also give less accurate low level readings.<br>
+ <br>
+ <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
+ option skips asking the user to place the instrument on the display.
+ Normally a grey patch is displayed, and then the user is asked to
+ confirm that the instrument is in place, so that readings can
+ commence. This flag disables that check. This may be useful in
+ automating certain operations.<br>
+ <br>
+ <a name="C"></a> The -<span style="font-weight: bold;">C</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of relaying each test value to some other display than that
+ on the system running dispcal (for instance, a photo frame, PDA
+ screen etc.), by causing the given command to be invoked to the
+ shell, with six arguments. The first three arguments are the RGB
+ test color as integers in the range 0 to 255, the second three
+ parameters are the RGB test color as floating point numbers in the
+ range 0.0 to 1.0. The script or tool should relay the given color to
+ the screen in some manner (e.g. by generating a raster file of the
+ given color and sending it to the display being profiled), before
+ returning. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of gathering each test value from some external source, such
+ as an instrument that is not directly supported by Argyll. The given
+ command is involked to the shell, with six arguments. The first
+ three arguments are the RGB test color as integers in the range 0 to
+ 255, the second three parameters are the RGB test color as floating
+ point numbers in the range 0.0 to 1.0. The script or tool should
+ create a file called <span style="font-weight: bold;">"command.meas</span>"
+ that contains the XYZ values for the given RGB (or measured from the
+ test window) in cd/m^2 as three numbers separated by spaces, before
+ returning. If the command returns a non-zero return value, dispcal
+ will abort. Note that a test window will also be created on the
+ system running dispcal.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="p1"></a><span style="font-weight: bold;">inoutfile</span>
+ The final parameter on the command line is the base filename for the
+ <a href="cal_format.html">.cal</a> file and the optional ICC
+ profile. Normally this will be created (or an existing file will be
+ overwritten). If the <span style="font-weight: bold;">-u</span>
+ flag is used, then these files will be updated. If a different ICC
+ profile name needs to be specified, do so as an argument to the <span
+ style="font-weight: bold;">-o</span> flag.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h2><a name="Adjustment"></a>Discussion and guide to display control
+ adjustment:</h2>
+ <br>
+ The adjustment of the display controls (brightness, contrast, R, G
+ &amp; B channel controls etc.) is very dependent on the particular
+ monitor. Different types and brands of monitors will have different
+ controls, or controls that operate in different ways. Some displays
+ have almost no user controls, and so you may well be best skipping
+ display adjustment, and going straight to calibration.<br>
+ <br>
+ Almost all LCD displays lack a real <span style="font-weight:
+ bold;">contrast</span> control. Those that do present such a
+ control generally fake it by adjusting the video signal. For this
+ reason it is usually best to set an LCD's <span style="font-weight:
+ bold;">contrast</span> control at its neutral setting (ie. the
+ setting at which it doesn't change the video signal). Unfortunately,
+ it can be hard to know what this neutral setting is. On some
+ displays it is 50%, others 75%. If the LCD display has a "reset to
+ factory defaults" mode, then try using this first, as a way of
+ setting the <span style="font-weight: bold;">contrast</span>
+ control to neutral. The LCD <span style="font-weight: bold;">brightness</span>
+ control generally adjusts the level of backlighting the display
+ gets, which affects the maximum brightness, and also tends to raise
+ or lower the black level in proportion, without changing the
+ displays response curve shape or overall contrast ratio. If your LCD
+ display has a <span style="font-weight: bold;">backlight</span>
+ control as well as a <span style="font-weight: bold;">brightness</span>
+ control, then the brightness control is also probably being faked,
+ and you are probably better off setting it to it's neutral setting,
+ and using the <span style="font-weight: bold;">backlight</span>
+ control in place of <span style="font-weight: bold;">brightness</span>
+ in the following adjustments.<br>
+ <br>
+ Some high end displays have the ability to mimic various standard
+ colorspaces such as sRGB or AdobeRGB. You could choose to calibrate
+ and profile the display in such an emulation mode, although you
+ probably don't want to fight the emulations white point and gamma.
+ To get the best out of such a display you really want to choose it's
+ "Native Gamut" setting, whatever that is called. Note that some
+ people have reported bad experiences in trying to use "6-axis custom
+ controls" on displays such as the Dell U2410, so attempting to use
+ such a mode should be approached with caution. Ideally such a mode
+ should be used to give just the underlying native display response,
+ but the settings to achieve this may be very difficult to determine,
+ and/or it may not be possible, depending on how such a mode distorts
+ the RGB signals.<br>
+ <br>
+ On CRT based displays, the <span style="font-weight: bold;">brightness</span>
+ control generally adjusts the black level of the display (sometimes
+ called the <span style="font-weight: bold;">offset</span>), and as
+ a side effect, tends to change the maximum brightness too. A CRT <span
+ style="font-weight: bold;">contrast</span> control generally
+ adjusts the maximum brightness (sometimes called <span
+ style="font-weight: bold;">gain</span>) without affecting the
+ black level a great deal. On a CRT both the <span
+ style="font-weight: bold;">brightness</span> and <span
+ style="font-weight: bold;">contrast</span> controls will tend to
+ affect the shape or gamma of the display response curve.<br>
+ <br>
+ Many displays have some sort of color temperature adjustment. This
+ may be in the form of some pre-set color temperatures, or in the
+ form of individual Red, Green and Blue channel gain adjustments.
+ Some CRT displays also have R, G &amp; B channel offset adjustments
+ that will affect the color temperatures near black, as well as
+ affect the individual channels curve shape. The color temperature
+ adjustment will generally affect the maximum brightness, and may
+ also affect the black level and the shape of the display response
+ curves.<br>
+ <br>
+ Some special (expensive) LCD displays may have a white point
+ adjustment that changes the color of the backlight. If you do not
+ have one of these types of LCD displays, then attempting to change
+ the white point of the display (even if it appears to have a "<span
+ style="font-weight: bold;">white point selection</span>" or <span
+ style="font-weight: bold;">R/G/B</span> "<span style="font-weight:
+ bold;">gain</span>" controls") may not be a good idea, as once
+ again these controls are probably being faked by manipulating the
+ signal levels. Even if you do manage to change the white point
+ significantly, it may do things like change the mid tone color too
+ dramatically, or create a display response that is hard to correct
+ with calibration, or results in side effects such as quantization
+ (banding) or other undesirable effects. You may have to try out
+ various controls (and your aim points for the display calibration),
+ to decide what is reasonable to attempt on an LCD display.<br>
+ <br>
+ Due to the variety of controls as well as the interaction between
+ them, it can be an iterative process to arrive at a good monitor
+ set-up, before proceeding on to calibrating and profiling a display.
+ For this reason, <span style="font-weight: bold;">dispcal</span>
+ offers a menu of adjustment modes, so that the user can
+ interactively and iteratively adjust the display controls to meet
+ the desired targets.<br>
+ <br>
+ &nbsp; 1) Black level (CRT: Brightness)<br>
+ &nbsp; 2) White point (Color temperature, R,G,B, Gain/Contrast)<br>
+ &nbsp; 3) White level (CRT: Gain/Contrast, LCD:
+ Brightness/Backlight)<br>
+ &nbsp; 4) Black point (R,G,B, Offset/Brightness)<br>
+ &nbsp; 5) Check all<br>
+ &nbsp; 6) Measure and set ambient for viewing condition adjustment<br>
+ &nbsp; 7) Continue on to calibration<br>
+ &nbsp; 8) Exit<br>
+ <br>
+ There are four basic adjustment modes. Normally one would proceed
+ through them in the order above, then perhaps repeat the first
+ adjustment, before checking the overall settings. The White point
+ and White level modes operate slightly differently, depending on
+ whether a white target point has been set using the <span
+ style="font-weight: bold;">-t -T</span> or <span
+ style="font-weight: bold;">-w</span> options, and on whether a
+ brightness target has been set using the <span style="font-weight:
+ bold;">-b</span> option.<br>
+ <br>
+ <br>
+ The first mode lets you adjust the black level of a CRT display.
+ Given the current white level, it calculates a value that should
+ produce a 1% display brightness if the black level is set correctly.
+ After doing some initial measurements, it will show the target
+ brightness value (in cd/m^2) on one line, and then underneath it
+ will show continuously updated readings from the display. The left
+ most character will switch from '\' to '/' or back again each time a
+ reading is updated. Some instruments can be quite slow in measuring
+ dark colors, and it's best to wait for a reading update before
+ changing the controls more than once. Underneath the target value is
+ displayed the current reading, and to the right of this is a '+',
+ '-' or '=' symbol, which gives a hint as to which way to adjust the
+ brightness control to improve the match to the target.<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Adjust CRT brightness to get target level.
+ Press space when done.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp; Target
+ 0.60</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; / Current 0.68&nbsp;
+ -</span></small><br>
+ <br>
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The second mode lets you adjust the color of the white point of the
+ display. If a target white point has been set, it will show the
+ target brightness value (in cd/m^2) on one line, together with the
+ target chromaticity co-ordinates for the white point, and then
+ underneath it will show continuously updated readings from the
+ display. The left most character will switch from '\' to '/' or back
+ again each time a reading is updated. Underneath the target
+ brightness value is displayed the current reading, and then the
+ current chromaticity co-ordinate values. To the right of this is the
+ current delta E of the white point from the target, and further to
+ the right are hints '+', '-' or '='&nbsp; as to which direction to
+ adjust the individual Red, Green and Blue gain settings to move the
+ white point in the direction of the target, and reduce the delta E.
+ If the symbol is doubled, then this channel will have the greatest
+ effect. If you do not have individual channel gain controls, then
+ try choosing amongst color temperature pre-sets, to find one with
+ the lowest delta E. Depending on the stability of the display, the
+ coarseness of the controls, and the repeatability of the instrument,
+ you may not be able to get a perfectly zero delta E.<br>
+ <br>
+ &nbsp;&nbsp; <small style="font-weight: bold;"><span
+ style="font-family: monospace;">Adjust R,G &amp; B gain to get
+ target x,y. Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target B 60.00, x 0.3451, y 0.3516<br>
+ &nbsp; / Current B 60.05, x 0.3426, y 0.3506&nbsp; DE&nbsp;
+ 1.4&nbsp; R+&nbsp; G+&nbsp; B--</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ If you did not set a white point target, then the information shown
+ is a little different - it will show the initial white point value,
+ as well as the color temperature, and the CIEDE2000 of the white
+ point to either the Daylight or Black Body locus (depending on
+ whether the <span style="font-weight: bold;">-T</span> flag was
+ set). The constantly updated values show the same thing, and the
+ Red, Green and Blue control hints show the direction to adjust the
+ controls to place the white point on the locus. The control that
+ will have the most direct effect on the color temperature will be
+ the Blue, while the Green will most directly move the white point
+ towards or away from the locus, thereby reducing the delta E of the
+ white point to the locus (but there is interaction).<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">Adjust R,G &amp; B gain to desired white point.
+ Press space when done.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Initial B 47.25, x
+ 0.3417, y 0.3456, CDT 5113 DE&nbsp; 6.9</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">\ Current B 47.38, x 0.3420,
+ y 0.3460&nbsp; CDT 5104 DE&nbsp; 6.7&nbsp; R-- G+&nbsp; B-</span></small><br>
+ <br>
+ &nbsp;The brightness value is just there as a guide to what effect
+ the adjustment is having on the overall brightness. Usually the
+ white level brightness is adjusted using the next adjustment mode.
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The third mode lets you adjust the brightness of white on the
+ display. If you set a target brightness using the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">-b</span></span>
+ parameter, it will show the target brightness value (in cd/m^2) on
+ one line, and then underneath it will show continuously updated
+ readings from the display. The left most character will switch from
+ '\' to '/' or back again each time a reading is updated. Underneath
+ the target value is displayed the current reading, and to the right
+ of this is a '+', '-' or '=' symbol, which gives a hint as to which
+ way to adjust the CRT contrast or LCD brightness control to improve
+ the match to the target.<br>
+ <br>
+ &nbsp;&nbsp; <small style="font-weight: bold;"><span
+ style="font-family: monospace;">Adjust CRT Contrast or LCD
+ Brightness to get target level. Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target 60.00<br>
+ &nbsp; / Current 59.96&nbsp; +</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ If you did not set a brightness target, it will show the initial
+ brightness as the target, and the current brightness, which you can
+ then set any way you want:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">Adjust CRT Contrast or LCD Brightness to desired
+ level. Press space when done.</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp; Initial 47.32</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">/ Current 47.54</span></small><br>
+ <br>
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The fourth mode lets you adjust the color of the black point of the
+ display, if the display has Red, Green and Blue channel offset
+ controls. It will show the target 1% brightness value (in cd/m^2) on
+ one line, together with the target chromaticity co-ordinates for the
+ black point, and then underneath it will show continuously updated
+ readings from the display. The left most character will switch from
+ '\' to '/' or back again each time a reading is updated. Underneath
+ the target brightness value is displayed the current reading, and
+ then the current chromaticity co-ordinate values. To the right of
+ this is the current delta E of the black point from the target, and
+ further to the right are hints '+', '-' or '='&nbsp; as to which
+ direction to adjust the individual Red, Green and Blue offset
+ settings to move the black point in the right direction. If the
+ symbol is doubled, then this channel will have the greatest effect.
+ <br>
+ <br>
+ <span style="font-family: monospace;"><span style="font-weight:
+ bold;">&nbsp; Adjust R,G &amp; B offsets to get target x,y.
+ Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target B 0.60, x 0.3451, y 0.3516<br>
+ &nbsp; \ Current B 0.62, x 0.2782, y 0.2331&nbsp; DE&nbsp;
+ 10.3&nbsp; R+&nbsp; G++ B-</span></span><small
+ style="font-weight: bold;"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><br>
+ <br>
+ The 1%&nbsp; brightness value is just there as a guide to what
+ effect the adjustment is having on the 1% brightness level. The
+ combined channel offsets may have an effect on this in combination
+ with the CRT brightness control. Press space to go back to the menu.<br>
+ <br>
+ <br>
+ The fifth selection checks on the overall settings.&nbsp; If targets
+ have been set, it will be like:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Target Brightness = 50.00, Current = 47.44,
+ error = -5.1%<br>
+ &nbsp; Target 50% Level&nbsp; = 10.32, Current =&nbsp; 8.10,
+ error = -4.4%<br>
+ &nbsp; Target Near Black =&nbsp; 0.47, Current =&nbsp; 0.68,
+ error =&nbsp; 0.4%<br>
+ &nbsp; Target white = x 0.3458, y 0.3586, Current = x 0.3420, y
+ 0.3454, error =&nbsp; 7.55 DE<br>
+ &nbsp; Target black = x 0.3458, y 0.3586, Current = x 0.2908, y
+ 0.2270, error = 29.69 DE</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ or if no targets are set:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Current Brightness = 46.28</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target 50%
+ Level&nbsp; = 10.07, Current =&nbsp; 7.52, error = -5.5%</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target Near Black
+ =&nbsp; 0.46, Current =&nbsp; 0.46, error = -0.0%</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Current white = x
+ 0.3439, y 0.3466, VCT 5098K DE&nbsp; 3.0</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target black = x
+ 0.3439, y 0.3466, Current = x 0.3093, y 0.2165, error = 30.30 DE</span></small><br>
+ <br>
+ and will then go back to the menu.<br>
+ <br>
+ The sixth selection <span style="font-weight: bold;">6)</span>
+ allows the reading of you ambient lighting conditions if your
+ instrument supports such a mode. Doing so will enable the <span
+ style="font-weight: bold;">-a</span> option to compensate for your
+ viewing conditions in the subsequent calibration. See <a
+ href="dispcal.html#a">-a</a>.<br>
+ <br>
+ Once&nbsp; you're happy with the display set-up, you can either
+ proceed on to the rest of the calibration by selecting <span
+ style="font-weight: bold;">7)</span>, or exit and re-start by
+ selecting <span style="font-weight: bold;">8)</span>. You might
+ want to re-start if you want to change the calibration targets.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h2>Other caveats:</h2>
+ NOTE that some <span style="font-weight: bold;">LCD</span> screens
+ behave a little strangely near their absolute white point, and may
+ therefore exhibit odd behavior at values just below white. It may be
+ advisable in such cases to set a brightness slightly less than the
+ maximum such a display is capable of.<br>
+ <br>
+ The program attempts to stop any screensaver or powersaver from
+ interfering with the measurements, but this may not be effective on
+ some systems, so it may be necessary to manually disable the
+ screensaver and/or powersaver before commencing the calibration with
+ a large number of patches.<br>
+ <br>
+ The calibration tables produced maintain the maximum level of
+ precision available on a system. If the display has VideoLUTs
+ available (Video Lookup Tables that the frame buffer values pass
+ through on their way to the display) and thier outputs are better
+ than 8 bits per component, then the resulting curves can reflect
+ this, although few current operating systems and/or display cards
+ actually support better than 8 bit per component output.<br>
+ <br>
+ If calibration curves are created for a display in which VideoLUTs
+ are not available, then the resulting calibration file will be
+ marked to indicate this, and a subsequent profile created with the
+ calibration will not have the calibration converted to the 'vcgt'
+ tag, since such a tag can't be loaded into the displays VideoLUTs.<br>
+ <br>
+ If communications break down with a USB connected instrument, you
+ may have to unplug it, and plug it in again to recover operation.<br>
+ <br>
+ Some systems (Apple OS X in particular) have a special set of user
+ interface controls ("Universal Access") that allows altering the
+ display in ways designed to assist visually impaired users, by
+ increasing contrast etc. This will interfere badly with any attempts
+ to calibrate or profile such a system, and must be turned off in
+ order to do so. Note that certain magic keyboard sequences can turn
+ this on by accident.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/dispread.html b/doc/dispread.html
index 52a38c2..f7fe551 100644
--- a/doc/dispread.html
+++ b/doc/dispread.html
@@ -1,25 +1,25 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>dispread</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/dispread</b>&nbsp;</h2>
- <h3>Summary</h3>
- Display test patches on a monitor, read the colorimetric value
- result with the colorimeter, and create the chart readings file. The
- type of instrument is determined by the communication port selected.
- Emission and display measurement instruments are supported.<br>
- <br>
- If you want to read a display manually rather than automatically,
- see <a href="chartread.html">chartread</a> and the <a
- href="chartread.html#d">-d</a> option.<br>
- <h3>Usage</h3>
- <small style="font-family: monospace;">dispread [-options]<i>
- inoutfile</i><br>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispread</b>&nbsp;</h2>
+ <h3>Summary</h3>
+ Display test patches on a monitor, read the colorimetric value
+ result with the colorimeter, and create the chart readings file. The
+ type of instrument is determined by the communication port selected.
+ Emission and display measurement instruments are supported.<br>
+ <br>
+ If you want to read a display manually rather than automatically,
+ see <a href="chartread.html">chartread</a> and the <a
+ href="chartread.html#d">-d</a> option.<br>
+ <h3>Usage</h3>
+ <small style="font-family: monospace;">dispread [-options]<i>
+ inoutfile</i><br>
&nbsp;<a href="#v">-v</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -54,17 +54,17 @@
-
- &nbsp;&nbsp;&nbsp;&nbsp; Verbose mode<br>
- &nbsp;</small><font size="-1"><a style="font-family: monospace;"
- href="#display">-display displayname</a><span
- style="font-family: monospace;"> [X11 only] Choose X11 display
- name<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [X11 only]Choose the display from the following list (default
- 1),<br>
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Verbose mode<br>
+ &nbsp;</small><font size="-1"><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [X11 only] Choose X11 display
+ name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [X11 only]Choose the display from the following list (default
+ 1),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
and
optionally
@@ -106,9 +106,9 @@ m
-
- for VideoLUT access.</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ for VideoLUT access.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Choose
the
@@ -150,8 +150,8 @@ list
-
- (default 1)</span></font><small style="font-family: monospace;"><br>
+
+ (default 1)</span></font><small style="font-family: monospace;"><br>
</small><span style="font-family: monospace;">&nbsp;<a href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -188,9 +188,9 @@ list
-
- Display via a web server at port (default 8080)</span><br>
- <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
+
+ Display via a web server at port (default 8080)</span><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#dmadvr">-dmadvr</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -214,22 +214,22 @@ list
-
- [MSWin] Display via MadVR Video Renderer</span><br>
+
+ [MSWin] Display via MadVR Video Renderer</span><br>
<tt>&nbsp;</tt><tt><a href="#dcc">-dcc[:n]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br>
- <small style="font-family: monospace;"> <span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#c">-c listno</a><span style="font-family: monospace;">
- &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set
- communication port from the following list (default 1)<br>
- </span></small><font size="-1"><span style="font-family:
+
+ </tt><tt>Display via n'th ChromeCast (default 1, ? for list)</tt><br>
+ <small style="font-family: monospace;"> <span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#c">-c listno</a><span style="font-family: monospace;">
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set
+ communication port from the following list (default 1)<br>
+ </span></small><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -264,10 +264,10 @@ list
-
- Use telephoto mode (ie. for a projector) (if available)</span></font><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
- href="#y">-y X</a>
+
+ Use telephoto mode (ie. for a projector) (if available)</span></font><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#y">-y X</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Display
@@ -304,10 +304,10 @@ Display
-
- type - instrument specific list to choose from.</span></font><br>
- <small style="font-family: monospace;">&nbsp;<span
- style="text-decoration: underline;">-</span><a href="#k">k
+
+ type - instrument specific list to choose from.</span></font><br>
+ <small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;">-</span><a href="#k">k
file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -342,10 +342,10 @@ Display
-
- Load calibration file into display while reading<br>
- </small><small style="font-family: monospace;">&nbsp;<span
- style="text-decoration: underline;">-</span><a href="#K">K
+
+ Load calibration file into display while reading<br>
+ </small><small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;">-</span><a href="#K">K
file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Apply
@@ -381,8 +381,8 @@ Apply
-
- calibration file to test values while reading</small><br>
+
+ calibration file to test values while reading</small><br>
<tt>&nbsp;<a href="#V">-V</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -398,8 +398,8 @@ Apply
-
- [MSWin] Enable MadVR color management (3dLut)</tt><br>
+
+ [MSWin] Enable MadVR color management (3dLut)</tt><br>
<small style="font-family: monospace;">&nbsp;<a href="#s">-s</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -434,12 +434,12 @@ Apply
-
- &nbsp;&nbsp;&nbsp;&nbsp; Save spectral information (default don't
- save)<br>
- </small><font style="font-family: monospace;" size="-1">&nbsp;<a
- href="#P">-P ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position
- test window and scale it<br>
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Save spectral information (default don't
+ save)<br>
+ </small><font style="font-family: monospace;" size="-1">&nbsp;<a
+ href="#P">-P ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position
+ test window and scale it<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ho,vi:
0.0
@@ -481,8 +481,8 @@ center,
-
- 1.0 = right/bottom etc.<br>
+
+ 1.0 = right/bottom etc.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ss:
0.5
@@ -524,8 +524,8 @@ normal,
-
- 2.0 = double etc.<br>
+
+ 2.0 = double etc.<br>
</font><font size="-1"><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -553,10 +553,10 @@ normal,
-
- ss,vs: = optional horizontal, vertical scale.</span></font><br>
- <font style="font-family: monospace;" size="-1"> &nbsp;</font><font
- size="-1"><span style="font-family: monospace;"><a href="#F">-F</a>
+
+ ss,vs: = optional horizontal, vertical scale.</span></font><br>
+ <font style="font-family: monospace;" size="-1"> &nbsp;</font><font
+ size="-1"><span style="font-family: monospace;"><a href="#F">-F</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -591,10 +591,10 @@ normal,
-
- Fill whole screen with black background</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
+
+ Fill whole screen with black background</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -614,11 +614,11 @@ normal,
-
- </span></font><small><span style="font-family: monospace;">Video
- encode output as (16-235)/255 "TV" levels</span></small><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#Z">-Z
+
+ </span></font><small><span style="font-family: monospace;">Video
+ encode output as (16-235)/255 "TV" levels</span></small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#Z">-Z
nbits</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -638,7 +638,7 @@ normal,
-
+
</span></font><small><span style="font-family: monospace;">Quantize
test
values
@@ -658,9 +658,9 @@ fit
-
- in nbits</span></small><br style="font-family: monospace;">
- <small style="font-family: monospace;">&nbsp;<span
+
+ in nbits</span></small><br style="font-family: monospace;">
+ <small style="font-family: monospace;">&nbsp;<span
style="text-decoration: underline;"></span><a href="#n">-n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
[X11
@@ -702,9 +702,9 @@ redirect
-
- on test window<br>
- </small><small style="font-family: monospace;">&nbsp;<a href="#J">-J</a>
+
+ on test window<br>
+ </small><small style="font-family: monospace;">&nbsp;<a href="#J">-J</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -739,9 +739,9 @@ redirect
-
- &nbsp;&nbsp;&nbsp;&nbsp; Run calibration first</small><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Run calibration first</small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -776,17 +776,17 @@ redirect
-
- Disable initial calibration of instrument if possible<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#H">-H</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
- available)</span></font><font size="-1"><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"><br>
- &nbsp;<a href="#w">-w</a>
+
+ Disable initial calibration of instrument if possible<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#H">-H</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
+ available)</span></font><font size="-1"><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ &nbsp;<a href="#w">-w</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Disable
normalisation
@@ -828,9 +828,9 @@ Y
-
- 100</span></font><small><span style="font-family: monospace;"></span></small><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+
+ 100</span></font><small><span style="font-family: monospace;"></span></small><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -865,9 +865,9 @@ Y
-
- Apply Colorimeter Correction Matrix</span></font><br>
- <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Use
Colorimeter
@@ -905,14 +905,14 @@ Calibration
-
- Spectral Samples for calibration</span><font size="-1"><span
- style="font-family: monospace;"><br>
- </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
- style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
- colorimeter data:</span><br style="font-family: monospace;">
+
+ Spectral Samples for calibration</span><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
+ colorimeter data:</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -947,12 +947,12 @@ Calibration
-
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
- style="font-family: monospace;">(def.)</span></small><small><span
- style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
- J&amp;V 1978_2, 1964_10c</span></small><br>
- <small><span style="font-family: monospace;">&nbsp;<a
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
+ style="font-family: monospace;">(def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2, 1964_10c</span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;<a
href="dispread.html#I">-I b|w</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Drift
compensation,
@@ -994,8 +994,8 @@ Both:
-
- -Ibw</span></small><br>
+
+ -Ibw</span></small><br>
<small><span style="font-family: monospace;"><tt>&nbsp;<a href="#YR">-Y
@@ -1008,7 +1008,7 @@ Both:
-
+
R:<i>rate</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1021,12 +1021,12 @@ Both:
-
- Override measured refresh rate with rate Hz<br>
- </tt>&nbsp;</span></small><font size="-1"><span
- style="font-family: monospace;"></span><a style=" font-family:
- monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
- style="font-family: monospace;">
+
+ Override measured refresh rate with rate Hz<br>
+ </tt>&nbsp;</span></small><font size="-1"><span
+ style="font-family: monospace;"></span><a style=" font-family:
+ monospace;" href="#YA">-<font size="-1">Y</font> A</a><span
+ style="font-family: monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1052,31 +1052,31 @@ Both:
-
- Use non-adaptive integration time mode (if available).</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
- <font size="-1">p</font></a><span style="font-family:
- monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
- the display</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#C">-C "command"</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is set<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#M">-M "command"</a><span style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
- "command" each time a color is measured</span></font><br>
- <small>&nbsp; <a style="font-family: monospace;" href="#x">-x x</a><span
+
+ Use non-adaptive integration time mode (if available).</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#Yp">-<font size="-1">Y</font>
+ <font size="-1">p</font></a><span style="font-family:
+ monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Don't wait for the instrument to be placed on
+ the display</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#C">-C "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is set<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#M">-M "command"</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is measured</span></font><br>
+ <small>&nbsp; <a style="font-family: monospace;" href="#x">-x x</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-Take
- manually entered
- XYZ values</span></small><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+Take
+ manually entered
+ XYZ values</span></small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
serial
@@ -1118,11 +1118,11 @@ n
-
- none, h = HW, x = Xon/Xoff</span></font><br>
- <small style="font-family: monospace;">&nbsp;<a href="#D">-D [level]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Print debug
- diagnostics to stderr</small><br>
+
+ none, h = HW, x = Xon/Xoff</span></font><br>
+ <small style="font-family: monospace;">&nbsp;<a href="#D">-D [level]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Print debug
+ diagnostics to stderr</small><br>
<small style="font-family: monospace;">&nbsp;<a href="#p1"><i>inoutfile</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1157,73 +1157,73 @@ n
-
- Base name for input[<a href="File_Formats.html#.ti1">.ti1</a>]/output[<a
- href="File_Formats.html#.ti3">.ti3</a>] file.<br>
- </small> <br>
- <b>Examples</b><br>
- <br>
- dispread -c1 -i92 mycrt<br>
- <h3>Comments<br>
- </h3>
- This is the tool for exercising a display, in order to measure its
- color characteristics. The device test colors are defined by the
- outfile.ti1 file, while the resulting device+colorimetric and
- optional spectral readings are stored in the outfile.ti3 file.
- Display calibration curves can be applied during the measurements,
- and the curves included in the resulting .ti3 data file using the <span
- style="font-weight: bold;">-k</span>flag. See <a
- href="dispcal.html">dispcal</a> for information on how&nbsp; to
- calibrate the display before profiling it. For best results, you
- should run this against a neutral grey desktop background, and avoid
- having any bright images or windows on the screen at the time you
- run it.<br>
- <br>
- <a name="v"></a> The <b>-v</b> flag reports progress information.<br>
- <br>
- <a name="display"></a><span style="font-weight: bold;">-display</span>:
- When running on a UNIX based system that used the X11 Windowing
- System, <b>dispread</b> will by default use the $DISPLAY
- environment variable to determine which display and screen to read
- from. This can be overridden by supplying an X11 display name to the
- <span style="font-weight: bold;">-display</span> option. Note that
- if Xinerama is active, you can't select the screen using $DISPLAY or
- -display, you have to select it using the <span style="font-weight:
- bold;">-d</span> parameter.<br>
- <br>
- <a name="d"></a> <span style="font-weight: bold;">-d</span>: By
- default the main display will be the location of the test window. If
- the system has more than one display or screen, an alternate
- display/screen can be selected with the <span style="font-weight:
- bold;">-d</span> parameter. If you invoke <span
- style="font-weight: bold;">dispread</span> so as to display the
- usage information (i.e. "dispread -?" or "dispread --"), then the
- discovered displays/screens will be listed. Multiple displays may
- not be listed, if they appear as a single display to the operating
- system (ie. the multi-display support is hidden in the video card
- driver). On UNIX based system that used the X11 Windowing System,
- the <span style="font-weight: bold;">-d</span> parameter will
- override the screen specified by the $DISPLAY or <span
- style="font-weight: bold;">-display</span> parameter.<br>
- <br>
- On X11 the inability to access VideoLUTs could be because you are
- trying to access a remote display, and the remote display doesn't
- support the XF86VidMode extension, or perhaps you are running
- multiple monitors using NVidia TwinView, or MergedFB, and trying to
- access anything other than the primary monitor. TwinView and
- MergedFB don't properly support the XF86VidMode extension for
- multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
- to test whether the VideoLUTs are accessible for a particular
- display. See also below, on how to select a different display for
- VideoLUT access. Also note that dispcal will fail if the Visual
- depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
- 256 entries per color component, so the Visual generally needs to be
- 24 bits, 8 bits per color component.<br>
- <br>
- <a name="dnm"></a>Because of the difficulty cause by TwinView and
- MergedFB in X11 based systems, you can optionally specify a separate
- display number after the display that is going to be used to present
- test patches, for accessing the VideoLUT hardware. This must be
+
+ Base name for input[<a href="File_Formats.html#.ti1">.ti1</a>]/output[<a
+ href="File_Formats.html#.ti3">.ti3</a>] file.<br>
+ </small> <br>
+ <b>Examples</b><br>
+ <br>
+ dispread -c1 -i92 mycrt<br>
+ <h3>Comments<br>
+ </h3>
+ This is the tool for exercising a display, in order to measure its
+ color characteristics. The device test colors are defined by the
+ outfile.ti1 file, while the resulting device+colorimetric and
+ optional spectral readings are stored in the outfile.ti3 file.
+ Display calibration curves can be applied during the measurements,
+ and the curves included in the resulting .ti3 data file using the <span
+ style="font-weight: bold;">-k</span>flag. See <a
+ href="dispcal.html">dispcal</a> for information on how&nbsp; to
+ calibrate the display before profiling it. For best results, you
+ should run this against a neutral grey desktop background, and avoid
+ having any bright images or windows on the screen at the time you
+ run it.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag reports progress information.<br>
+ <br>
+ <a name="display"></a><span style="font-weight: bold;">-display</span>:
+ When running on a UNIX based system that used the X11 Windowing
+ System, <b>dispread</b> will by default use the $DISPLAY
+ environment variable to determine which display and screen to read
+ from. This can be overridden by supplying an X11 display name to the
+ <span style="font-weight: bold;">-display</span> option. Note that
+ if Xinerama is active, you can't select the screen using $DISPLAY or
+ -display, you have to select it using the <span style="font-weight:
+ bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a> <span style="font-weight: bold;">-d</span>: By
+ default the main display will be the location of the test window. If
+ the system has more than one display or screen, an alternate
+ display/screen can be selected with the <span style="font-weight:
+ bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispread</span> so as to display the
+ usage information (i.e. "dispread -?" or "dispread --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed, if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or <span
+ style="font-weight: bold;">-display</span> parameter.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
+ <a name="dnm"></a>Because of the difficulty cause by TwinView and
+ MergedFB in X11 based systems, you can optionally specify a separate
+ display number after the display that is going to be used to present
+ test patches, for accessing the VideoLUT hardware. This must be
specified as a single string, e.g. <span style="font-weight: bold;">-d
@@ -1258,423 +1258,423 @@ n
-
- 1,2</span> . Some experimentation may be needed using <a
- href="dispwin.html">dispwin</a> on such systems, to discover what
- screen has access to the VideoLUT hardware, and which screens the
- test patches appear on. You may be able to calibrate one screen, and
- then share the calibration with another screen. Profiling can be
- done independently to calibration.<br>
- <br>
- <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
- <span style="font-weight: bold;">-dweb:port</span> starts a
- standalone web server on your machine, which then allows a local or
- remote web browser to display the the color test patches. By default
- port <span style="font-weight: bold;">8080</span> is used, but this
- can be overridden by appending a <span style="font-weight: bold;">:</span>
- and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
- The URL will be <span style="font-weight: bold;">http://</span>
- then name of the machine or its I.P. address followed by a colon and
- the port number - e.g something like <span style="font-weight:
- bold;">http://192.168.0.1:8080</span>. If you use the verbose
- option (<span style="font-weight: bold;">-v</span>) then a likely
- URL will be printed once the server is started, or you could run <span
- style="font-weight: bold;">ipconfig</span> (MSWin) or <span
- style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
- and identify an internet address for your machine that way. <b>
- JavaScript</b> needs to be enabled in your web browser for this to
- work. You may have to modify any firewall to permit port 8080 to be
- accessed on your machine.<br>
- <br>
- Note that if you use this method of displaying test patches, that
- there is no access to the display VideoLUTs and that the colors will
- be displayed with 8 bit per component precision, and any
- screen-saver or power-saver will not be disabled. You will also be
- at the mercy of any color management applied by the web browser, and
- may have to carefully review and configure such color management.
- See the <a href="dispcal.html#o">-o</a> flag for an explanation of
- the implications of having no access to the VideoLUTs.<br>
- <br>
- <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
- [MSWin only] causes test patches to be displayed using the MadVR
- video renderer. Note that will have to start <b>MadTPG</b> before
- running dispread, and that while you can adjust the "Test Pattern
- Configuration" controls, you should <u>not</u> normally alter the
- "Existing Calibration" controls, as dispread will set these
- appropriately. See also <tt><a
- href="dispread.html#V">-V</a> flag.</tt><br>
- <br>
- <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
- causes test patches to be displayed using and available <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
- your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
- local network. Note that the ChromeCast as a test patch source is
- probably the<b> least accurate</b> of your choices, since it
- up-samples the test patch and transforms from RGB to YCC and back,
- but should be accurate within ± 1 bit. You may have to modify any
- firewall to permit port 8081 to be accessed on your machine if it
+
+ 1,2</span> . Some experimentation may be needed using <a
+ href="dispwin.html">dispwin</a> on such systems, to discover what
+ screen has access to the VideoLUT hardware, and which screens the
+ test patches appear on. You may be able to calibrate one screen, and
+ then share the calibration with another screen. Profiling can be
+ done independently to calibration.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>
+ JavaScript</b> needs to be enabled in your web browser for this to
+ work. You may have to modify any firewall to permit port 8080 to be
+ accessed on your machine.<br>
+ <br>
+ Note that if you use this method of displaying test patches, that
+ there is no access to the display VideoLUTs and that the colors will
+ be displayed with 8 bit per component precision, and any
+ screen-saver or power-saver will not be disabled. You will also be
+ at the mercy of any color management applied by the web browser, and
+ may have to carefully review and configure such color management.
+ See the <a href="dispcal.html#o">-o</a> flag for an explanation of
+ the implications of having no access to the VideoLUTs.<br>
+ <br>
+ <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
+ [MSWin only] causes test patches to be displayed using the MadVR
+ video renderer. Note that will have to start <b>MadTPG</b> before
+ running dispread, and that while you can adjust the "Test Pattern
+ Configuration" controls, you should <u>not</u> normally alter the
+ "Existing Calibration" controls, as dispread will set these
+ appropriately. See also <tt><a
+ href="file:///D:/src/argyll/doc/dispread.html#V">-V</a> flag.</tt><br>
+ <br>
+ <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
+ causes test patches to be displayed using and available <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
+ your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
+ local network. Note that the ChromeCast as a test patch source is
+ probably the<b> least accurate</b> of your choices, since it
+ up-samples the test patch and transforms from RGB to YCC and back,
+ but should be accurate within ± 1 bit. You may have to modify any
+ firewall to permit port 8081 to be accessed on your machine if it
falls back to the Default receiver (see <a href="Installing.html">installation
-
- instructions</a> for your platform).<br>
- <br>
- <a name="c"></a> <span style="font-weight: bold;">-c</span>: The
- instrument is assumed to communicate through a USB or serial
- communication port, and the port can be selected with the <b>-c</b>
- option, if the instrument is not connected to the first port. If you
- invoke <span style="font-weight: bold;">dispread</span> so as to
- display the usage information (i.e. "dispread -?" or "dispread --"),
- then the discovered USB and serial ports will be listed. On
- UNIX/Linux, a list of all possible serial ports are shown, but not
- all of them may actually be present on your system.<br>
- <br>
- <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
- allows measuring in telephoto mode, using instruments that support
- this mode, e.g. the ColorMunki. Telephoto mode is one for taking
- emissive measurements from a distance (ie. telespectometer,
- tele-colorimeter) mode, and typically would be used for measuring
- projector type displays. If a device does not support a specific
- telephoto mode, then the normal emissive mode may be suitable for
- measuring projectors.<br>
- <br>
- <a name="y"></a>The <span style="font-weight: bold;">-y</span> flag
- allows setting the Display Type. The selection typically determines
- two aspects of of the instrument operation: <span
- style="font-weight: bold;">1)</span> It may set the measuring mode
- to suite <a
- href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
- style="font-weight: bold;">refresh</span> or <span
- style="font-weight: bold;">non-refresh</span> displays</a>.
- Typically only LCD (Liquid Crystal) displays have a non-refresh
- nature. <span style="font-weight: bold;">2)</span> It may select an
- instrument calibration matrix suitable for a particular display
- type. The selections available depends on the type and model of
- instrument, and a list of the options for the discovered instruments
- will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
- information. For more details on what particular instruments support
- and how this works, see <a href="instruments.html">Operation of
- particular instruments</a>. <b>3)</b> Any installed CCSS files
- (if applicable), or CCMX files. These files are typically created
- using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
- href="oeminst.html">oeminst</a>. The default and Base Calibration
- types will be indicated in the usage.<br>
- <br>
- <a name="s"></a><span style="font-weight: bold;">-s</span>: By
- default only the colorimetric information (XYZ value) will be saved,
- but for instruments that support spectral readings (such as the
- Gretag Spectrolino), the <b>-s</b> option will save the spectral
- readings to the .ti3 file as well.<br>
- <br>
- <a name="k"></a> <span style="font-weight: bold;">-k: </span>If a
- display video lookup table calibration <a
- href="File_Formats.html#.cal">.cal</a> file is provided, it will
- be loaded into the display <span style="font-weight: bold;">VideoLUTs</span>
- while the measurements are being taken, thereby being applied to the
- measurement values, and the calibration will also included in the
- resulting .ti3 data file, so that <a href="colprof.html">colprof</a>
- can include it as a <span style="font-weight: bold;">vcgt</span>
- tag in the resulting profile. This is the <span style="font-weight:
- bold;">normal</span> way to profile a calibrated display. The
- calibration file has usually been created using <a
- href="dispcal.html">dispcal</a>. If the calibration file indicates
- that the displays VideoLUTs are not accessible, or if they prove not
- to be accessible, then dispread will switch to <span
- style="font-weight: bold;">-K</span> mode (see below). If a
- calibration file is not supplied using <b>-k</b> or <b>-K</b>,
- then the display will be measured in whatever calibration state it
- is in, and no calibration information is saved to the resulting .ti3
- file.<br>
- If the calibration file provided created using video range encoding
- (dispcal -E), then the <b>-E</b> option in dispread will be
- triggered automatically.<br>
- <span style="font-weight: bold;">NOTE</span> that the calibration is
- loaded into the display hardware just before the instrument starts
- measurement, after the test window first appears.<br>
- <br>
- <a name="K"></a> <span style="font-weight: bold;">-K: </span>If a
- display video lookup table calibration <a
- href="File_Formats.html#.cal">.cal</a> file is provided, it will
- be applied to the test values for each measurement, and also
- included in the resulting .ti3 data file, so that <a
- href="colprof.html">colprof</a> can include it as a <span
- style="font-weight: bold;">vcgt</span> tag in the resulting
- profile. This is <span style="font-weight: bold;">NOT</span>
- normally the best way to profile a calibrated display, since the
- frame buffer may have lower precision than the VideoLUTs output
- values. This is the way calibration should be applied if MadVR is
- being used to display the test patches. If a calibration file is not
- supplied using <b>-k</b> or <b>-K</b>, then the display will be
- measured in whatever calibration state it is in, and no calibration
- information is saved to the resulting .ti3 file.<br>
- If the calibration file provided created using video range encoding
- (dispcal -E), then the <b>-E</b> option in dispread will be
- triggered automatically.<br>
- <br>
- <a name="V"></a><b>-V:</b> [MSWin] If using MadVR to display test
- patches, then enable Color Managenent (3dLut). This would be used
- for verification measurement.<br>
- <br>
- <a name="P"></a> The <span style="font-weight: bold;">-P</span>
- parameter allows you to position and size the test patch window. By
- default it is places in the center of the screen, and sized
- appropriately for the type of instrument, or 10% of the width of the
- display if the display size is unknown. The <span
- style="font-weight: bold;">ho</span> and <span
- style="font-weight: bold;">vo</span> values govern the horizontal
- and vertical offset respectively. A value of 0.0 positions the
- window to the far left or top of the screen, a value of 0.5
- positions it in the center of the screen (the default), and 1.0
- positions it to the far right or bottom of the screen. If three
- parameters are provided, then the <span style="font-weight: bold;">ss</span>
- parameter is a scale factor for the test window size. A value of 0.5
- for instance, would produce a half sized window. A value of 2.0 will
- produce a double size window. If four parameters are provided, then
- the last two set independent horizontal and vertical scaling
- factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
- specified as a single string (no space between the numbers and the
- comma). For example, to create a double sized test window at the top
- right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
- . To create a window twice as wide as high: <span
- style="font-weight: bold;">-P 1,0,2,1</span>.<br>
- <br>
- <a name="F"></a> The <span style="font-weight: bold;">-F</span>
- flag causes the while screen behind the test window to be masked
- with black. This can aid black accuracy when measuring CRT displays
- or projectors.<br>
- <br>
- <a name="E"></a> The <span style="font-weight: bold;">-E</span>
- flag causes the test values to be scaled to the Video RGB encoding
- range of 16/255 to 235/255. If the calibration file provided using
- the <b>-k</b> or <b>-K</b> flag was created using video range
- encoding, then this option will be triggered automatically. This
- will also set quantization of 8 bits (see -Z flag below). If your
- video connection is better than 8 bits (ie. 10 or 12 bits), then you
- may wish to raise this default.<br>
- <br>
- <a name="Z"></a> <b>-Z nbits </b>Normally the target device values
- are floating point numbers that may get rounded and quantized in the
- process of printing them or reproducing them on the display device.
- If some of this quantization can be accounted for, it may improve
- the accuracy of the resulting profile, and the <span
- style="font-weight: bold;">Q</span> parameter allows this
- quantization to be specified. The parameter is the number of binary
- digits (bits) that the device values should be quantized to. An idea
- of the number of bits of precision that makes its way to your
- display can be obtained by using <a href="dispcal.html#R">dispcal
- -R</a> If Video encoding is selected (see -E flag above), then 8
- bits is selected by default. On systems using an VGA connection or
- Display Port with a graphics card with VideoLUT entries with greater
- than 8 bits depth, or if using the MadVR rendered with dithering,
- then a higher bit depth is typically possible.<br>
- <br>
- <a name="n"></a><span style="font-weight: bold;">-n</span>: When
- running on a UNIX based system that used the X11 Windowing System, <b>dispread</b>
- normally selects the override redirect so that the test window will
- appear above any other windows on the display. On some systems this
- can interfere with window manager operation, and the <b>-n</b>
- option turns this behaviour off.<br>
- <br>
- <a name="J"></a> The -<span style="font-weight: bold;">J</span>
- option runs through the black and sensor relative calibration
- routines for the Xrite DTP92 and DTP94 instrument, the black level
- calibration for the Eye-One Display 1, and a CRT frequency
- calibration for the Eye-One Display 2. For the black calibration the
- instrument should be placed on an opaque, black surface, and any
- stray light should be avoided by placing something opaque over the
- instrument. If a Spectrolino is being used, then a white and black
- calibration will always be performed before the instrument can be
- placed on the display, unless the <a href="#N">-N</a> flag is used.
- Generally it is not necessary to do a calibration every time an
- instrument is used, just now and again. There is no point in
- doing&nbsp; a CRT frequency calibration, as this will be done
- automatically at the commencement of patch reading.<br>
- <br>
- <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
- instrument that requires regular calibration will ask for
- calibration on initial start-up. Sometimes this can be awkward if
- the instrument is being mounted in some sort of measuring jig, or
- annoying if several sets of readings are being taken in quick
- succession. The -<span style="font-weight: bold;">N</span>
- suppresses this initial calibration if a valid and not timed out
- previous calibration is recorded in the instrument or on the host
- computer. It is advisable to only use this option on the second and
- subsequent measurements in a single session.<br>
- <br>
- <a name="H"></a> The -<span style="font-weight: bold;">H</span>
- option turns on high resolution spectral mode, if the instrument
- supports it. See <a href="instruments.html">Operation of particular
- instruments</a> for more details. This may give better accuracy
- for display measurements.<br>
- <br>
- <a name="w"></a>The <b>-w</b> flag disables the normalisation of
- the white patch value to 100.0, resulting in values that are in
- cd/m^2. This is mainly for diagnostic purposes.<br>
- <br>
- <a name="X1"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccmx</span></span> option reads
- a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
- from the given file, and applies it to the colorimeter instruments
- readings. This can improve a colorimeters accuracy for a particular
- type of display. A list of contributed <span style="font-weight:
- bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
- <br>
- <a name="X2"></a> The -<span style="font-weight: bold;">X <span
- style="font-style: italic;">file.ccss</span></span> option reads
- a <a href="File_Formats.html#.ccss">Colorimeter Calibration
- Spectral Sample</a> from the given file, and uses it to set the
- colorimeter instruments calibration. This will only work with
- colorimeters that rely on sensor spectral sensitivity calibration
- information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
- or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
- Spyder 5</span>).This can improve a colorimeters accuracy for a
- particular type of display.<br>
- <br>
- <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
- observer, and is used to compute PCS (Profile Connection Space)
- tristimulus values from spectral readings or using a colorimeter
- that has CCSS capability. The following choices are available:<br>
- <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
- observer. The default.<br>
- &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
- observer.<br>
- &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
- observer<br>
- &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
- observer<br>
- &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
- observer<br>
- &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
- observer that has been adjusted using a 3x3 matrix to better agree
- with the 1931 2 degree observer.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that if you select
- anything other than the default 1931 2 degree observer, that the Y
- values will not be cd/m^2, due to the Y curve not being the CIE 1924
- photopic V(&#955;) luminosity function.<br>
- <br>
- <a name="I"></a> The -<span style="font-weight: bold;">I <span
- style="font-style: italic;">b|w</span></span> options invoke
- instrument black level, and display white level compensation
- (respectively). Instrument black level drift compensation attempts
- to combat instrument black calibration drift by using a display
- black test patch as a reference. If an instrument is not
- acclimatised sufficiently to the measurement conditions, changes in
- temperature can affect the black readings. Display white level drift
- compensation attempts to combat changes in display brightness as it
- warms up by measuring a white patch every so often, and using it to
- normalise all the other readings. If just instrument black drift
- compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
- If just display white level compensation is needed, use <span
- style="font-weight: bold;">-Iw</span>. If both are needed, use <span
- style="font-weight: bold;">-Ibw</span> or <span
- style="font-weight: bold;">-Iwb</span>.<br>
- <br>
- <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
- options overrides calibration of the instrument refresh rate. This
- may be useful if the instrument supports this function and the
- refresh rate cannot be accurately calibrated from the display
- itself.<br>
- <span style="font-weight: bold;">&nbsp;<br>
- </span><a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
- option uses a non-adaptive integration time emission measurement
- mode, if the instrument supports it, such as the Eye-One Pro,
- ColorMunki, i1d3 and K10. By default an adaptive integration time
- measurement mode will be used for emission measurements, but some
- instruments support a fixed integration time mode that can be used
- with display devices. This may give faster measurement times, but
- may also give less accurate low level readings.<br>
- <br>
- <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
- option skips asking the user to place the instrument on the display.
- Normally a grey patch is displayed, and then the user is asked to
- confirm that the instrument is in place, so that readings can
- commence. This flag disables that check. This may be useful in
- automating certain operations.<br>
- <span style="font-weight: bold;"><br>
- </span><a name="C"></a> The -<span style="font-weight: bold;">C</span>
- <span style="font-weight: bold;">"command" </span>option allows a
- method of relaying each test value to some other display than that
- on the system running dispread (for instance, a photo frame, PDA
- screen etc.), by causing the given command to be invoked to the
- shell, with six arguments. The first three arguments are the RGB
- test color as integers in the range 0 to 255, the second three
- parameters are the RGB test color as floating point numbers in the
- range 0.0 to 1.0. The script or tool should relay the given color to
- the screen in some manner (e.g. by generating a raster file of the
- given color and sending it to the display being profiled), before
- returning. Note that a test window will also be created on the
- system running dispread.<br>
- <br>
- <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
- style="font-weight: bold;">"command" </span>option allows a
- method of gathering each test value from some external source, such
- as an instrument that is not directly supported by Argyll. The given
- command is involked to the shell, with six arguments. The first
- three arguments are the RGB test color as integers in the range 0 to
- 255, the second three parameters are the RGB test color as floating
- point numbers in the range 0.0 to 1.0. The script or tool should
- create a file called <span style="font-weight: bold;">"command.meas</span>"
- that contains the XYZ values for the given RGB (or measured from the
- test window) in cd/m^2 as three numbers separated by spaces, before
- returning. If the command returns a non-zero return value, dispread
- will abort. Note that a test window will also be created on the
- system running dispread.<br>
- <br>
- <a name="x"></a> The <b>-x</b> flag causes dispread to expect
- values to be manually entered for each reading, rather than using an
- instrument to do the measurements.&nbsp; This mode is ideal if your
- instrument is not supported by Argyll. XYZ values should be entered.
- It is possible to navigate about the test values being measured, so
- as to do them in any order, as well as re-do values, in case of any
- mistakes.<br>
- <br>
- <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
- parameter overrides the default serial communications flow control
- setting. The value <span style="font-weight: bold;">n</span> turns
- all flow control off, <span style="font-weight: bold;">h</span>
- sets hardware handshaking, and <span style="font-weight: bold;">x</span>
- sets Xon/Xoff handshaking. This commend may be useful in workaround
- serial communications issues with some systems and cables. <br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes communications and other
- instrument diagnostics to be printed to stdout. A level can be set
- between 1 .. 9, that may give progressively more verbose
- information, depending on the instrument. This can be useful in
- tracking down why an instrument can't connect.<br>
- <br>
- <a name="p1"></a> The final parameter on the command line is the
- base filename for the <a href="File_Formats.html#.ti1">.ti1</a>
- input file, and the <a href="File_Formats.html#.ti3">.ti3</a>
- output file. <b>dispread</b> will add the .ti1 and .ti3 extensions
- automatically.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that on an X11 system,
- if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
- is set (ie. set it to "yes"), then the presence of the XRandR 1.2
- extension will be ignored, and other extensions such as Xinerama and
- XF86VidMode extension will be used. This may be a way to work around
- buggy XRandR 1.2 implementations.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- If a large number of patches is being read, the screensaver on many
- systems can interfere with the operation of dispread. It is
- therefore advisable in these cases to manually turn off the
- screensaver before commencing the measurements.<br>
- <br>
- If communications break down with a USB connected instrument, you
- may have to unplug it, and plug it in again to recover.<br>
- <br>
- Some systems (Apple OSX in particular) have a special set of user
- interface controls ("Universal Access") that allows altering the
- display in ways designed to assist visually impaired users, by
- increasing contrast etc. This will interfere badly with any attempts
- to calibrate or profile such a system, and must be turned off in
- order to do so. Note that certain magic keyboard sequences can turn
- this on by accident.<br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ instructions</a> for your platform).<br>
+ <br>
+ <a name="c"></a> <span style="font-weight: bold;">-c</span>: The
+ instrument is assumed to communicate through a USB or serial
+ communication port, and the port can be selected with the <b>-c</b>
+ option, if the instrument is not connected to the first port. If you
+ invoke <span style="font-weight: bold;">dispread</span> so as to
+ display the usage information (i.e. "dispread -?" or "dispread --"),
+ then the discovered USB and serial ports will be listed. On
+ UNIX/Linux, a list of all possible serial ports are shown, but not
+ all of them may actually be present on your system.<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Telephoto mode is one for taking
+ emissive measurements from a distance (ie. telespectometer,
+ tele-colorimeter) mode, and typically would be used for measuring
+ projector type displays. If a device does not support a specific
+ telephoto mode, then the normal emissive mode may be suitable for
+ measuring projectors.<br>
+ <br>
+ <a name="y"></a>The <span style="font-weight: bold;">-y</span> flag
+ allows setting the Display Type. The selection typically determines
+ two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
+ href="oeminst.html">oeminst</a>. The default and Base Calibration
+ types will be indicated in the usage.<br>
+ <br>
+ <a name="s"></a><span style="font-weight: bold;">-s</span>: By
+ default only the colorimetric information (XYZ value) will be saved,
+ but for instruments that support spectral readings (such as the
+ Gretag Spectrolino), the <b>-s</b> option will save the spectral
+ readings to the .ti3 file as well.<br>
+ <br>
+ <a name="k"></a> <span style="font-weight: bold;">-k: </span>If a
+ display video lookup table calibration <a
+ href="File_Formats.html#.cal">.cal</a> file is provided, it will
+ be loaded into the display <span style="font-weight: bold;">VideoLUTs</span>
+ while the measurements are being taken, thereby being applied to the
+ measurement values, and the calibration will also included in the
+ resulting .ti3 data file, so that <a href="colprof.html">colprof</a>
+ can include it as a <span style="font-weight: bold;">vcgt</span>
+ tag in the resulting profile. This is the <span style="font-weight:
+ bold;">normal</span> way to profile a calibrated display. The
+ calibration file has usually been created using <a
+ href="dispcal.html">dispcal</a>. If the calibration file indicates
+ that the displays VideoLUTs are not accessible, or if they prove not
+ to be accessible, then dispread will switch to <span
+ style="font-weight: bold;">-K</span> mode (see below). If a
+ calibration file is not supplied using <b>-k</b> or <b>-K</b>,
+ then the display will be measured in whatever calibration state it
+ is in, and no calibration information is saved to the resulting .ti3
+ file.<br>
+ If the calibration file provided created using video range encoding
+ (dispcal -E), then the <b>-E</b> option in dispread will be
+ triggered automatically.<br>
+ <span style="font-weight: bold;">NOTE</span> that the calibration is
+ loaded into the display hardware just before the instrument starts
+ measurement, after the test window first appears.<br>
+ <br>
+ <a name="K"></a> <span style="font-weight: bold;">-K: </span>If a
+ display video lookup table calibration <a
+ href="File_Formats.html#.cal">.cal</a> file is provided, it will
+ be applied to the test values for each measurement, and also
+ included in the resulting .ti3 data file, so that <a
+ href="colprof.html">colprof</a> can include it as a <span
+ style="font-weight: bold;">vcgt</span> tag in the resulting
+ profile. This is <span style="font-weight: bold;">NOT</span>
+ normally the best way to profile a calibrated display, since the
+ frame buffer may have lower precision than the VideoLUTs output
+ values. This is the way calibration should be applied if MadVR is
+ being used to display the test patches. If a calibration file is not
+ supplied using <b>-k</b> or <b>-K</b>, then the display will be
+ measured in whatever calibration state it is in, and no calibration
+ information is saved to the resulting .ti3 file.<br>
+ If the calibration file provided created using video range encoding
+ (dispcal -E), then the <b>-E</b> option in dispread will be
+ triggered automatically.<br>
+ <br>
+ <a name="V"></a><b>-V:</b> [MSWin] If using MadVR to display test
+ patches, then enable Color Managenent (3dLut). This would be used
+ for verification measurement.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument, or 10% of the width of the
+ display if the display size is unknown. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="E"></a> The <span style="font-weight: bold;">-E</span>
+ flag causes the test values to be scaled to the Video RGB encoding
+ range of 16/255 to 235/255. If the calibration file provided using
+ the <b>-k</b> or <b>-K</b> flag was created using video range
+ encoding, then this option will be triggered automatically. This
+ will also set quantization of 8 bits (see -Z flag below). If your
+ video connection is better than 8 bits (ie. 10 or 12 bits), then you
+ may wish to raise this default.<br>
+ <br>
+ <a name="Z"></a> <b>-Z nbits </b>Normally the target device values
+ are floating point numbers that may get rounded and quantized in the
+ process of printing them or reproducing them on the display device.
+ If some of this quantization can be accounted for, it may improve
+ the accuracy of the resulting profile, and the <span
+ style="font-weight: bold;">Q</span> parameter allows this
+ quantization to be specified. The parameter is the number of binary
+ digits (bits) that the device values should be quantized to. An idea
+ of the number of bits of precision that makes its way to your
+ display can be obtained by using <a href="dispcal.html#R">dispcal
+ -R</a> If Video encoding is selected (see -E flag above), then 8
+ bits is selected by default. On systems using an VGA connection or
+ Display Port with a graphics card with VideoLUT entries with greater
+ than 8 bits depth, or if using the MadVR rendered with dithering,
+ then a higher bit depth is typically possible.<br>
+ <br>
+ <a name="n"></a><span style="font-weight: bold;">-n</span>: When
+ running on a UNIX based system that used the X11 Windowing System, <b>dispread</b>
+ normally selects the override redirect so that the test window will
+ appear above any other windows on the display. On some systems this
+ can interfere with window manager operation, and the <b>-n</b>
+ option turns this behaviour off.<br>
+ <br>
+ <a name="J"></a> The -<span style="font-weight: bold;">J</span>
+ option runs through the black and sensor relative calibration
+ routines for the Xrite DTP92 and DTP94 instrument, the black level
+ calibration for the Eye-One Display 1, and a CRT frequency
+ calibration for the Eye-One Display 2. For the black calibration the
+ instrument should be placed on an opaque, black surface, and any
+ stray light should be avoided by placing something opaque over the
+ instrument. If a Spectrolino is being used, then a white and black
+ calibration will always be performed before the instrument can be
+ placed on the display, unless the <a href="#N">-N</a> flag is used.
+ Generally it is not necessary to do a calibration every time an
+ instrument is used, just now and again. There is no point in
+ doing&nbsp; a CRT frequency calibration, as this will be done
+ automatically at the commencement of patch reading.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it. See <a href="instruments.html">Operation of particular
+ instruments</a> for more details. This may give better accuracy
+ for display measurements.<br>
+ <br>
+ <a name="w"></a>The <b>-w</b> flag disables the normalisation of
+ the white patch value to 100.0, resulting in values that are in
+ cd/m^2. This is mainly for diagnostic purposes.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4 &amp;
+ Spyder 5</span>).This can improve a colorimeters accuracy for a
+ particular type of display.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values from spectral readings or using a colorimeter
+ that has CCSS capability. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
+ observer that has been adjusted using a 3x3 matrix to better agree
+ with the 1931 2 degree observer.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you select
+ anything other than the default 1931 2 degree observer, that the Y
+ values will not be cd/m^2, due to the Y curve not being the CIE 1924
+ photopic V(&#955;) luminosity function.<br>
+ <br>
+ <a name="I"></a> The -<span style="font-weight: bold;">I <span
+ style="font-style: italic;">b|w</span></span> options invoke
+ instrument black level, and display white level compensation
+ (respectively). Instrument black level drift compensation attempts
+ to combat instrument black calibration drift by using a display
+ black test patch as a reference. If an instrument is not
+ acclimatised sufficiently to the measurement conditions, changes in
+ temperature can affect the black readings. Display white level drift
+ compensation attempts to combat changes in display brightness as it
+ warms up by measuring a white patch every so often, and using it to
+ normalise all the other readings. If just instrument black drift
+ compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
+ If just display white level compensation is needed, use <span
+ style="font-weight: bold;">-Iw</span>. If both are needed, use <span
+ style="font-weight: bold;">-Ibw</span> or <span
+ style="font-weight: bold;">-Iwb</span>.<br>
+ <br>
+ <a name="YR"></a> The -<span style="font-weight: bold;">Y R:<i>rate</i></span>
+ options overrides calibration of the instrument refresh rate. This
+ may be useful if the instrument supports this function and the
+ refresh rate cannot be accurately calibrated from the display
+ itself.<br>
+ <span style="font-weight: bold;">&nbsp;<br>
+ </span><a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro,
+ ColorMunki, i1d3 and K10. By default an adaptive integration time
+ measurement mode will be used for emission measurements, but some
+ instruments support a fixed integration time mode that can be used
+ with display devices. This may give faster measurement times, but
+ may also give less accurate low level readings.<br>
+ <br>
+ <a name="Yp"></a> The -<span style="font-weight: bold;">Y p</span>
+ option skips asking the user to place the instrument on the display.
+ Normally a grey patch is displayed, and then the user is asked to
+ confirm that the instrument is in place, so that readings can
+ commence. This flag disables that check. This may be useful in
+ automating certain operations.<br>
+ <span style="font-weight: bold;"><br>
+ </span><a name="C"></a> The -<span style="font-weight: bold;">C</span>
+ <span style="font-weight: bold;">"command" </span>option allows a
+ method of relaying each test value to some other display than that
+ on the system running dispread (for instance, a photo frame, PDA
+ screen etc.), by causing the given command to be invoked to the
+ shell, with six arguments. The first three arguments are the RGB
+ test color as integers in the range 0 to 255, the second three
+ parameters are the RGB test color as floating point numbers in the
+ range 0.0 to 1.0. The script or tool should relay the given color to
+ the screen in some manner (e.g. by generating a raster file of the
+ given color and sending it to the display being profiled), before
+ returning. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of gathering each test value from some external source, such
+ as an instrument that is not directly supported by Argyll. The given
+ command is involked to the shell, with six arguments. The first
+ three arguments are the RGB test color as integers in the range 0 to
+ 255, the second three parameters are the RGB test color as floating
+ point numbers in the range 0.0 to 1.0. The script or tool should
+ create a file called <span style="font-weight: bold;">"command.meas</span>"
+ that contains the XYZ values for the given RGB (or measured from the
+ test window) in cd/m^2 as three numbers separated by spaces, before
+ returning. If the command returns a non-zero return value, dispread
+ will abort. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="x"></a> The <b>-x</b> flag causes dispread to expect
+ values to be manually entered for each reading, rather than using an
+ instrument to do the measurements.&nbsp; This mode is ideal if your
+ instrument is not supported by Argyll. XYZ values should be entered.
+ It is possible to navigate about the test values being measured, so
+ as to do them in any order, as well as re-do values, in case of any
+ mistakes.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="p1"></a> The final parameter on the command line is the
+ base filename for the <a href="File_Formats.html#.ti1">.ti1</a>
+ input file, and the <a href="File_Formats.html#.ti3">.ti3</a>
+ output file. <b>dispread</b> will add the .ti1 and .ti3 extensions
+ automatically.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ If a large number of patches is being read, the screensaver on many
+ systems can interfere with the operation of dispread. It is
+ therefore advisable in these cases to manually turn off the
+ screensaver before commencing the measurements.<br>
+ <br>
+ If communications break down with a USB connected instrument, you
+ may have to unplug it, and plug it in again to recover.<br>
+ <br>
+ Some systems (Apple OSX in particular) have a special set of user
+ interface controls ("Universal Access") that allows altering the
+ display in ways designed to assist visually impaired users, by
+ increasing contrast etc. This will interfere badly with any attempts
+ to calibrate or profile such a system, and must be turned off in
+ order to do so. Note that certain magic keyboard sequences can turn
+ this on by accident.<br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/dispwin.html b/doc/dispwin.html
index dac6b8e..05db989 100644
--- a/doc/dispwin.html
+++ b/doc/dispwin.html
@@ -1,38 +1,38 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>dispwin</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/dispwin</b></h2>
- <h3>Summary</h3>
- This tool has several different but related functions. When given as
- a file argument an ICC profile containing vcgt "gamma" curves, or an
- Argyll video calibration .cal file, it will load that calibration
- into the chosen display. It can also install or uninstall a profile
- in the system for the chosen display, or set the display calibration
- to that in the currently installed system profile. By default it
- displays a test window the same as that used by dispcal and
- dispread, to test this functionality. It can also be used to test
- the ability to load video card LUT curves to each display, and to
- test how the console Bell will sound when used with some instruments
- (ie. Eye-One Pro).<br>
- <br>
- [Note that in OS X 10.7 Lion, changes to the default system profile
- permissions mean that you can't set a calibration persistently when
- the default system profile is being used, unless you run as root
- (ie. use sudo). Note that you do <span style="font-weight: bold;">not</span>
- need to run as root to install a user profile (-Su, the default
- install type.)]<br>
- <h3>Usage</h3>
- <font size="-1"><span style="font-family: monospace;">dispwin
- [options] [<span style="font-style: italic;">calfile</span>]</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#v">-v</a><span
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispwin</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispwin</b></h2>
+ <h3>Summary</h3>
+ This tool has several different but related functions. When given as
+ a file argument an ICC profile containing vcgt "gamma" curves, or an
+ Argyll video calibration .cal file, it will load that calibration
+ into the chosen display. It can also install or uninstall a profile
+ in the system for the chosen display, or set the display calibration
+ to that in the currently installed system profile. By default it
+ displays a test window the same as that used by dispcal and
+ dispread, to test this functionality. It can also be used to test
+ the ability to load video card LUT curves to each display, and to
+ test how the console Bell will sound when used with some instruments
+ (ie. Eye-One Pro).<br>
+ <br>
+ [Note that in OS X 10.7 Lion, changes to the default system profile
+ permissions mean that you can't set a calibration persistently when
+ the default system profile is being used, unless you run as root
+ (ie. use sudo). Note that you do <span style="font-weight: bold;">not</span>
+ need to run as root to install a user profile (-Su, the default
+ install type.)]<br>
+ <h3>Usage</h3>
+ <font size="-1"><span style="font-family: monospace;">dispwin
+ [options] [<span style="font-style: italic;">calfile</span>]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
Verbose
@@ -51,18 +51,18 @@ Verbose
-
- mode<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
- href="#display">-display displayname</a><span
- style="font-family: monospace;"> [<span style="font-weight:
- bold;">X11 only</span>] Choose X11 display name<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [<span style="font-weight: bold;">X11 only</span>] Choose the
- display from the following list (default 1),<br>
+
+ mode<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [<span style="font-weight:
+ bold;">X11 only</span>] Choose X11 display name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [<span style="font-weight: bold;">X11 only</span>] Choose the
+ display from the following list (default 1),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
and
optionally
@@ -81,9 +81,9 @@ optionally
-
- choose a different display m for Video LUT access.<br>
- </span></font><font size="-1"><span style="font-family:
+
+ choose a different display m for Video LUT access.<br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
[Not
X11]
@@ -102,9 +102,9 @@ X11]
-
- Choose the display from the following list (default 1)<br>
- </span></font><span style="font-family: monospace;">&nbsp;<a
+
+ Choose the display from the following list (default 1)<br>
+ </span></font><span style="font-family: monospace;">&nbsp;<a
href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -119,22 +119,22 @@ X11]
-
- Display via a web server at port (default 8080)</span><br>
- <span style="font-family: monospace;">&nbsp;<a
- href="dispwin.html#dmadvr">-dmadvr</a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- [MSWin] Display via MadVR Video Renderer</span><br>
+
+ Display via a web server at port (default 8080)</span><br>
+ <span style="font-family: monospace;">&nbsp;<a
+ href="dispwin.html#dmadvr">-dmadvr</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [MSWin] Display via MadVR Video Renderer</span><br>
<tt>&nbsp;</tt><tt><a href="#dcc">-dcc[:n]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- </tt><tt></tt><tt>Display via n'th ChromeCast (default 1, ? for
- list)</tt><br style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;<a href="#P">-P
- ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
- and scale it</span><br style="font-family: monospace;">
+
+ </tt><tt></tt><tt>Display via n'th ChromeCast (default 1, ? for
+ list)</tt><br style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;<a href="#P">-P
+ ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
+ and scale it</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ho,vi:
0.0
@@ -153,9 +153,9 @@ ho,vi:
-
- = left/top, 0.5 = center, 1.0 = right/bottom etc.</span><br
- style="font-family: monospace;">
+
+ = left/top, 0.5 = center, 1.0 = right/bottom etc.</span><br
+ style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ss:
0.5
@@ -174,8 +174,8 @@ ss:
-
- = half, 1.0 = normal, 2.0 = double etc.<br>
+
+ = half, 1.0 = normal, 2.0 = double etc.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -188,10 +188,10 @@ ss:
-
- ss,vs: = optional horizontal, vertical scale.<br>
- &nbsp;</span></font><font size="-1"><span style="font-family:
- monospace;"><a href="#F">-F</a>
+
+ ss,vs: = optional horizontal, vertical scale.<br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><a href="#F">-F</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Fill
whole
@@ -210,10 +210,10 @@ whole
-
- screen with black background</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
- size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
+
+ screen with black background</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span></font><font
+ size="-1"><span style="font-family: monospace;"><a href="#E">-E</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -221,25 +221,25 @@ whole
-
- </span></font><small><span style="font-family: monospace;">Video
- encode output as (16-235)/255 "TV" levels</span></small><br
- style="font-family: monospace;">
- <font size="-1"><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#i">-i</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Run forever with random values<br>
- &nbsp;<a href="#G">-G <span style="font-style: italic;">filename</span></a>
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Display RGB
- colors from CGATS file<br>
- &nbsp;</span></font><font size="-1"><a style="font-family:
- monospace;" href="#m">-m</a><span style="font-family:
- monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; Manually step through colors</span></font><br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+
+ </span></font><small><span style="font-family: monospace;">Video
+ encode output as (16-235)/255 "TV" levels</span></small><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#i">-i</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Run forever with random values<br>
+ &nbsp;<a href="#G">-G <span style="font-style: italic;">filename</span></a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Display RGB
+ colors from CGATS file<br>
+ &nbsp;</span></font><font size="-1"><a style="font-family:
+ monospace;" href="#m">-m</a><span style="font-family:
+ monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Manually step through colors</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
href="#r">-r</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Test
just
@@ -258,10 +258,10 @@ just
-
- video LUT loading &amp; Beeps<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#n">-n</a>
+
+ video LUT loading &amp; Beeps<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#n">-n</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Test
native
@@ -280,8 +280,8 @@ native
-
- display values (rather than through Video LUT&nbsp; and C.M.)<br>
+
+ display values (rather than through Video LUT&nbsp; and C.M.)<br>
&nbsp;<a href="#s">-s <span style="font-style: italic;">filename.cal</span></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Save
the
@@ -300,10 +300,10 @@ the
-
- currently loaded Video LUT to 'filename'<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#c">-c</a>
+
+ currently loaded Video LUT to 'filename'<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#c">-c</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Load
a
@@ -322,11 +322,11 @@ a
-
- linear display calibration (clear calibration)</span></font><font
- size="-1"><span style="font-family: monospace;"><br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#V">-V</a>
+
+ linear display calibration (clear calibration)</span></font><font
+ size="-1"><span style="font-family: monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#V">-V</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Verify
that
@@ -345,10 +345,10 @@ that
-
- calfile/profile cal. is currently loaded in LUT<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#I">-I</a>
+
+ calfile/profile cal. is currently loaded in LUT<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#I">-I</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -365,11 +365,11 @@ that
-
- </span></font><font size="-1"><span style="font-family:
- monospace;">Install profile for display and use it's calibration<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#U">-U</a>
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Install profile for display and use it's calibration<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#U">-U</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -386,9 +386,9 @@ that
-
- </span></font><font size="-1"><span style="font-family:
- monospace;">Un-install profile for display<br>
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Un-install profile for display<br>
&nbsp;<a href="#S">-S d</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Specify
the
@@ -407,8 +407,8 @@ the
-
- install/uninstall scope for OS X [nlu] or Vista [lu]<br>
+
+ install/uninstall scope for OS X [nlu] or Vista [lu]<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
d
is
@@ -427,11 +427,11 @@ is
-
- one of: n = network, l = local system, u = user (default)<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;">&nbsp;<a href="#L">-L</a>
+
+ one of: n = network, l = local system, u = user (default)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;">&nbsp;<a href="#L">-L</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -448,11 +448,11 @@ is
-
- </span></font><font size="-1"><span style="font-family:
- monospace;">Load installed profiles cal. into Video LUT<br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;<a href="#X">-<font size="-1">X</font></a>
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Load installed profiles cal. into Video LUT<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#X">-<font size="-1">X</font></a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -469,11 +469,11 @@ is
-
- [<span style="font-weight: bold;">X11 only</span>] Run in daemon
- loader mode for given X11 server <br>
- </span></font><font size="-1"><span style="font-family:
- monospace;">&nbsp;</span><a style="font-family: monospace;"
+
+ [<span style="font-weight: bold;">X11 only</span>] Run in daemon
+ loader mode for given X11 server <br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
href="#D">-D [level]</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Print
debug
@@ -492,14 +492,14 @@ debug
-
- diagnostics to stderr</span></font><font size="-1"><span
- style="font-family: monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;"></span><span style="font-family:
- monospace;"><br>
- &nbsp;</span></font><a style="font-family: monospace;"
- href="#p1"><font size="-1"><span style="font-family: monospace;"></span></font></a><font
- size="-1"><a style="font-family: monospace;" href="#p1"><i>calfile</i></a><span
+
+ diagnostics to stderr</span></font><font size="-1"><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ &nbsp;</span></font><a style="font-family: monospace;"
+ href="#p1"><font size="-1"><span style="font-family: monospace;"></span></font></a><font
+ size="-1"><a style="font-family: monospace;" href="#p1"><i>calfile</i></a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Load
display
@@ -518,60 +518,60 @@ display
-
- calibration (<a href="cal_format.html">.cal</a> or .icm) into
- LUT, and exit.</span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></font><br>
- <br>
- <h3>Comments<br>
- </h3>
- <a name="v"></a> The <b>-v</b> flag makes the program more
- verbose..<br>
- <br>
- <a name="display"></a><span style="font-weight: bold;">display</span>:
- When running on a UNIX based system that used the X11 Windowing
- System, <b>dispwin</b> will by default use the $DISPLAY environment
- variable to determine which display and screen to read from. This
- can be overridden by supplying an X11 display name to the <span
- style="font-weight: bold;">-display</span> option. Note that if
- Xinerama is active, you can't select the screen using $DISPLAY or
- -display, you have to select it using the <span style="font-weight:
- bold;">-d</span> parameter.<br>
- <br>
- <a name="d"></a><span style="font-weight: bold;">-d</span>: By
- default the location of the test window will be the main display. If
- the system has more than one display or screen, an alternate
- display/screen can be selected with the <span style="font-weight:
- bold;">-d</span> parameter. If you invoke <span
- style="font-weight: bold;">dispwin</span> so as to display the
- usage information (i.e. "dispcal -?" or "dispcal --"), then the
- discovered displays/screens will be listed. Multiple displays may
- not be listed if they appear as a single display to the operating
- system (ie. the multi-display support is hidden in the video card
- driver). On UNIX based system that used the X11 Windowing System,
- the <span style="font-weight: bold;">-d</span> parameter will
- override the screen specified by the $DISPLAY or <span
- style="font-weight: bold;">-display</span> parameter.<br>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
- display are not accessible (i.e. no hardware calibration
- capability), <span style="font-weight: bold;">dispwin</span> will
- will issue a warning or fail when it attempts to access them.<br>
- <br>
- On X11 the inability to access VideoLUTs could be because you are
- trying to access a remote display, and the remote display doesn't
- support the XF86VidMode extension, or perhaps you are running
- multiple monitors using NVidia TwinView, or MergedFB, and trying to
- access anything other than the primary monitor. TwinView and
- MergedFB don't properly support the XF86VidMode extension for
- multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
- to test whether the VideoLUTs are accessible for a particular
- display. See also below, on how to select a different display for
- VideoLUT access. Also note that dispcal will fail if the Visual
- depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
- 256 entries per color component, so the Visual generally needs to be
- 24 bits, 8 bits per color component.<br>
- <br>
+
+ calibration (<a href="cal_format.html">.cal</a> or .icm) into
+ LUT, and exit.</span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></font><br>
+ <br>
+ <h3>Comments<br>
+ </h3>
+ <a name="v"></a> The <b>-v</b> flag makes the program more
+ verbose..<br>
+ <br>
+ <a name="display"></a><span style="font-weight: bold;">display</span>:
+ When running on a UNIX based system that used the X11 Windowing
+ System, <b>dispwin</b> will by default use the $DISPLAY environment
+ variable to determine which display and screen to read from. This
+ can be overridden by supplying an X11 display name to the <span
+ style="font-weight: bold;">-display</span> option. Note that if
+ Xinerama is active, you can't select the screen using $DISPLAY or
+ -display, you have to select it using the <span style="font-weight:
+ bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a><span style="font-weight: bold;">-d</span>: By
+ default the location of the test window will be the main display. If
+ the system has more than one display or screen, an alternate
+ display/screen can be selected with the <span style="font-weight:
+ bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispwin</span> so as to display the
+ usage information (i.e. "dispcal -?" or "dispcal --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or <span
+ style="font-weight: bold;">-display</span> parameter.<br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
+ display are not accessible (i.e. no hardware calibration
+ capability), <span style="font-weight: bold;">dispwin</span> will
+ will issue a warning or fail when it attempts to access them.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
<a name="dnm"></a><span style="font-weight: bold;">-d n[,m]</span>Because
of
the
@@ -590,257 +590,257 @@ the
-
- difficulty cause by TwinView and MergedFB in X11 based systems, you
- can optionally specify a separate display number after the display
- that is going to be used to present test patches, for accessing the
- VideoLUT hardware. This must be specified as a single string, e.g. <span
- style="font-weight: bold;">-d 1,2</span> . Some experimentation
- may be needed on such systems, to discover what screen has access to
- the VideoLUT hardware, and which screens the test patches appear on.
- You may be able to calibrate one screen, and then share the
- calibration with another screen. Profiling can be done independently
- to calibration.<br>
- <br>
- <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
- <span style="font-weight: bold;">-dweb:<i>port</i></span> starts a
- standalone web server on your machine, which then allows a local or
- remote web browser to display the the color test patches. By default
- port <span style="font-weight: bold;">8080</span> is used, but this
- can be overridden by appending a <span style="font-weight: bold;">:</span>
- and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
- The URL will be <span style="font-weight: bold;">http://</span>
- then name of the machine or its I.P. address followed by a colon and
- the port number - e.g something like <span style="font-weight:
- bold;">http://192.168.0.1:8080</span>. If you use the verbose
- option (<span style="font-weight: bold;">-v</span>) then a likely
- URL will be printed once the server is started, or you could run <span
- style="font-weight: bold;">ipconfig</span> (MSWin) or <span
- style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
- and identify an internet address for your machine that way. <b>JavaScript</b>
- needs to be enabled in your web browser for this to work. You may
- have to modify any firewall to permit port 8080 to be accessed on
- your machine.<br>
- <br>
- Note that if you use this method of accessing a display, that there
- is no access to the display Video Lookup tables, and that any
- operation that depends on accessing the VideoLUTs will either
- generate a warning or fail.<br>
- <br>
- <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
- [MSWin only] causes test patches to be displayed using the MadVR
- video renderer. Note that will have to start <b>MadTPG</b> before
- running dispread, and that while you can adjust the "Test Pattern
- Configuration" controls, you should <u>not</u> normally alter the
- "Existing Calibration" controls, as dispread will set these
- appropriately. See <a href="#n">-n</a> flag.<br>
- <br>
- <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
- causes test patches to be displayed using and available <a
- href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
- your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
- local network. Note that the ChromeCast as a test patch source is
- probably the<b> least accurate</b> of your choices, since it
- up-samples the test patch and transforms from RGB to YCC and back,
- but should be accurate within ± 1 bit. You may have to modify any
- firewall to permit port 8081 to be accessed on your machine if it
+
+ difficulty cause by TwinView and MergedFB in X11 based systems, you
+ can optionally specify a separate display number after the display
+ that is going to be used to present test patches, for accessing the
+ VideoLUT hardware. This must be specified as a single string, e.g. <span
+ style="font-weight: bold;">-d 1,2</span> . Some experimentation
+ may be needed on such systems, to discover what screen has access to
+ the VideoLUT hardware, and which screens the test patches appear on.
+ You may be able to calibrate one screen, and then share the
+ calibration with another screen. Profiling can be done independently
+ to calibration.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:<i>port</i></span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>JavaScript</b>
+ needs to be enabled in your web browser for this to work. You may
+ have to modify any firewall to permit port 8080 to be accessed on
+ your machine.<br>
+ <br>
+ Note that if you use this method of accessing a display, that there
+ is no access to the display Video Lookup tables, and that any
+ operation that depends on accessing the VideoLUTs will either
+ generate a warning or fail.<br>
+ <br>
+ <a name="dmadvr"></a><span style="font-weight: bold;">-dmadvr</span>
+ [MSWin only] causes test patches to be displayed using the MadVR
+ video renderer. Note that will have to start <b>MadTPG</b> before
+ running dispread, and that while you can adjust the "Test Pattern
+ Configuration" controls, you should <u>not</u> normally alter the
+ "Existing Calibration" controls, as dispread will set these
+ appropriately. See <a href="#n">-n</a> flag.<br>
+ <br>
+ <a name="dcc"></a><span style="font-weight: bold;">-dcc</span> or <b>-dcc:<i>no</i></b>
+ causes test patches to be displayed using and available <a
+ href="http://en.wikipedia.org/wiki/Chromecast">ChromeCast</a> to
+ your TV. Use <b>-dcc:?</b> to display a list of ChromeCasts on your
+ local network. Note that the ChromeCast as a test patch source is
+ probably the<b> least accurate</b> of your choices, since it
+ up-samples the test patch and transforms from RGB to YCC and back,
+ but should be accurate within ± 1 bit. You may have to modify any
+ firewall to permit port 8081 to be accessed on your machine if it
falls back to the Default receiver (see <a href="Installing.html">installation
-
- instructions</a> for your platform).<br>
- <br>
- <a name="P"></a> The <span style="font-weight: bold;">-P</span>
- parameter allows you to position and size the test patch window. By
- default it is places in the center of the screen, and sized
- appropriately for the type of instrument, or 10% of the width of the
- display if the display size is unknown.. The <span
- style="font-weight: bold;">ho</span> and <span
- style="font-weight: bold;">vo</span> values govern the horizontal
- and vertical offset respectively. A value of 0.0 positions the
- window to the far left or top of the screen, a value of 0.5
- positions it in the center of the screen (the default), and 1.0
- positions it to the far right or bottom of the screen. If three
- parameters are provided, then the <span style="font-weight: bold;">ss</span>
- parameter is a scale factor for the test window size. A value of 0.5
- for instance, would produce a half sized window. A value of 2.0 will
- produce a double size window. If four parameters are provided, then
- the last two set independent horizontal and vertical scaling
- factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
- specified as a single string (no space between the numbers and the
- comma). For example, to create a double sized test window at the top
- right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
- . To create a window twice as wide as high: <span
- style="font-weight: bold;">-P 1,0,2,1</span>.<br>
- <br>
- <a name="F"></a> The <span style="font-weight: bold;">-F</span>
- flag causes the while screen behind the test window to be masked
- with black. This can aid black accuracy when measuring CRT displays
- or projectors.<br>
- <br>
- <a name="E"></a> The <span style="font-weight: bold;">-E</span>
- flag causes the test values to be scaled to the Video RGB encoding
- range of 16/255 to 235/255. Note that this is not applicable if the
- MadVR render is being used to display patches, as MadVR should be
- configured for Video encoding instead.<br>
- <br>
- By default <span style="font-weight: bold;">dispwin</span> will put
- a test window on the selected display, and display some test colors,
- before darkening&nbsp; then brightening the screen by loading video
- LUT values, test the bell sounds, then restore the original values
- and exit.<br>
- <br>
- If the&nbsp;<a name="i"></a><span style="font-weight: bold;">-i</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will display the preset sequence, then random test colors forever.<br>
- <br>
- If the&nbsp;<a name="G"></a><span style="font-weight: bold;">-G</span>
- parameter is set, then <span style="font-weight: bold;">dispwin</span>
- will display the sequence of RGB color in the supplied CGATS file,
- e.g. a .ti1 file. Typically this might the used with the <span
- style="font-weight: bold;">-m</span> option to manually measure a
- set of test patches.<br>
- <br>
- If the&nbsp;<a name="m"></a><span style="font-weight: bold;">-m</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will display the preset sequence then exits, but advances manually
- after each return key.<br>
- <br>
- If the&nbsp;<a name="r"></a><span style="font-weight: bold;">-r</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will test just the loading of video LUT values by first darkening,
- then lightening the screen, before exiting.<br>
- <br>
- If the&nbsp;<a name="n"></a><span style="font-weight: bold;">-n</span>
- flag is set, then <span style="font-weight: bold;">dispwin</span>
- will display the colors directly on the display, rather than having
- the color values translated through the currently loaded Video LUTs.
- In the case of using the MadVR renderer to display the patches, any
- 3dLut will also be disabled.<br>
- <br>
- <a name="s"></a> If a <span style="font-weight: bold;">-s <span
- style="font-style: italic;">filename.cal</span></span> option is
- used, then rather than displaying a test window, <span
- style="font-weight: bold;">dispwin</span> will save the currently
- loaded calibration curves to the given calibration file. Note that
- other functions such as clearing or loading a calibration can be
- performed after this action.<br>
- <br>
- <a name="c"></a> If a <span style="font-weight: bold;">-c</span>
- flag is used, then rather than displaying a test window, <span
- style="font-weight: bold;">dispwin</span> will load the selected
- display with a linear set of Video LUT curves, effectively clearing
- the calibration, and will then exit. Note that other functions such
- as loading a calibration can be performed after this action.<span
- style="font-style: italic;"></span><br>
- <br>
- <a name="V"></a> If a <span style="font-weight: bold;">-V</span>
- flag is used, then rather than loading the calibration specified as
- the final argument, the currently loaded calibration will be
- verified as being the same as the given calibration file. If this is
- combined with the <span style="font-weight: bold;"><span
- style="font-weight: bold;">-L</span></span> flag, the currently
- loaded calibration will be verified as being the same as the
- installed system profile for the display.<br>
- <br>
- <a name="I"></a><span style="font-weight: bold;">-I</span>: The ICC
- profile specified as the final argument will be installed as the
- default operating system profile for the chosen display, and the
- display calibration will be set to the calibration tag ('vcgt' tag,
- if any) in that profile.. On MSWindows and OS X this means that the
- profile will be copied to the appropriate color profile directory
- and registered with the operating system. For Linux X11 systems, the
- profile will be installed using the <a href="ucmm.html">ucmm</a>
- convention, and the X11 _ICC_PROFILE property in the root window,
- and also the the XrandR 1.2 X11 _ICC_PROFILE output property on
- systems that are running XrandR 1.2 or later. The latter is
- following this <a
- href="http://www.burtonini.com/computing/x-icc-profiles-spec-0.2.html">convention</a>
- for allowing applications to locate the display profile for a
- particular X11 display, and expands it to accomodate XrandR 1.2.
- Note that for X11 systems, the properties are not persistent, and
- will need to be loaded each time the X11 server is started (see the
- <a href="#L">-L</a> flag). To make sure that the profile calbration
- 'vcgt' tag gets loaded into the Graphics Card at system start,
- please read the guide <a href="dispprofloc.html">here</a>.<br>
- <br>
- <a name="U"></a><span style="font-weight: bold;">-U</span>: The ICC
- profile specified as the final argument will be un-installed as the
- default operating system profile for the chosen display. The display
- calibration will remain unchanged.<br>
- <br>
- <a name="S"></a><span style="font-weight: bold;">-S</span> d: Some
- systems have more than one profile scope that an installed profile
- will apply to, and this parameter allows overriding the default user
- scope. On OS X, there is a choice of three scopes: <span
- style="font-weight: bold;">n</span>: for network scope, if people
- are sharing profiles over a network, <span style="font-weight:
- bold;">l</span>: local system scope, which installs the profile
- for all users of a system, and the default <span
- style="font-weight: bold;">u</span>, which covers just the user
- installing the profile. On Linux or Microsoft Vista, just the local
- system <span style="font-weight: bold;">l</span> and user <span
- style="font-weight: bold;">u</span> scope are available. Note that
- you may need to run dispwin with elevated privileges(sudo) to be
- able to successfully use network or local system scope. This option
- also applies to uninstalling a profile. Note that to install a user
- profile for the root account, you will have to login as root (sudo
- will not achieve this).<br>
- <br>
- <a name="L"></a> <span style="font-weight: bold;">-L</span>: This
- option fetches the current installed system profile for the chosen
- display, and sets the display to the calibration tag ('vcgt' tag, if
- any) in the profile. This is a convenient way of initializing the
- display on system startup from the installed display profile, if the
- system doesn't not do this automatically .<br>
- <br>
- <a name="X"></a> <span style="font-weight: bold;">-X</span>: Daemon
- mode (experimental). When running on a UNIX based system that used
- the X11 Windowing System, this option runs dispwin in a "daemon"
- mode where it monitors the given X11 server, waiting for any changes
- in monitors that may require loading a matching ICC profile (ie.
- such as re-configuring, plugging in a different monitor etc.)&nbsp;
- This only works if XRandR 1.2 is available on the server. By default
- dispwin runs silently, and will not terminate. If the <span
- style="font-weight: bold;">-v</span> option is given, it will emit
- messages to stdout to show what it is doing. When it is first
- invoked, it will load the installed profiles of all the screens of
- the given X11 server.<br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes diagnostics to be printed
- to stdout. A level can be set between 1 .. 9, that may give
- progressively more verbose information. This can be useful in
- tracking down why an operation fails.<br>
- <br>
- <a name="p1"></a> The final optional parameter on the command line
- is the name of an ICC profile that contains a Video LUT <span
- style="font-weight: bold;">vcgt</span> tag, or an Argyll <a
- href="cal_format.html">.cal</a> format display calibration. If
- this parameter is provided, then the selected display will be loaded
- with the given calibration. If the <span style="font-weight: bold;">-V</span>
- flag was given, then it is verified that this calibration is the
- currently loaded one.&nbsp; This may be useful in initializing a
- system to the current calibration on system startup, although a
- better way may be to install the profile (<span style="font-weight:
- bold;">-I</span> option), and then just use <span
- style="font-weight: bold;">-L</span>. Note that the vcgt tag
- interpretation within Argyll is consistent with that of the
- originators of the tag. Other ICC profile vcgt implementations may
- not be so consistent.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> that on an X11 system,
- if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
- is set (ie. set it to "yes"), then the presence of the XRandR 1.2
- extension will be ignored, and other extensions such as Xinerama and
- XF86VidMode extension will be used. This may be a way to work around
- buggy XRandR 1.2 implementations.<br>
- <span style="font-weight: bold;"><br>
- NOTE</span> on MSWin systems that you will have to disable any
- other calibration installer program if you want to be able to
- control calibration using dispwin. Note also that there are other
- programs that will interfere with calibration loading, such as
- igfxpers.exe that gets installed with nVidia "Optimus" technology.<br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ instructions</a> for your platform).<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument, or 10% of the width of the
+ display if the display size is unknown.. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="E"></a> The <span style="font-weight: bold;">-E</span>
+ flag causes the test values to be scaled to the Video RGB encoding
+ range of 16/255 to 235/255. Note that this is not applicable if the
+ MadVR render is being used to display patches, as MadVR should be
+ configured for Video encoding instead.<br>
+ <br>
+ By default <span style="font-weight: bold;">dispwin</span> will put
+ a test window on the selected display, and display some test colors,
+ before darkening&nbsp; then brightening the screen by loading video
+ LUT values, test the bell sounds, then restore the original values
+ and exit.<br>
+ <br>
+ If the&nbsp;<a name="i"></a><span style="font-weight: bold;">-i</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the preset sequence, then random test colors forever.<br>
+ <br>
+ If the&nbsp;<a name="G"></a><span style="font-weight: bold;">-G</span>
+ parameter is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the sequence of RGB color in the supplied CGATS file,
+ e.g. a .ti1 file. Typically this might the used with the <span
+ style="font-weight: bold;">-m</span> option to manually measure a
+ set of test patches.<br>
+ <br>
+ If the&nbsp;<a name="m"></a><span style="font-weight: bold;">-m</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the preset sequence then exits, but advances manually
+ after each return key.<br>
+ <br>
+ If the&nbsp;<a name="r"></a><span style="font-weight: bold;">-r</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will test just the loading of video LUT values by first darkening,
+ then lightening the screen, before exiting.<br>
+ <br>
+ If the&nbsp;<a name="n"></a><span style="font-weight: bold;">-n</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the colors directly on the display, rather than having
+ the color values translated through the currently loaded Video LUTs.
+ In the case of using the MadVR renderer to display the patches, any
+ 3dLut will also be disabled.<br>
+ <br>
+ <a name="s"></a> If a <span style="font-weight: bold;">-s <span
+ style="font-style: italic;">filename.cal</span></span> option is
+ used, then rather than displaying a test window, <span
+ style="font-weight: bold;">dispwin</span> will save the currently
+ loaded calibration curves to the given calibration file. Note that
+ other functions such as clearing or loading a calibration can be
+ performed after this action.<br>
+ <br>
+ <a name="c"></a> If a <span style="font-weight: bold;">-c</span>
+ flag is used, then rather than displaying a test window, <span
+ style="font-weight: bold;">dispwin</span> will load the selected
+ display with a linear set of Video LUT curves, effectively clearing
+ the calibration, and will then exit. Note that other functions such
+ as loading a calibration can be performed after this action.<span
+ style="font-style: italic;"></span><br>
+ <br>
+ <a name="V"></a> If a <span style="font-weight: bold;">-V</span>
+ flag is used, then rather than loading the calibration specified as
+ the final argument, the currently loaded calibration will be
+ verified as being the same as the given calibration file. If this is
+ combined with the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-L</span></span> flag, the currently
+ loaded calibration will be verified as being the same as the
+ installed system profile for the display.<br>
+ <br>
+ <a name="I"></a><span style="font-weight: bold;">-I</span>: The ICC
+ profile specified as the final argument will be installed as the
+ default operating system profile for the chosen display, and the
+ display calibration will be set to the calibration tag ('vcgt' tag,
+ if any) in that profile.. On MSWindows and OS X this means that the
+ profile will be copied to the appropriate color profile directory
+ and registered with the operating system. For Linux X11 systems, the
+ profile will be installed using the <a href="ucmm.html">ucmm</a>
+ convention, and the X11 _ICC_PROFILE property in the root window,
+ and also the the XrandR 1.2 X11 _ICC_PROFILE output property on
+ systems that are running XrandR 1.2 or later. The latter is
+ following this <a
+ href="http://www.burtonini.com/computing/x-icc-profiles-spec-0.2.html">convention</a>
+ for allowing applications to locate the display profile for a
+ particular X11 display, and expands it to accomodate XrandR 1.2.
+ Note that for X11 systems, the properties are not persistent, and
+ will need to be loaded each time the X11 server is started (see the
+ <a href="#L">-L</a> flag). To make sure that the profile calbration
+ 'vcgt' tag gets loaded into the Graphics Card at system start,
+ please read the guide <a href="dispprofloc.html">here</a>.<br>
+ <br>
+ <a name="U"></a><span style="font-weight: bold;">-U</span>: The ICC
+ profile specified as the final argument will be un-installed as the
+ default operating system profile for the chosen display. The display
+ calibration will remain unchanged.<br>
+ <br>
+ <a name="S"></a><span style="font-weight: bold;">-S</span> d: Some
+ systems have more than one profile scope that an installed profile
+ will apply to, and this parameter allows overriding the default user
+ scope. On OS X, there is a choice of three scopes: <span
+ style="font-weight: bold;">n</span>: for network scope, if people
+ are sharing profiles over a network, <span style="font-weight:
+ bold;">l</span>: local system scope, which installs the profile
+ for all users of a system, and the default <span
+ style="font-weight: bold;">u</span>, which covers just the user
+ installing the profile. On Linux or Microsoft Vista, just the local
+ system <span style="font-weight: bold;">l</span> and user <span
+ style="font-weight: bold;">u</span> scope are available. Note that
+ you may need to run dispwin with elevated privileges(sudo) to be
+ able to successfully use network or local system scope. This option
+ also applies to uninstalling a profile. Note that to install a user
+ profile for the root account, you will have to login as root (sudo
+ will not achieve this).<br>
+ <br>
+ <a name="L"></a> <span style="font-weight: bold;">-L</span>: This
+ option fetches the current installed system profile for the chosen
+ display, and sets the display to the calibration tag ('vcgt' tag, if
+ any) in the profile. This is a convenient way of initializing the
+ display on system startup from the installed display profile, if the
+ system doesn't not do this automatically .<br>
+ <br>
+ <a name="X"></a> <span style="font-weight: bold;">-X</span>: Daemon
+ mode (experimental). When running on a UNIX based system that used
+ the X11 Windowing System, this option runs dispwin in a "daemon"
+ mode where it monitors the given X11 server, waiting for any changes
+ in monitors that may require loading a matching ICC profile (ie.
+ such as re-configuring, plugging in a different monitor etc.)&nbsp;
+ This only works if XRandR 1.2 is available on the server. By default
+ dispwin runs silently, and will not terminate. If the <span
+ style="font-weight: bold;">-v</span> option is given, it will emit
+ messages to stdout to show what it is doing. When it is first
+ invoked, it will load the installed profiles of all the screens of
+ the given X11 server.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes diagnostics to be printed
+ to stdout. A level can be set between 1 .. 9, that may give
+ progressively more verbose information. This can be useful in
+ tracking down why an operation fails.<br>
+ <br>
+ <a name="p1"></a> The final optional parameter on the command line
+ is the name of an ICC profile that contains a Video LUT <span
+ style="font-weight: bold;">vcgt</span> tag, or an Argyll <a
+ href="cal_format.html">.cal</a> format display calibration. If
+ this parameter is provided, then the selected display will be loaded
+ with the given calibration. If the <span style="font-weight: bold;">-V</span>
+ flag was given, then it is verified that this calibration is the
+ currently loaded one.&nbsp; This may be useful in initializing a
+ system to the current calibration on system startup, although a
+ better way may be to install the profile (<span style="font-weight:
+ bold;">-I</span> option), and then just use <span
+ style="font-weight: bold;">-L</span>. Note that the vcgt tag
+ interpretation within Argyll is consistent with that of the
+ originators of the tag. Other ICC profile vcgt implementations may
+ not be so consistent.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <span style="font-weight: bold;"><br>
+ NOTE</span> on MSWin systems that you will have to disable any
+ other calibration installer program if you want to be able to
+ control calibration using dispwin. Note also that there are other
+ programs that will interfere with calibration loading, such as
+ igfxpers.exe that gets installed with nVidia "Optimus" technology.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/fakeread.html b/doc/fakeread.html
index e8c353e..376e971 100644
--- a/doc/fakeread.html
+++ b/doc/fakeread.html
@@ -240,7 +240,7 @@
digits (bits) that the device values should be quantized to. An idea
of the number of bits of precision that makes its way to your
display can be obtained by using <a
- href="dispcal.html#R">dispcal -R</a> If
+ href="file:///D:/src/argyll/doc/dispcal.html#R">dispcal -R</a> If
Video encoding is selected (see -E flag above), then 8 bits is
selected by default. On systems using an VGA connection or Display
Port with a graphics card with VideoLUT entries with greater than 8
diff --git a/doc/iccgamut.html b/doc/iccgamut.html
index ead8f7c..47df32c 100644
--- a/doc/iccgamut.html
+++ b/doc/iccgamut.html
@@ -16,7 +16,7 @@
in Lab or CIECAM02 Jab colorspace, and can also representing the
gamut as a X3DOM file.<br>
<br>
- See <a href="3dformat.html">3D Viewing
+ See <a href="file:///D:/src/argyll/doc/3Df.htmlormat">3D Viewing
Format</a> for switching to VRML or X3D output format.<br>
<h3>Usage<br>
</h3>
@@ -235,7 +235,7 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></small>&nbsp;</span><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
g:glare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare light % of ambient
- (default 5)</span><br style="font-family: monospace;">
+ (default 1)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
diff --git a/doc/illumread.html b/doc/illumread.html
index 3ee7aa5..9b65b2f 100644
--- a/doc/illumread.html
+++ b/doc/illumread.html
@@ -1,309 +1,309 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>illumread</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- <meta name="author" content="Graeme Gill">
- </head>
- <body>
- <h2><b>spectro/illumread</b></h2>
- <h3>Summary</h3>
- Use an instrument or instruments to measure an illuminant spectrum,
- including estimate its Ultra Violet content. A combination of direct
- illumination readings and readings from a piece of paper having some
- FWA content are used for this. (If the UV content is not needed, or
- a suitable instrument is not available, then <a
- href="spotread.html">spotread</a> should be used instead.)<br>
- <h3>Usage Summary</h3>
- <small><span style="font-family: monospace;">illumread [-options]
- illuminant.sp</span><br style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#v">-v</a><span
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>illumread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/illumread</b></h2>
+ <h3>Summary</h3>
+ Use an instrument or instruments to measure an illuminant spectrum,
+ including estimate its Ultra Violet content. A combination of direct
+ illumination readings and readings from a piece of paper having some
+ FWA content are used for this. (If the UV content is not needed, or
+ a suitable instrument is not available, then <a
+ href="spotread.html">spotread</a> should be used instead.)<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">illumread [-options]
+ illuminant.sp</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;
-
- &nbsp; &nbsp; Verbose mode</span><span style="font-family:
- monospace;"></span></small><small><span style="font-family:
- monospace;"></span></small><br style="font-family: monospace;">
- <small><span style="font-family: monospace;"></span><span
- style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#S">-S</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp; &nbsp; &nbsp; Plot the readings in a graph window.</span><br
- style="font-family: monospace;">
- <span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#c">-c comport</a><span
+
+ &nbsp; &nbsp; Verbose mode</span><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;"></span></small><br style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#S">-S</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; &nbsp; Plot the readings in a graph window.</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c comport</a><span
style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Set
-
- COM port, 1..4 (default 1)</span><span style="font-family:
- monospace;"></span><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></small><small><span
- style="font-family: monospace;"></span></small><font size="-1"><span
- style="font-family: monospace;"></span></font><font size="-1"><span
- style="font-family: monospace;"><br>
- </span></font><font size="-1"><span style="font-family:
+
+ COM port, 1..4 (default 1)</span><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"></span></small><font size="-1"><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Disable
-
- initial calibration of instrument</span></font> if possible<br>
- <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#H">-H</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode
- (if available)<br>
+
+ initial calibration of instrument</span></font> if possible<br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode
+ (if available)<br>
<font size="-1">&nbsp;<a href="#Yr">-Y r</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- Set refresh measurement mode</font><br>
- </span></font><font size="-1"><span style="font-family:
+
+ Set refresh measurement mode</font><br>
+ </span></font><font size="-1"><span style="font-family:
monospace;">&nbsp;<a href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Override
-
- serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br>
- <small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#T">-T</a><span
- style="font-family: monospace;">
+
+ serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#T">-T</a><span
+ style="font-family: monospace;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- Test mode - restore &amp; save measurements to<br>
+
+ Test mode - restore &amp; save measurements to<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- *_i.sp, *_r.sp, *_p.sp, *_mpir.sp, *_cpir.sp files<br>
- </span></small> <small><span style="font-family: monospace;">&nbsp;</span><a
- style="font-family: monospace;" href="#D">-D [level]</a><span
- style="font-family: monospace;">
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- Print debug diagnostics to stderr</span></small><br>
- &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+
+ *_i.sp, *_r.sp, *_p.sp, *_mpir.sp, *_cpir.sp files<br>
+ </span></small> <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D [level]</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Print debug diagnostics to stderr</span></small><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
href="#file"><span style="font-style: italic;">illuminant.sp</span></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
File
-
- to save measurement to<br style="font-family: monospace;">
- </span></font><small><span style="font-family: monospace;"></span><span
- style="font-family: monospace;"></span></small><br>
- <h3>Usage Details and Discussion</h3>
- <b>illumread</b> uses a suitable instrument to read an illuminant
- spectrum, and uses an indirect method to estimate the Ultra Violet
- content of the illuminant, so as to provide better accuracy with <a
- href="FWA.html">FWA compensation</a>. An instrument or combination
- of instruments capable of spectral measurement of both emissive
- measurement and reflective measurement without a U.V. filter is
- required for this.<br>
- <br>
- <a name="v"></a>The <b>-v</b> flag causes extra information to be
- printed out during chartread operation.<br>
- <br>
- <a name="S"></a>The <b>-S</b> flag enables the plotting of the
- spectral reflectance/transmittance values. You must select the plot
- window and strike a key in it to continue with another measurement.<br>
- <br>
- <a name="c"></a> The instrument is assumed to communicate through a
- USB or serial communication port, and the initial port can be
- selected with the <b>-c</b> option, if the instrument is not
- connected to the first port. If you invoke <span
- style="font-weight: bold;">illumread</span> so as to display the
- usage information (i.e. "illumread -?" or "illumread --"), then the
- discovered USB and serial ports will be listed. On UNIX/Linux, a
- list of all possible serial ports are shown, but not all of them may
- actually be present on your system.<br>
- <br>
- <a name="N"></a><span style="font-weight: bold;">-N</span> Any
- instrument that requires regular calibration will ask for
- calibration on initial start-up. Sometimes this can be awkward if
- the instrument is being mounted in some sort of measuring jig, or
- annoying if several sets of readings are being taken in quick
- succession. The -<span style="font-weight: bold;">N</span>
- suppresses this initial calibration if a valid and not timed out
- previous calibration is recorded in the instrument or on the host
- computer. It is advisable to only use this option on the second and
- subsequent measurements in a single session.<br>
- <br>
- <a name="H"></a> The -<span style="font-weight: bold;">H</span>
- option turns on high resolution spectral mode, if the instrument
- supports it. See <a href="instruments.html">Operation of particular
- instruments</a> for more details.<br>
- <br>
- <a name="Yr"></a> The -<span style="font-weight: bold;">Y r</span>
- option turns on refresh mode measurement, if the instrument supports
- it. This may improve the repeatability of measurements of
- illuminants that have a repetitive flicker.<br>
- <br>
- <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
- parameter overrides the default serial communications flow control
- setting. The value <span style="font-weight: bold;">n</span> turns
- all flow control off, <span style="font-weight: bold;">h</span>
- sets hardware handshaking, and <span style="font-weight: bold;">x</span>
- sets Xon/Xoff handshaking. This commend may be useful in workaround
- serial communications issues with some systems and cables. <br>
- <br>
- <a name="T"></a>The <b>-T</b> flag invokes the test mode. In test
- mode the three measurements are saved to files <i>illuminant</i><i>_i.sp</i>
- (Illuminant spectrum), <i>illuminant</i><i>_r.sp</i> (Illuminant
- off paper spectrum), and <i>illuminant_p.sp (</i>Instrument
- measured paper reflectance spectrum), and these will be loaded if
- discovered, allowing a replay of the calculation without requiring
- any measurement. In addition, two diagnostic files <i>illuminant</i><i>_mpir.sp</i>
+
+ to save measurement to<br style="font-family: monospace;">
+ </span></font><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><br>
+ <h3>Usage Details and Discussion</h3>
+ <b>illumread</b> uses a suitable instrument to read an illuminant
+ spectrum, and uses an indirect method to estimate the Ultra Violet
+ content of the illuminant, so as to provide better accuracy with <a
+ href="FWA.html">FWA compensation</a>. An instrument or combination
+ of instruments capable of spectral measurement of both emissive
+ measurement and reflective measurement without a U.V. filter is
+ required for this.<br>
+ <br>
+ <a name="v"></a>The <b>-v</b> flag causes extra information to be
+ printed out during chartread operation.<br>
+ <br>
+ <a name="S"></a>The <b>-S</b> flag enables the plotting of the
+ spectral reflectance/transmittance values. You must select the plot
+ window and strike a key in it to continue with another measurement.<br>
+ <br>
+ <a name="c"></a> The instrument is assumed to communicate through a
+ USB or serial communication port, and the initial port can be
+ selected with the <b>-c</b> option, if the instrument is not
+ connected to the first port. If you invoke <span
+ style="font-weight: bold;">illumread</span> so as to display the
+ usage information (i.e. "illumread -?" or "illumread --"), then the
+ discovered USB and serial ports will be listed. On UNIX/Linux, a
+ list of all possible serial ports are shown, but not all of them may
+ actually be present on your system.<br>
+ <br>
+ <a name="N"></a><span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it. See <a href="instruments.html">Operation of particular
+ instruments</a> for more details.<br>
+ <br>
+ <a name="Yr"></a> The -<span style="font-weight: bold;">Y r</span>
+ option turns on refresh mode measurement, if the instrument supports
+ it. This may improve the repeatability of measurements of
+ illuminants that have a repetitive flicker.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="T"></a>The <b>-T</b> flag invokes the test mode. In test
+ mode the three measurements are saved to files <i>illuminant</i><i>_i.sp</i>
+ (Illuminant spectrum), <i>illuminant</i><i>_r.sp</i> (Illuminant
+ off paper spectrum), and <i>illuminant_p.sp (</i>Instrument
+ measured paper reflectance spectrum), and these will be loaded if
+ discovered, allowing a replay of the calculation without requiring
+ any measurement. In addition, two diagnostic files <i>illuminant</i><i>_mpir.sp</i>
(Measured paper under illuminant spectrum) and <i>illuminant</i><i>_cpir.sp
-
- (</i>Computed paper under illuminant spectrum) will be saved.<br>
- <br>
- <a name="D"></a>The <b>-D</b> flag causes communications and other
- instrument diagnostics to be printed to stdout. A level can be set
- between 1 .. 9, that may give progressively more verbose
- information, depending on the instrument. This can be useful in
- tracking down why an instrument can't connect.<br>
- <br>
- <a name="file"></a>The <span style="font-weight: bold; font-style:
- italic;">illuminant.sp</span> is the name of the file to save the
- resulting illuminant spectrum to. The format used is <a
- href="File_Formats.html#.sp">.sp</a>.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- Unlike the other measurement utilities, <span style="font-weight:
- bold;">illumread</span> doesn't connect to the instrument until it
- is about to make a measurement. This allows for the possibility of
- using a different instrument for each measurement.<br>
- <br>
- It will display a menu:<br>
- <br>
- Press 1 .. 6<br>
- 1) Measure direct illuminant<br>
- 2) Measure illuminant reflected from paper<br>
- 3) Measure paper<br>
- 4) Select another instrument, Currently 1 'usb:/bus4/dev2/
- (GretagMacbeth i1 Pro)'<br>
- 5) Compute illuminant spectrum, average result with 0 previous
- readings &amp; save it<br>
- 6) Compute illuminant spectrum from this reading &amp; save result<br>
- 7) Exit<br>
- <br>
- There are three measurements to be made, after which the illuminant
- can be computed and saved. Before each measurement, the instrument
- may need calibrating.<br>
- <br>
- The first measurement needs a spectral instrument capable of reading
- in an ambient or emissive mode. For instance, a Spectrolino, Eye-One
- Pro or ColorMunki would be suitable instruments.<br>
- <br>
- The second measurement needs a spectral instrument capable of
- reading in an projector or emissive mode. For instance, a
- Spectrolino, Eye-One Pro or ColorMunki would be suitable
- instruments.<br>
- <br>
- The third measurement needs a spectral instrument capable of reading
- in reflective mode with UV included. For instance, a Spectrolino,
- Eye-One Pro, DTP20, DTP22 or&nbsp; DTP41 would be suitable
- instruments, as long as they are not fitted with UV filters.<br>
- <br>
- To be able to estimate the level of Ultra Violet (UV) light in the
- illuminant, a reasonable sized piece of white paper needs to be
- used. The paper should have some noticeable level of FWA
- (Fluorescent Whitener Additive, or Optical Brightening Agents) in
- it, so that it responds to UV light. A piece of cheap copier paper
- is ideal, since cheap paper is typically whitened with large amounts
- of FWA. If the paper is thin (less than 160 gsm) then two or three
- sheets should be used to prevent any background showing through. If
- the intention is to use the illuminant spectrum for proofing to a
- particular paper, then it's best to use the intended paper for this
- purpose.<br>
- <br>
- The first measurement <span style="font-weight: bold;">1)</span>,
- is to use either the ambient or emissive measurement mode to measure
- the illumination directly.<br>
- <br>
- <div style="margin-left: 40px;">If the instrument supports an
- ambient measurement capability, then it will be used. If the
- insrument does not have an ambient mode, then an emissive
- measurement mode can be used, although typically many illuminants
- are too bright to directly point the instrument at. A work-around
- is to reflect the illuminant from a spectrally flat white surface.
- A good candidate for this is a piece of white, fine textured
- polystyrene foam. [The suitability of a reflector can be checked
- using <span style="font-weight: bold;">spotread -S</span> to
- check that the reflection characteristic is close to flat.]<br>
- <br>
- <img style="width: 228px; height: 300px;" alt="Measuring Ambient"
- src="illumread_1.jpg"><img style="width: 141px; height: 282px;"
- alt="Measuring Ambient" src="illumread_2.jpg">&nbsp; <img
- style="width: 226px; height: 282px;" alt="Measuring Ambient"
- src="illumread_3.jpg"><br>
- </div>
- <br>
- The second measurement <span style="font-weight: bold;">2)</span>,
- is to measure the illuminant after it has reflected from the paper.<br>
- <br>
- <div style="margin-left: 40px;">This is done by placing the paper
- such that it is uniformly illuminated with reasonable brightness,
- and then placing the instrument so that it receives the reflected
- light from the paper. This is typically achieved by placing the
- instrument close to the paper at about 45º, so that it's aperture
- has a clear view of the illuminated paper, but avoiding shadowing
- the region that is in view. <br>
- <br>
- <img style="width: 219px; height: 261px;" alt="Measuring via
- Paper" src="illumread_5.jpg"><img style="width: 252px; height:
- 259px;" alt="Measuring via Paper" src="illumread_4.jpg"><br>
- </div>
- <br>
- The third measurement <span style="font-weight: bold;">3)</span>,
- is to measure the paper directly using the instrument reflective
- mode measurement.<br>
- <div style="margin-left: 40px;"><img style="width: 186px; height:
- 162px;" alt="Measuring Paper" src="illumread_6.jpg"><br>
- </div>
- If a different instrument is needed, use <span style="font-weight:
- bold;">4)</span> to select from the available instruments attached
- to your computer.<br>
- <br>
- Once these three measurements have been made, then the illuminant
- readings spectrum can be computed and save using <span
- style="font-weight: bold;">6)</span>, or a series of readings can
- be made with each reading being averages with the previous readings
- before saving it by using <span style="font-weight: bold;">5)</span>.
- Note that the averaged readings will be weighted by their absolute
- intensities, and that while the direct and indirect illumination
- needs measuring for each reading, the same paper measurement can be
- used each time.<br>
- <br>
- If plotting is enabled, a plot of the measured (black) and with
- estimated UV (red) is plotted. This is followed by a plot showing
- measured paper reflectance (black) and the FWA calculated paper
- reflectance (red).<br>
- <br>
- <br>
- Illumread can then be terminated using <span style="font-weight:
- bold;">7)</span>.<br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ (</i>Computed paper under illuminant spectrum) will be saved.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="file"></a>The <span style="font-weight: bold; font-style:
+ italic;">illuminant.sp</span> is the name of the file to save the
+ resulting illuminant spectrum to. The format used is <a
+ href="File_Formats.html#.sp">.sp</a>.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ Unlike the other measurement utilities, <span style="font-weight:
+ bold;">illumread</span> doesn't connect to the instrument until it
+ is about to make a measurement. This allows for the possibility of
+ using a different instrument for each measurement.<br>
+ <br>
+ It will display a menu:<br>
+ <br>
+ Press 1 .. 6<br>
+ 1) Measure direct illuminant<br>
+ 2) Measure illuminant reflected from paper<br>
+ 3) Measure paper<br>
+ 4) Select another instrument, Currently 1 'usb:/bus4/dev2/
+ (GretagMacbeth i1 Pro)'<br>
+ 5) Compute illuminant spectrum, average result with 0 previous
+ readings &amp; save it<br>
+ 6) Compute illuminant spectrum from this reading &amp; save result<br>
+ 7) Exit<br>
+ <br>
+ There are three measurements to be made, after which the illuminant
+ can be computed and saved. Before each measurement, the instrument
+ may need calibrating.<br>
+ <br>
+ The first measurement needs a spectral instrument capable of reading
+ in an ambient or emissive mode. For instance, a Spectrolino, Eye-One
+ Pro or ColorMunki would be suitable instruments.<br>
+ <br>
+ The second measurement needs a spectral instrument capable of
+ reading in an projector or emissive mode. For instance, a
+ Spectrolino, Eye-One Pro or ColorMunki would be suitable
+ instruments.<br>
+ <br>
+ The third measurement needs a spectral instrument capable of reading
+ in reflective mode with UV included. For instance, a Spectrolino,
+ Eye-One Pro, DTP20, DTP22 or&nbsp; DTP41 would be suitable
+ instruments, as long as they are not fitted with UV filters.<br>
+ <br>
+ To be able to estimate the level of Ultra Violet (UV) light in the
+ illuminant, a reasonable sized piece of white paper needs to be
+ used. The paper should have some noticeable level of FWA
+ (Fluorescent Whitener Additive, or Optical Brightening Agents) in
+ it, so that it responds to UV light. A piece of cheap copier paper
+ is ideal, since cheap paper is typically whitened with large amounts
+ of FWA. If the paper is thin (less than 160 gsm) then two or three
+ sheets should be used to prevent any background showing through. If
+ the intention is to use the illuminant spectrum for proofing to a
+ particular paper, then it's best to use the intended paper for this
+ purpose.<br>
+ <br>
+ The first measurement <span style="font-weight: bold;">1)</span>,
+ is to use either the ambient or emissive measurement mode to measure
+ the illumination directly.<br>
+ <br>
+ <div style="margin-left: 40px;">If the instrument supports an
+ ambient measurement capability, then it will be used. If the
+ insrument does not have an ambient mode, then an emissive
+ measurement mode can be used, although typically many illuminants
+ are too bright to directly point the instrument at. A work-around
+ is to reflect the illuminant from a spectrally flat white surface.
+ A good candidate for this is a piece of white, fine textured
+ polystyrene foam. [The suitability of a reflector can be checked
+ using <span style="font-weight: bold;">spotread -S</span> to
+ check that the reflection characteristic is close to flat.]<br>
+ <br>
+ <img style="width: 228px; height: 300px;" alt="Measuring Ambient"
+ src="illumread_1.jpg"><img style="width: 141px; height: 282px;"
+ alt="Measuring Ambient" src="illumread_2.jpg">&nbsp; <img
+ style="width: 226px; height: 282px;" alt="Measuring Ambient"
+ src="illumread_3.jpg"><br>
+ </div>
+ <br>
+ The second measurement <span style="font-weight: bold;">2)</span>,
+ is to measure the illuminant after it has reflected from the paper.<br>
+ <br>
+ <div style="margin-left: 40px;">This is done by placing the paper
+ such that it is uniformly illuminated with reasonable brightness,
+ and then placing the instrument so that it receives the reflected
+ light from the paper. This is typically achieved by placing the
+ instrument close to the paper at about 45º, so that it's aperture
+ has a clear view of the illuminated paper, but avoiding shadowing
+ the region that is in view. <br>
+ <br>
+ <img style="width: 219px; height: 261px;" alt="Measuring via
+ Paper" src="illumread_5.jpg"><img style="width: 252px; height:
+ 259px;" alt="Measuring via Paper" src="illumread_4.jpg"><br>
+ </div>
+ <br>
+ The third measurement <span style="font-weight: bold;">3)</span>,
+ is to measure the paper directly using the instrument reflective
+ mode measurement.<br>
+ <div style="margin-left: 40px;"><img style="width: 186px; height:
+ 162px;" alt="Measuring Paper" src="illumread_6.jpg"><br>
+ </div>
+ If a different instrument is needed, use <span style="font-weight:
+ bold;">4)</span> to select from the available instruments attached
+ to your computer.<br>
+ <br>
+ Once these three measurements have been made, then the illuminant
+ readings spectrum can be computed and save using <span
+ style="font-weight: bold;">6)</span>, or a series of readings can
+ be made with each reading being averages with the previous readings
+ before saving it by using <span style="font-weight: bold;">5)</span>.
+ Note that the averaged readings will be weighted by their absolute
+ intensities, and that while the direct and indirect illumination
+ needs measuring for each reading, the same paper measurement can be
+ used each time.<br>
+ <br>
+ If plotting is enabled, a plot of the measured (black) and with
+ estimated UV (red) is plotted. This is followed by a plot showing
+ measured paper reflectance (black) and the FWA calculated paper
+ reflectance (red).<br>
+ <br>
+ <br>
+ Illumread can then be terminated using <span style="font-weight:
+ bold;">7)</span>.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/instruments.html b/doc/instruments.html
index 1e287fc..b493b27 100644
--- a/doc/instruments.html
+++ b/doc/instruments.html
@@ -1,28 +1,28 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
- <head>
- <title>Operation of particular instruments</title>
- <meta http-equiv="content-type" content="text/html;
- charset=windows-1252">
- </head>
- <body>
- <h2><u>Operation of particular instruments</u></h2>
- <span style="font-weight: bold;">Please note that instruments are
- being driven by ArgyllCMS drivers, and that any problems or
- queries regarding instrument<br>
- operation </span><span style="font-weight: bold;">should be
- directed to the Argyll's author(s) or the Argyll mailing list, and
- not to any</span> <span style="font-weight: bold;">other party.</span><span
- style="font-weight: bold;"></span><br>
- <br>
- The following instruments are directly supported:<br>
- (Please <span style="font-weight: bold;">note</span> the <a
- href="Installing.html">installation instructions</a> for each
- platform - they contain important information for getting your
- instruments working.)<br>
- <br>
- JETI:<br>
- <br>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Operation of particular instruments</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=windows-1252">
+ </head>
+ <body>
+ <h2><u>Operation of particular instruments</u></h2>
+ <span style="font-weight: bold;">Please note that instruments are
+ being driven by ArgyllCMS drivers, and that any problems or
+ queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should be
+ directed to the Argyll's author(s) or the Argyll mailing list, and
+ not to any</span> <span style="font-weight: bold;">other party.</span><span
+ style="font-weight: bold;"></span><br>
+ <br>
+ The following instruments are directly supported:<br>
+ (Please <span style="font-weight: bold;">note</span> the <a
+ href="Installing.html">installation instructions</a> for each
+ platform - they contain important information for getting your
+ instruments working.)<br>
+ <br>
+ JETI:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="#specbos">specbos 1211 &amp; 1201</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -48,11 +48,11 @@
-
- - Tele-Spectro-Radiometer<br>
- <br>
- Image Engineering:<br>
- <br>
+
+ - Tele-Spectro-Radiometer<br>
+ <br>
+ Image Engineering:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <a href="#ex1">EX1</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -107,20 +107,20 @@
-
- - Tele-Spectro-Radiometer<br>
- <br>
- Klein:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="#k10a">K10-A</a>&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
- the K-1, K-8 and&nbsp; K-10<br>
- <br>
- X-Rite:<br>
- &nbsp;&nbsp;&nbsp; <a href="#DTP20">DTP20 "Pulse"</a>&nbsp;
+
+ - Tele-Spectro-Radiometer<br>
+ <br>
+ Klein:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="#k10a">K10-A</a>&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; - Display Colorimeter. Reported also to work with
+ the K-1, K-8 and&nbsp; K-10<br>
+ <br>
+ X-Rite:<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP20">DTP20 "Pulse"</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -168,8 +168,8 @@
-
- - "swipe" type reflective spectrometer, that can be used untethered.<br>
+
+ - "swipe" type reflective spectrometer, that can be used untethered.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP22">DTP22 Digital Swatchbook</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -217,8 +217,8 @@
-
- - spot type reflective spectrometer.<br>
+
+ - spot type reflective spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -266,10 +266,10 @@
-
- - spot and strip reading reflective spectrometer.<br>
- &nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41T</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+
+ - spot and strip reading reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41T</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -317,8 +317,8 @@
-
- - spot and strip reading reflective/transmissive spectrometer.<br>
+
+ - spot and strip reading reflective/transmissive spectrometer.<br>
&nbsp;&nbsp;&nbsp; <a href="#dtp51">DTP51</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -366,8 +366,8 @@
-
- - strip reading reflective colorimeter.<br>
+
+ - strip reading reflective colorimeter.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP92">DTP92</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -415,8 +415,8 @@
-
- - CRT display colorimeter.<br>
+
+ - CRT display colorimeter.<br>
&nbsp;&nbsp;&nbsp; <a href="#DTP94">DTP94</a> <font size="-1">"Optix
@@ -464,8 +464,8 @@
-
- XR"</font> or "Optix XR2" or "Optix Pro"- display colorimeter.<br>
+
+ XR"</font> or "Optix XR2" or "Optix Pro"- display colorimeter.<br>
<a href="#ColorMunki"><span style="text-decoration: underline;"></span></a>&nbsp;&nbsp;&nbsp;
@@ -513,62 +513,62 @@
-
- <a href="#ColorMunki"><span style="text-decoration: underline;">ColorMunki</span></a>
- Design or Photo&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - spot and "swipe"
- reflective/emissive spectrometer (UV cut only).<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d"><span style="text-decoration:
- underline;">ColorMunki</span></a> Create or Smile&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter. (Similar to an Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="#Huey">Lenovo W</a> &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - built in laptop
- Huey display colorimeter.<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d3">Eye-One Display 3</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; - i1 DisplayPro and ColorMunki Display<br>
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
- i1Display Pro, NEC SpectraSensor Pro,<br>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
- DreamColor&nbsp; i1d3 are also reported to work.]<br>
- &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
- "swipe" reflective/emissive spectrometer.<br>
- <br>
- Gretag-Macbeth (now X-Rite):<br>
- &nbsp; &nbsp; <a href="#sl">Spectrolino</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive
- spectrometer<br>
- &nbsp; &nbsp; <a href="#ss">SpectroScan</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive, XY table
- reflective spectrometer&nbsp; <br>
- &nbsp; &nbsp; <a href="#ss">SpectroScanT</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; - spot reflective/emissive/transmissive, XY
- table reflective spectrometer<br>
- &nbsp; &nbsp; <a href="#i1p">Eye-One Pro</a> "EFI ES-1000" &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" reflective/emissive
- spectrometer<br>
- &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive spectrometer<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d">Eye-One Display 1 or 2&nbsp; or
- LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
- colorimeter<br>
- &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
- APS</a>&nbsp;
+
+ <a href="#ColorMunki"><span style="text-decoration: underline;">ColorMunki</span></a>
+ Design or Photo&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - spot and "swipe"
+ reflective/emissive spectrometer (UV cut only).<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d"><span style="text-decoration:
+ underline;">ColorMunki</span></a> Create or Smile&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter. (Similar to an Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#Huey">Lenovo W</a> &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - built in laptop
+ Huey display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d3">Eye-One Display 3</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; - i1 DisplayPro and ColorMunki Display<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
+ i1Display Pro, NEC SpectraSensor Pro,<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM and HP
+ DreamColor&nbsp; i1d3 are also reported to work.]<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
+ "swipe" reflective/emissive spectrometer.<br>
+ <br>
+ Gretag-Macbeth (now X-Rite):<br>
+ &nbsp; &nbsp; <a href="#sl">Spectrolino</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive
+ spectrometer<br>
+ &nbsp; &nbsp; <a href="#ss">SpectroScan</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive, XY table
+ reflective spectrometer&nbsp; <br>
+ &nbsp; &nbsp; <a href="#ss">SpectroScanT</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; - spot reflective/emissive/transmissive, XY
+ table reflective spectrometer<br>
+ &nbsp; &nbsp; <a href="#i1p">Eye-One Pro</a> "EFI ES-1000" &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" reflective/emissive
+ spectrometer<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive spectrometer<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d">Eye-One Display 1 or 2&nbsp; or
+ LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
+ APS</a>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -616,9 +616,9 @@
-
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="#i1d">CalMAN X2</a>
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d">CalMAN X2</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -666,18 +666,18 @@
-
- - display colorimeter. (Treated as a Eye-One Display 2)<br>
- &nbsp;&nbsp;&nbsp; <a href="#Huey">Huey</a> &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter<br>
- <br>
- Sequel imaging (Now X-Rite):<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#mox">MonacoOPTIX</a> &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Treated
- as an Eye-One Display 1)<br>
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#Huey">Huey</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter<br>
+ <br>
+ Sequel imaging (Now X-Rite):<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#mox">MonacoOPTIX</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Treated
+ as an Eye-One Display 1)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -725,10 +725,10 @@
-
- [The Sequel Chroma 4 may also work.]<br>
- <br>
- Lacie Blue
+
+ [The Sequel Chroma 4 may also work.]<br>
+ <br>
+ Lacie Blue
Eye:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -776,15 +776,15 @@
-
- - see <a href="#i1d">Eye-One Display</a><br>
- <br>
- DataColor ColorVision:<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd2">Spyder 2</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> firmware)<br>
+
+ - see <a href="#i1d">Eye-One Display</a><br>
+ <br>
+ DataColor ColorVision:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd2">Spyder 2</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> firmware)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -832,27 +832,27 @@
-
- [The Spyder 1 also seems to work.]<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd3">Spyder 3</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd4">Spyder 4</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd5">Spyder 5</a> &nbsp;
- &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
- that the user must <a href="oeminst.html">supply</a> calibration
- data)<br>
- <br>
- Other:<br>
- &nbsp;&nbsp;&nbsp; <span class="titre"><a href="#HCFR">Colorimètre
+
+ [The Spyder 1 also seems to work.]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd3">Spyder 3</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd4">Spyder 4</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd5">Spyder 5</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ <br>
+ Other:<br>
+ &nbsp;&nbsp;&nbsp; <span class="titre"><a href="#HCFR">Colorimètre
HCFR</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -900,8 +900,8 @@
-
- - display colorimeter<br>
+
+ - display colorimeter<br>
</span>&nbsp;&nbsp;&nbsp; <a href="#ColorHug">ColorHug</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -940,288 +940,288 @@
-
- - display colorimeter<span class="titre"></span><br>
+
+ - display colorimeter<span class="titre"></span><br>
&nbsp;&nbsp;&nbsp; <a href="#SMCube">Palette/SwatchMate Cube</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- - reflective colorimeter<br>
- <br>
- Other instruments can be supported indirectly, since patch result
- files created by other packages can be imported into Argyll.<br>
- <span class="titre"><br>
- General information about:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <a href="#strip">Strip reading instruments</a><br>
- </span>&nbsp;&nbsp;&nbsp; <a href="#xy">X-Y Table instruments</a><br>
- &nbsp;&nbsp;&nbsp; <a href="#spot">Spot reading instruments</a><br>
- <span style="font-weight: bold;"></span><br>
- <br>
- There is a <a href="ccmxs.html">list of contributed</a> <span
- style="font-weight: bold;">ccmx</span> (Colorimeter Correction
- Matrix) files.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="strip"></a>Strip reading instruments</h3>
- When used with a <span style="font-weight: bold;">DT20</span>, <span
- style="font-weight: bold;">DTP41</span>, <span
- style="font-weight: bold;">DTP51</span>, <span
- style="font-weight: bold;">Eye-One Pro<span style="font-weight:
- bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
- strip reading instrument, chartread will first establish
- communications with the instrument, and then set it up ready to read
- the strips. The strips are labeled A to ZZ, and for each strip it
- will prompt:<br>
- <br>
- &nbsp;&nbsp;&nbsp; About to read strip XX&nbsp; :<br>
- <br>
- where XX is the strip label, and this is followed by the available
- options to navigate, read the strip, or finish. Note that the normal
- (forward) direction of strip reading is one that starts at the strip
- label.<br>
- <br>
- For the <span style="font-weight: bold;">DTP51</span> you should
- feed the strip into the instrument, and the microswitch will trigger
- the read.<br>
- <br>
- For the <span style="font-weight: bold;">DTP41</span> you should
- line the appropriate strip up in the machine, and press its button.<br>
- <br>
- For the <span style="font-weight: bold;">Eye-One Pro</span> you
- should set the guide to the appropriate strip, place the instrument
- <span style="text-decoration: underline;">ahead</span> of the first
- patch on blank paper, and then press and hold the instruments
- button. When you hear a beep from the computer, you can then move
- the instrument steadily over the patches, releasing the button after
- the instrument is past the last patch. Moving the instrument too
- fast or changing speeds may cause a mis-read, or a scan with few
- samples read per patch.<br>
- <br>
- For the <span style="font-weight: bold;">ColorMunki</span> with the
- default chart, the patches are the same width as the silver portion
- of body (white version), or the textured portion of the body (black
- version). Place aperture of the the instrument (located at its
- center) in the white space ahead of the first patch, and then press
- and hold the instruments button. When you hear a beep from the
- computer, you can then move the instrument steadily over the
- patches, releasing the button after the instrument is past the last
- patch. Moving the instrument too fast or changing speeds may cause a
- mis-read, or a scan with few samples read per patch. For the <span
- style="font-weight: bold;">high density</span> ColorMunki chart (<a
- href="printtarg.html#h">printtarg -h</a>), the patches are
- arranged so that three rows are exactly the width of the&nbsp; body
- of the instrument. If you are careful you can use this to guide the
- center of the instrument over each row, or you may prefer to use
- something like a plastic ruler to help guide the instrument.<br>
- <br>
- Using the <span style="font-weight: bold;">DTP20</span> or the <span
- style="font-weight: bold;">Eye-One Pro</span> or <span
- style="font-weight: bold;">ColorMunki</span> with a randomized
- chart layout, the strip may be scanned from either direction. If a
- randomized chart layout has not been used for the <span
- style="font-weight: bold;">Eye-One Pro</span> or <span
- style="font-weight: bold;">ColorMunki</span>, then the chart
- should only be read in the one direction (use <a
- href="chartread.html#B">chartread -B</a>).<br>
- <br>
- Note that you may have to check that system alert sounds are enabled
- and at a suitable volume to in order to hear the beep prompt. For
- the Eye-One Pro and ColorMunki, a second beep will sound after a
- successfully read strip, or a double beep will sound,&nbsp;
- indicating a failure or warning that needs attention. See also the
- note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
- <br>
- If the strip is read successfully there will be a single "success"
- beep, and the line will be followed with:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; : <br>
- &nbsp;&nbsp;&nbsp; Strip read OK<br>
- <br>
- If there is an error of some sort there will be a double "fail"
- beep, and a message will be issued, and you will be asked whether to
- abort the chart reading, or retry the<br>
- failed strip:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip XX&nbsp; : <br>
- &nbsp;&nbsp;&nbsp; Strip read failed due to misread (Not enough
- patches)<br>
- <br>
- &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
- <br>
- If you are unable to successfully read a strip after several
- retries, you can skip that strip using the <span
- style="font-weight: bold;">'n'</span> key, and save<br>
- the chart readings without that strip.<br>
- <br>
- If the strip is read successfully, but the patches values don't seem
- to be what is expected, you will get a double "fail" beep&nbsp; and
- the following type of warning:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
- &nbsp;&nbsp;&nbsp; (Warning) Seem to have read strip&nbsp; YY&nbsp;
- rather than&nbsp; XX !<br>
- &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
- retry, Esc, ^C or Q to give up:<br>
- <br>
- This could be because you have accidentally read the wrong strip (a
- common mistake), or it could be that the device response is so
- different from what is expected that warning is erroneous, or you
- may get a lot of these sorts of warnings if you are accidentally
- reading the wrong chart. You may also get this sort of warning if
- you are not using bi-direction reading (chartread -B), and read the
- strip from the wrong end.<br>
- If you are absolutely sure you lined up the correct strip, then hit
- return, otherwise line the appropriate strip up again, and hit some
- other key (ie. space).<br>
- Erroneous warnings are less likely if a previous profile for a
- device was given to <span style="font-weight: bold;">targen</span>
- to set more accurate expectations.<br>
- <br>
- You may also see the following type of warning:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
- &nbsp;&nbsp;&nbsp; (Warning) Patch error YY.YYY (&gt;35 not good,
- &gt;95 bad)<br>
- &nbsp;&nbsp; There is at least one patch with an very unexpected
- response!<br>
- &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
- retry, Esc, ^C or Q to give up:<br>
- <br>
- Similar to the previous warning, this indicates that while the right
- strip appears to have been read, one of the patch readings is quite
- different to what is expected. This may indicate an error of some
- sort (ie. damaged test chart, or bad instrument positioning), or may
- be erroneous if the actual device response is quite different to the
- expectation. Erroneous warnings are less likely if a previous
- profile for a device was given to <span style="font-weight: bold;">targen</span>
- to set more accurate expectations.<br>
- <br>
- You can also navigate the next strip to be read using the <span
- style="font-weight: bold;">'f'</span> key to move forward and the
- <span style="font-weight: bold;">'b'</span> keys<span
- style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
- to move backwards. The prompt will indicate whether this strip has
- already been read or not, or whether all strips have been read. You
- can also use <span style="font-weight: bold;">'n'</span> to move
- forward to the next unread strip. After each successful reading it
- will move forward to the next unread strip. When you are finished,
- use the <span style="font-weight: bold;">'d'</span> to indicate
- that you are done. You can choose to finish before all the strips
- are read, and the patches that have been read will be saved to the
- .ti3 file. This is useful if you are unable to read a particular
- strip successfully, or if you are unable to finish the chart in one
- session, and you can later <span style="text-decoration:
- underline;">resume</span> reading the chart by using the <span
- style="font-weight: bold;">chartread -r</span> flag. [You could
- resume reading the chart patch by patch using the <span
- style="font-weight: bold;">chartread -r -p</span> if you are
- unable to read a strip successfully.]<br>
- <br>
- When reading in patch by patch mode, there are a few additional
- navigation options, such as <span style="font-weight: bold;"><span
- style="font-weight: bold;">F</span></span> to move forward 10
- patches, <span style="font-weight: bold;">B</span> to move
- backwards 10 patches, and <span style="font-weight: bold;">g</span>
- to go to a specific patch.<br>
- <br>
- You can abort the whole process at any time by hitting Escape, and
- the readings will not be saved.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="xy"></a>X-Y Table instruments</h3>
- When you are using an XY table type instrument, such as a Gretag <span
- style="font-weight: bold;">SpectroScan</span>, &nbsp;chartread
- will first establish communications with the instrument, and then
- set it up ready to read the chart. You will be prompted for each
- sheet with a message such as:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Please make sure that the white reference is in
- slot 1, then<br>
- &nbsp;&nbsp;&nbsp; place sheet 1 of 4 on table, then<br>
- &nbsp;&nbsp;&nbsp; hit return to continue, Esc to give up<br>
- <br>
- After hitting return you will be prompted to line up three squares
- on the sheet, one at a time:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Using the XY table controls, locate patch A1 with
- the sight,<br>
- &nbsp;&nbsp;&nbsp; then hit return to continue, Esc to give up<br>
- <br>
- On completing this, the instrument will commence reading each sheet.<br>
- <br>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="spot"></a>Spot reading instruments</h3>
- When used with a <span style="font-weight: bold;">DT22</span> or <span
- style="font-weight: bold;">SpectroLino</span> or use the patch by
- patch reading mode (<span style="font-weight: bold;">chartread -p</span>)
- with the <span style="font-weight: bold;"></span> <span
- style="font-weight: bold;">Eye-One Pro<span style="font-weight:
- bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
- instrument, or use the external values mode (<span
- style="font-weight: bold;">chartread -x</span>), chartread will
- first establish communications with the instrument, and then set it
- up ready to read the patches. The patches are typically labeled by
- column A to ZZ, and row 1-999. Each patch will prompt:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read patch 'XX'&nbsp; :<br>
- <br>
- where XX is the patch label, and this is followed by the available
- options to navigate, read the strip, or finish.<br>
- <br>
- Place the instrument on the indicated patch, and trigger a reading
- using one of the available methods (typically using the instrument
- switch of pressing a key).<br>
- <br>
- There should be an audible prompt on a successful or failed reading.
- <br>
- <br>
- Note that you may have to check that system alert sounds are enabled
- and at a suitable volume to in order to hear the beep prompt. For
- the Eye-One Pro and ColorMunki, a second beep will sound after a
- successfully read strip, or a double beep will sound,&nbsp;
- indicating a failure or warning that needs attention. See also the
- note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
- <br>
- If the patch is read successfully, the line will be completed with:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read patch&nbsp; XX&nbsp; :<br>
- &nbsp;&nbsp;&nbsp; Patch read OK<br>
- <br>
- If there is an error of some sort, a message will be issued, and you
- will be asked whether to abort the chart reading, or retry the<br>
- failed patch:<br>
- <br>
- &nbsp;&nbsp;&nbsp; Ready to read patch XX&nbsp; : read_strip
- returned 'Strip misread' (Bad reading)<br>
- <br>
- &nbsp;&nbsp;&nbsp; Strip read failed due to misread<br>
- &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
- <br>
- You can navigate the next patch to be read using the <span
- style="font-weight: bold;">'f'</span> key to move forward and the
- <span style="font-weight: bold;">'b'</span> keys<span
- style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
- to move backwards, while <span style="font-weight: bold;">'F'</span>
- and <span style="font-weight: bold;">'B'</span> will move forward
- and backwards by 10 patches. The prompt will indicate whether this
- patch has already been read or not, or whether all patches have been
- read. You can also use <span style="font-weight: bold;">'n'</span>
- to move forward to the next unread patch. When you are finished, use
- the <span style="font-weight: bold;">'d'</span> to indicate that
- you are done. You can choose to finish before all the patches are
- read, and they will be saved to the .ti3 file. This is useful if you
- are unable to finish the chart in one session, and you can later <span
- style="text-decoration: underline;">resume</span> reading the
- chart by using the <span style="font-weight: bold;">chartread -r</span>
- flag.<br>
- <br>
- You can abort the whole process at any time by hitting Escape, and
- the readings will not be saved.<br>
- <br>
- <span style="font-weight: bold;"></span>
- <hr style="width: 100%; height: 2px;">
- <h3><a name="displaytype"></a>Display Type<br>
- </h3>
+
+ - reflective colorimeter<br>
+ <br>
+ Other instruments can be supported indirectly, since patch result
+ files created by other packages can be imported into Argyll.<br>
+ <span class="titre"><br>
+ General information about:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="#strip">Strip reading instruments</a><br>
+ </span>&nbsp;&nbsp;&nbsp; <a href="#xy">X-Y Table instruments</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#spot">Spot reading instruments</a><br>
+ <span style="font-weight: bold;"></span><br>
+ <br>
+ There is a <a href="ccmxs.html">list of contributed</a> <span
+ style="font-weight: bold;">ccmx</span> (Colorimeter Correction
+ Matrix) files.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="strip"></a>Strip reading instruments</h3>
+ When used with a <span style="font-weight: bold;">DT20</span>, <span
+ style="font-weight: bold;">DTP41</span>, <span
+ style="font-weight: bold;">DTP51</span>, <span
+ style="font-weight: bold;">Eye-One Pro<span style="font-weight:
+ bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
+ strip reading instrument, chartread will first establish
+ communications with the instrument, and then set it up ready to read
+ the strips. The strips are labeled A to ZZ, and for each strip it
+ will prompt:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; About to read strip XX&nbsp; :<br>
+ <br>
+ where XX is the strip label, and this is followed by the available
+ options to navigate, read the strip, or finish. Note that the normal
+ (forward) direction of strip reading is one that starts at the strip
+ label.<br>
+ <br>
+ For the <span style="font-weight: bold;">DTP51</span> you should
+ feed the strip into the instrument, and the microswitch will trigger
+ the read.<br>
+ <br>
+ For the <span style="font-weight: bold;">DTP41</span> you should
+ line the appropriate strip up in the machine, and press its button.<br>
+ <br>
+ For the <span style="font-weight: bold;">Eye-One Pro</span> you
+ should set the guide to the appropriate strip, place the instrument
+ <span style="text-decoration: underline;">ahead</span> of the first
+ patch on blank paper, and then press and hold the instruments
+ button. When you hear a beep from the computer, you can then move
+ the instrument steadily over the patches, releasing the button after
+ the instrument is past the last patch. Moving the instrument too
+ fast or changing speeds may cause a mis-read, or a scan with few
+ samples read per patch.<br>
+ <br>
+ For the <span style="font-weight: bold;">ColorMunki</span> with the
+ default chart, the patches are the same width as the silver portion
+ of body (white version), or the textured portion of the body (black
+ version). Place aperture of the the instrument (located at its
+ center) in the white space ahead of the first patch, and then press
+ and hold the instruments button. When you hear a beep from the
+ computer, you can then move the instrument steadily over the
+ patches, releasing the button after the instrument is past the last
+ patch. Moving the instrument too fast or changing speeds may cause a
+ mis-read, or a scan with few samples read per patch. For the <span
+ style="font-weight: bold;">high density</span> ColorMunki chart (<a
+ href="printtarg.html#h">printtarg -h</a>), the patches are
+ arranged so that three rows are exactly the width of the&nbsp; body
+ of the instrument. If you are careful you can use this to guide the
+ center of the instrument over each row, or you may prefer to use
+ something like a plastic ruler to help guide the instrument.<br>
+ <br>
+ Using the <span style="font-weight: bold;">DTP20</span> or the <span
+ style="font-weight: bold;">Eye-One Pro</span> or <span
+ style="font-weight: bold;">ColorMunki</span> with a randomized
+ chart layout, the strip may be scanned from either direction. If a
+ randomized chart layout has not been used for the <span
+ style="font-weight: bold;">Eye-One Pro</span> or <span
+ style="font-weight: bold;">ColorMunki</span>, then the chart
+ should only be read in the one direction (use <a
+ href="chartread.html#B">chartread -B</a>).<br>
+ <br>
+ Note that you may have to check that system alert sounds are enabled
+ and at a suitable volume to in order to hear the beep prompt. For
+ the Eye-One Pro and ColorMunki, a second beep will sound after a
+ successfully read strip, or a double beep will sound,&nbsp;
+ indicating a failure or warning that needs attention. See also the
+ note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
+ <br>
+ If the strip is read successfully there will be a single "success"
+ beep, and the line will be followed with:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; : <br>
+ &nbsp;&nbsp;&nbsp; Strip read OK<br>
+ <br>
+ If there is an error of some sort there will be a double "fail"
+ beep, and a message will be issued, and you will be asked whether to
+ abort the chart reading, or retry the<br>
+ failed strip:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip XX&nbsp; : <br>
+ &nbsp;&nbsp;&nbsp; Strip read failed due to misread (Not enough
+ patches)<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
+ <br>
+ If you are unable to successfully read a strip after several
+ retries, you can skip that strip using the <span
+ style="font-weight: bold;">'n'</span> key, and save<br>
+ the chart readings without that strip.<br>
+ <br>
+ If the strip is read successfully, but the patches values don't seem
+ to be what is expected, you will get a double "fail" beep&nbsp; and
+ the following type of warning:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; (Warning) Seem to have read strip&nbsp; YY&nbsp;
+ rather than&nbsp; XX !<br>
+ &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
+ retry, Esc, ^C or Q to give up:<br>
+ <br>
+ This could be because you have accidentally read the wrong strip (a
+ common mistake), or it could be that the device response is so
+ different from what is expected that warning is erroneous, or you
+ may get a lot of these sorts of warnings if you are accidentally
+ reading the wrong chart. You may also get this sort of warning if
+ you are not using bi-direction reading (chartread -B), and read the
+ strip from the wrong end.<br>
+ If you are absolutely sure you lined up the correct strip, then hit
+ return, otherwise line the appropriate strip up again, and hit some
+ other key (ie. space).<br>
+ Erroneous warnings are less likely if a previous profile for a
+ device was given to <span style="font-weight: bold;">targen</span>
+ to set more accurate expectations.<br>
+ <br>
+ You may also see the following type of warning:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; (Warning) Patch error YY.YYY (&gt;35 not good,
+ &gt;95 bad)<br>
+ &nbsp;&nbsp; There is at least one patch with an very unexpected
+ response!<br>
+ &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
+ retry, Esc, ^C or Q to give up:<br>
+ <br>
+ Similar to the previous warning, this indicates that while the right
+ strip appears to have been read, one of the patch readings is quite
+ different to what is expected. This may indicate an error of some
+ sort (ie. damaged test chart, or bad instrument positioning), or may
+ be erroneous if the actual device response is quite different to the
+ expectation. Erroneous warnings are less likely if a previous
+ profile for a device was given to <span style="font-weight: bold;">targen</span>
+ to set more accurate expectations.<br>
+ <br>
+ You can also navigate the next strip to be read using the <span
+ style="font-weight: bold;">'f'</span> key to move forward and the
+ <span style="font-weight: bold;">'b'</span> keys<span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
+ to move backwards. The prompt will indicate whether this strip has
+ already been read or not, or whether all strips have been read. You
+ can also use <span style="font-weight: bold;">'n'</span> to move
+ forward to the next unread strip. After each successful reading it
+ will move forward to the next unread strip. When you are finished,
+ use the <span style="font-weight: bold;">'d'</span> to indicate
+ that you are done. You can choose to finish before all the strips
+ are read, and the patches that have been read will be saved to the
+ .ti3 file. This is useful if you are unable to read a particular
+ strip successfully, or if you are unable to finish the chart in one
+ session, and you can later <span style="text-decoration:
+ underline;">resume</span> reading the chart by using the <span
+ style="font-weight: bold;">chartread -r</span> flag. [You could
+ resume reading the chart patch by patch using the <span
+ style="font-weight: bold;">chartread -r -p</span> if you are
+ unable to read a strip successfully.]<br>
+ <br>
+ When reading in patch by patch mode, there are a few additional
+ navigation options, such as <span style="font-weight: bold;"><span
+ style="font-weight: bold;">F</span></span> to move forward 10
+ patches, <span style="font-weight: bold;">B</span> to move
+ backwards 10 patches, and <span style="font-weight: bold;">g</span>
+ to go to a specific patch.<br>
+ <br>
+ You can abort the whole process at any time by hitting Escape, and
+ the readings will not be saved.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="xy"></a>X-Y Table instruments</h3>
+ When you are using an XY table type instrument, such as a Gretag <span
+ style="font-weight: bold;">SpectroScan</span>, &nbsp;chartread
+ will first establish communications with the instrument, and then
+ set it up ready to read the chart. You will be prompted for each
+ sheet with a message such as:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Please make sure that the white reference is in
+ slot 1, then<br>
+ &nbsp;&nbsp;&nbsp; place sheet 1 of 4 on table, then<br>
+ &nbsp;&nbsp;&nbsp; hit return to continue, Esc to give up<br>
+ <br>
+ After hitting return you will be prompted to line up three squares
+ on the sheet, one at a time:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Using the XY table controls, locate patch A1 with
+ the sight,<br>
+ &nbsp;&nbsp;&nbsp; then hit return to continue, Esc to give up<br>
+ <br>
+ On completing this, the instrument will commence reading each sheet.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="spot"></a>Spot reading instruments</h3>
+ When used with a <span style="font-weight: bold;">DT22</span> or <span
+ style="font-weight: bold;">SpectroLino</span> or use the patch by
+ patch reading mode (<span style="font-weight: bold;">chartread -p</span>)
+ with the <span style="font-weight: bold;"></span> <span
+ style="font-weight: bold;">Eye-One Pro<span style="font-weight:
+ bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
+ instrument, or use the external values mode (<span
+ style="font-weight: bold;">chartread -x</span>), chartread will
+ first establish communications with the instrument, and then set it
+ up ready to read the patches. The patches are typically labeled by
+ column A to ZZ, and row 1-999. Each patch will prompt:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch 'XX'&nbsp; :<br>
+ <br>
+ where XX is the patch label, and this is followed by the available
+ options to navigate, read the strip, or finish.<br>
+ <br>
+ Place the instrument on the indicated patch, and trigger a reading
+ using one of the available methods (typically using the instrument
+ switch of pressing a key).<br>
+ <br>
+ There should be an audible prompt on a successful or failed reading.
+ <br>
+ <br>
+ Note that you may have to check that system alert sounds are enabled
+ and at a suitable volume to in order to hear the beep prompt. For
+ the Eye-One Pro and ColorMunki, a second beep will sound after a
+ successfully read strip, or a double beep will sound,&nbsp;
+ indicating a failure or warning that needs attention. See also the
+ note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
+ <br>
+ If the patch is read successfully, the line will be completed with:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; Patch read OK<br>
+ <br>
+ If there is an error of some sort, a message will be issued, and you
+ will be asked whether to abort the chart reading, or retry the<br>
+ failed patch:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch XX&nbsp; : read_strip
+ returned 'Strip misread' (Bad reading)<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Strip read failed due to misread<br>
+ &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
+ <br>
+ You can navigate the next patch to be read using the <span
+ style="font-weight: bold;">'f'</span> key to move forward and the
+ <span style="font-weight: bold;">'b'</span> keys<span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
+ to move backwards, while <span style="font-weight: bold;">'F'</span>
+ and <span style="font-weight: bold;">'B'</span> will move forward
+ and backwards by 10 patches. The prompt will indicate whether this
+ patch has already been read or not, or whether all patches have been
+ read. You can also use <span style="font-weight: bold;">'n'</span>
+ to move forward to the next unread patch. When you are finished, use
+ the <span style="font-weight: bold;">'d'</span> to indicate that
+ you are done. You can choose to finish before all the patches are
+ read, and they will be saved to the .ti3 file. This is useful if you
+ are unable to finish the chart in one session, and you can later <span
+ style="text-decoration: underline;">resume</span> reading the
+ chart by using the <span style="font-weight: bold;">chartread -r</span>
+ flag.<br>
+ <br>
+ You can abort the whole process at any time by hitting Escape, and
+ the readings will not be saved.<br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="displaytype"></a>Display Type<br>
+ </h3>
Many of the colorimeters have a <span style="font-weight: bold;">display
@@ -1264,174 +1264,174 @@
-
- type</span> selection parameter. Depending on the instrument, this
- may combine two related functions: 1) Changing the measurement mode
- to suite either refresh-type, or non-refresh displays, and 2)
- Changing the calibration to suite a particular displays spectral
- characteristics.<br>
- <br>
- A refresh type display uses a technology that presents different
- portions of the image at different times, doing so at a high enough
- rate that this is normally imperceptible. This time varying
- characteristic can interfere with measuring a display color unless
- the instrument makes allowances for it, typically by making its
- measurement period a multiple of the display refresh period. Display
- types that <span style="font-weight: bold;">refresh</span> are CRT
- (Cathode Ray Tube), Single chip DLP (Digital Light Processing) and
- Plasma displays. An example of a <span style="font-weight: bold;">non-refresh</span>
- display technology is LCD (Liquid Crystal Display), although is a
- few cases the back-light illumination may have a low enough
- frequency flicker to benefit from the refresh mode.<br>
- <br>
- Instruments in which the display type selection only changes the
- measurement mode (i.e. i1d3), will typically have some other
- independent option to set the calibration type. Simpler instruments
- combine the measurement mode with a calibration selections,
- typically refresh+CRT and non-refresh+LCD. Some instruments are a
- hybrid of both (Spyder4), where the display type can select between
- generic refresh/non-refresh that can then use a .CCSS to set the
- calibration type, or a combined selection of non-refresh and a
- particular display type.<br>
- <br>
- See <a
- href="http://en.wikipedia.org/wiki/Comparison_of_display_technology">Comparison_of_display_technology</a>
- for some background on different display technologies.<br>
- <br>
- <hr size="2" width="100%"><br>
- <h3><a name="refreshmeasurement"></a>Refresh Rate Measurement</h3>
- <p>Most of the colorimeters that have a refresh display type
- selection, also have an ability to measure the refresh rate of a
- display. Some of the spectrometers also have a display refresh
- rate measurement capability when in an emissive measurement mode,
- even though they don't use this to support a refresh display mode.
- You can do a display refresh rate measurement in <a
- href="spotread.html">spotread</a> using the <b>'F' </b>key.
- The particular instruments have a range of accuracy when making
- this measurement. A rough guide is as follows:<br>
- <br>
- </p>
- <table border="1" cellpadding="2" cellspacing="2" width="372"
- height="230">
- <tbody>
- <tr>
- <td valign="top"><b>Instrument</b></td>
- <td valign="top"><b>Typical error in Hz.</b></td>
- </tr>
- <tr>
- <td valign="top">spectrobos 1211/1201<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Klein K10-A<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">DTP92<br>
- </td>
- <td valign="top">0.1<br>
- </td>
- </tr>
- <tr>
- <td valign="top">i1 Display 2<br>
- </td>
- <td valign="top">0.5<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Spyder 2<br>
- </td>
- <td valign="top">0.7<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Spyder 3<br>
- </td>
- <td valign="top">3<br>
- </td>
- </tr>
- <tr>
- <td valign="top">Spyder 4<br>
- </td>
- <td valign="top">3<br>
- </td>
- </tr>
- <tr>
- <td valign="top">i1 Display Pro<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">i1 Pro Spectro.<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- <tr>
- <td valign="top">ColorMunki Spectro.<br>
- </td>
- <td valign="top">0.05<br>
- </td>
- </tr>
- </tbody>
- </table>
- <p><br>
- </p>
- <hr size="2" width="100%">
- <p><span style="font-weight: bold;"><a name="specbos"></a><span
- style="font-weight: bold;">specbos 1211 and 1201
- Tele-Spectro-Radiometer<br>
- </span></span></p>
- <img alt="JETI specbos 1211" src="JETI_1211.jpg" width="257"
- height="254">
- <p><span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">specbos 1211</span><span
- style="font-weight: bold;"> </span>and <b>1201</b> from <a
- href="http://www.jeti.com/">JETI</a>&nbsp; are currently
- available instruments. These are reference grade instruments
- capable of emissive and ambient measurements, and are often used
- for monitor, projector and cinema calibration &amp;
- characterization, lighting measurement and colorimeter
- calibration, amongst many other uses.<br>
- </p>
- <hr size="2" width="100%">
- <p><span style="font-weight: bold;"><a name="ex1"></a><span
- style="font-weight: bold;">Image Engineering EX1<br>
- </span></span></p>
- <img alt="Image Engineering EX1" src="EX1.jpg" width="253"
- height="158"> <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;"><br>
- Availability:<br>
- <br>
- </span>The <a
+
+ type</span> selection parameter. Depending on the instrument, this
+ may combine two related functions: 1) Changing the measurement mode
+ to suite either refresh-type, or non-refresh displays, and 2)
+ Changing the calibration to suite a particular displays spectral
+ characteristics.<br>
+ <br>
+ A refresh type display uses a technology that presents different
+ portions of the image at different times, doing so at a high enough
+ rate that this is normally imperceptible. This time varying
+ characteristic can interfere with measuring a display color unless
+ the instrument makes allowances for it, typically by making its
+ measurement period a multiple of the display refresh period. Display
+ types that <span style="font-weight: bold;">refresh</span> are CRT
+ (Cathode Ray Tube), Single chip DLP (Digital Light Processing) and
+ Plasma displays. An example of a <span style="font-weight: bold;">non-refresh</span>
+ display technology is LCD (Liquid Crystal Display), although is a
+ few cases the back-light illumination may have a low enough
+ frequency flicker to benefit from the refresh mode.<br>
+ <br>
+ Instruments in which the display type selection only changes the
+ measurement mode (i.e. i1d3), will typically have some other
+ independent option to set the calibration type. Simpler instruments
+ combine the measurement mode with a calibration selections,
+ typically refresh+CRT and non-refresh+LCD. Some instruments are a
+ hybrid of both (Spyder4), where the display type can select between
+ generic refresh/non-refresh that can then use a .CCSS to set the
+ calibration type, or a combined selection of non-refresh and a
+ particular display type.<br>
+ <br>
+ See <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology">Comparison_of_display_technology</a>
+ for some background on different display technologies.<br>
+ <br>
+ <hr size="2" width="100%"><br>
+ <h3><a name="refreshmeasurement"></a>Refresh Rate Measurement</h3>
+ <p>Most of the colorimeters that have a refresh display type
+ selection, also have an ability to measure the refresh rate of a
+ display. Some of the spectrometers also have a display refresh
+ rate measurement capability when in an emissive measurement mode,
+ even though they don't use this to support a refresh display mode.
+ You can do a display refresh rate measurement in <a
+ href="spotread.html">spotread</a> using the <b>'F' </b>key.
+ The particular instruments have a range of accuracy when making
+ this measurement. A rough guide is as follows:<br>
+ <br>
+ </p>
+ <table border="1" cellpadding="2" cellspacing="2" width="372"
+ height="230">
+ <tbody>
+ <tr>
+ <td valign="top"><b>Instrument</b></td>
+ <td valign="top"><b>Typical error in Hz.</b></td>
+ </tr>
+ <tr>
+ <td valign="top">spectrobos 1211/1201<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Klein K10-A<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">DTP92<br>
+ </td>
+ <td valign="top">0.1<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Display 2<br>
+ </td>
+ <td valign="top">0.5<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 2<br>
+ </td>
+ <td valign="top">0.7<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 3<br>
+ </td>
+ <td valign="top">3<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 4<br>
+ </td>
+ <td valign="top">3<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Display Pro<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Pro Spectro.<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">ColorMunki Spectro.<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <p><br>
+ </p>
+ <hr size="2" width="100%">
+ <p><span style="font-weight: bold;"><a name="specbos"></a><span
+ style="font-weight: bold;">specbos 1211 and 1201
+ Tele-Spectro-Radiometer<br>
+ </span></span></p>
+ <img alt="JETI specbos 1211" src="JETI_1211.jpg" width="257"
+ height="254">
+ <p><span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">specbos 1211</span><span
+ style="font-weight: bold;"> </span>and <b>1201</b> from <a
+ href="http://www.jeti.com/">JETI</a>&nbsp; are currently
+ available instruments. These are reference grade instruments
+ capable of emissive and ambient measurements, and are often used
+ for monitor, projector and cinema calibration &amp;
+ characterization, lighting measurement and colorimeter
+ calibration, amongst many other uses.<br>
+ </p>
+ <hr size="2" width="100%">
+ <p><span style="font-weight: bold;"><a name="ex1"></a><span
+ style="font-weight: bold;">Image Engineering EX1<br>
+ </span></span></p>
+ <img alt="Image Engineering EX1" src="EX1.jpg" width="253"
+ height="158"> <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;"><br>
+ Availability:<br>
+ <br>
+ </span>The <a
href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/ex1">Image
-
- Engineering EX1</a> is a currently available instruments. This is
- a high resolution spectrometer intended for the measurement of light
- sources.
- <p> </p>
- <p><br>
- </p>
- <hr size="2" width="100%">
- <p><span style="font-weight: bold;"><a name="k10a"></a><span
- style="font-weight: bold;">Klein K10-A Colorimeter<br>
- </span></span></p>
- <img alt="Klein K10-A" src="K10A.jpg" width="267" height="236"><br>
- <p><span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
+
+ Engineering EX1</a> is a currently available instruments. This is
+ a high resolution spectrometer intended for the measurement of light
+ sources.
+ <p> </p>
+ <p><br>
+ </p>
+ <hr size="2" width="100%">
+ <p><span style="font-weight: bold;"><a name="k10a"></a><span
+ style="font-weight: bold;">Klein K10-A Colorimeter<br>
+ </span></span></p>
+ <img alt="Klein K10-A" src="K10A.jpg" width="267" height="236"><br>
+ <p><span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
</span>The <span style="font-weight: bold;">Klein K10-A </span>from
@@ -1445,7 +1445,7 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
-
+
<a href="http://www.kleininstruments.com/">Klein Instruments</a>&nbsp;
@@ -1459,277 +1459,277 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
-
- is a currently available instrument. It is noted for it's speed,
- high precision, and ability to measure to very low light
- levels.This is a high end instruments capable of contact and tele
- - emissive, and ambient measurements, and are often used for
- monitor, projector and cinema calibration and characterization. <br>
- </p>
- <p>Note that unlike the operation of other instruments, the Ambient
- mode is purely manual - the diffuser must be fitted and then the
- appropriate calibration setting chosen (Typically with "Lux" in
- the name).<br>
- </p>
- <p>By default, more measurements are taken and averaged together
- when the light level is low. This can be disabled and a single
- measurement taken per reading, to gain maximum speed by using the
- -Y A flag.<br>
- </p>
- <p>The <b>K-1</b>, <b>K-8</b> and&nbsp; <b>K-10</b> are also
- reported to work. </p>
- <p> </p>
- <hr size="2" width="100%">
- <p><br>
- </p>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><a name="ColorMunki"></a><span
- style="font-weight: bold;">ColorMunki </span>Design or Photo <span
- style="font-weight: bold;">reflective/emissive spectrometer</span><br>
- <br>
- <img style="width: 272px; height: 243px;" alt="" title="ColorMunki
- (White)" src="ColorMunki.jpg">&nbsp;&nbsp; <br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">ColorMunki</span> <span
- style="font-weight: bold;">Design or Photo </span>from <a
- href="http://www.xrite.com/">X-Rite</a>&nbsp; is currently
- available in two different packages from the manufacturer. These
- packages differ in what features the manufacturers software
- provides, as well as cosmetic differences between the instrument
- (white and black). This comparison <a
- href="http://www.colormunki.com/product/show?page=2">chart</a>
- illustrates the differences. Used with Argyll, there are no
- differences in operation of a ColorMunki instrument, irrespective of
- which package it came with. The ColorMunki Design has the lowest
- RRP, but the Photo package may be cheaper with discounting .<br>
- <br>
- <span style="font-weight: bold;">Limitations &amp; Features:</span><br>
- <br>
- Unlike the Eye-One Pro, the ColorMunki is only available in a U.V.
- Cut (ie. "Ultra Violet filtered") model. This means that it is not
- suitable for use with the&nbsp; Fluorescent Whitener Additive
- Compensation option in Argyll (see <a href="FWA.html">here</a> for
- a discussion about what FWA compensation is).<br>
- <br>
- Like the Eye-One Pro, this instrument does support the <a
- href="spotread.html#H">high resolution</a> spectral mode.<br>
- <br>
- <span style="font-weight: bold;">OS X and X-Rite drivers</span><br>
- <br>
- Please note the installation <a
- href="Installing_OSX.html#ColorMunki">instructions</a>.<br>
- <br>
- <span style="font-weight: bold;">Tips &amp; Tricks:<br>
- <br>
- </span>In handling the instrument when about to make a reading, be
- very careful not to accidentally press the switch - it is large and
- easily pressed by accident. A guide of some sort (ie. a plastic
- ruler) can help a lot in&nbsp; keeping the instrument over a line
- of&nbsp; patches. <br>
- <br>
- <span style="font-weight: bold;">Patch recognition:</span><br>
- <br>
- For the best chances of good patch recognition, the instrument
- should be drawn smoothly and not too rapidly over the strip. (This
- can be a little tricky due to the two small rubber feet on the
- bottom of the device that aid its spot reading guide.) If there is a
- misread, try slowing down slightly. Generally a higher quality set
- of readings will result if slower scans are used, since there will
- then be more samples averaged for each patch. <br>
- <br>
- In <a href="chartread.html">chartread</a>, the -<span
- style="font-weight: bold;">T ratio</span> argument modifies the
- patch consistency tolerance threshold for the ColorMunki. In
- recognizing patches in a strip, the instrument takes multiple
- readings as the strip is read, and then divide the readings up into
- each patch. It then check the consistency of the multiple readings
- corresponding to each patch, and reject the measurement if they are
- too inconsistent. For some media (ie. a coarser screens, fabric
- etc.) the default tolerance may be unreasonably tight, so the <span
- style="font-weight: bold;">-T ratio</span> argument can be used to
- modify this criteria. To loosen the tolerance, use a number greater
- than 1.0 (ie. 1.5, 2.0). <br>
- <br>
- Note that <a href="printtarg.html">printtarg</a> provides the <a
- href="printtarg.html#h">-h</a> option that allows the choice of
- two different patch row widths with ColorMunki test charts. [Some
- people have successfully used the i1Pro patch layout with the
- ColorMunki, by making a guide to keep it over the much narrower
- patchs.]<br>
- <br>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
- style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP20"></a></span><span style="font-weight: bold;">DTP20
- "Pulse" reflective spectrometer<br>
- <br>
- </span><span style="font-weight: bold;"><img title="DTP20" alt=""
- src="DTP20.jpg" style="width: 304px; height: 210px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP20</span> from <a
- href="http://www.xrite.com/">X-Rite</a> was discontinued during
- 2007, but may still be available from old stock or second hand. <br>
- <br>
- <span style="font-weight: bold;">Special features:</span><br>
- <br>
- The <span style="font-weight: bold;">DTP20</span> has a couple of
- unique features that Argyll can take advantage of. One is that it
- can operate un-tethered (off line). A whole chart can be read
- un-tethered by first clearing any previous readings in the
- instrument, then reading the chart TID strip, before reading all the
- other strips. The instrument can then be connected up to <span
- style="font-weight: bold;">chartread</span>, which will recognize
- the chart, and download all the measurements.<br>
- If there is no chart in the instrument when chartread connects to
- it, then it will use the strip by strip tethered mode, just like the
- other strip instruments. If the right number of spot readings are
- present in the instrument, these will be used by <span
- style="font-weight: bold;">chartread</span> too.<br>
- <br>
- Un-tethered spot measurements can also be read in using&nbsp; <span
- style="font-weight: bold;">spotread</span>, which will notice the
- stored readings, and offer to print them out, or they can be
- ignored, and tethered readings taken. This will clear any saved spot
- readings.<br>
- <br>
- <span style="font-weight: bold;">Note</span> that tethered (on-line)
- strip reading will only work if the firmware in the device is
- version 1.03 or greater. You can check the firmware version by
- running with the verbose option: <span style="font-weight: bold;">-v<br>
- <br>
- Chart printing:<br>
- <span style="font-weight: bold;"><br>
- </span></span>Because the DTP20 measures exact distances using the
- markings on its ruler, it's critical that the chart be printed out
- exactly the right size. If the chart gets re-sized at all in the
- process of printing it, the DTP20 is likely to fail in reading it.
- If you have a problem with this, you might want to increase the page
- margins using the <span style="font-weight: bold;">printtarg -m</span>
- parameter, or find a printing path that preserves the test chart
- size correctly.<br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
- style="font-weight: bold;">Operation:<br>
- <br>
- </span>When reading in tethered (on-line) mode, that the instrument
- takes <span style="font-weight: bold;">several seconds</span> to
- download the measurements after each strip, and that the indicator
- will be in "rainbow" mode while this occurs. <span
- style="text-decoration: underline;">Wait</span> until the
- indicator turns solid green again before starting to measure the
- next strip.<br>
- <br>
- To <span style="font-weight: bold;">reset</span> the instrument and
- clear any stored readings: press the button three times in quick
- succession. The indicator will turn solid blue. Then hold the button
- down until the instrument beeps and the indicator goes out. Release
- the button and the indicator should flash then return to solid green
- (ready).<br>
- <br>
- To <span style="font-weight: bold;">calibrate</span> the
- instrument, place it on its calibration tile, then press the button
- three times in quick succession.The indicator will turn solid blue.
- Click the button another three times in quick succession, and the
- indicator should turn yellow. Then hold the button down until the
- instrument beeps and the indicator goes out. Release the button and
- the instrument should flash and then turn solid green.<br>
- <br>
- If the chart is particularly <span style="font-weight: bold;">small</span>,
- the patches may end up printed very close to the edge of the chart,
- and therefore it may be difficult to confine your scan to the chart,
- and passing<br>
- the instrument over the edge of the chart may prevent it reading
- successfully. One way of working around this is to place the chart
- on a larger piece of paper of the same type.<br>
- <br>
- The <span style="font-weight: bold;">speed</span> of scan can be
- quite critical with this instrument. In particular, it doesn't work
- very well if the scan is too <span style="font-weight: bold;">slow</span>.
- You don't want to go too fast either, as this reduces the number of
- samples per patch.<br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
- style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP22"></a></span><span style="font-weight: bold;">DTP22
- Digital Swatchbook reflective spectrometer</span><br>
- <span style="font-weight: bold;"><br>
- <img alt="" src="DTP22.jpg" style="width: 222px; height: 193px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP22</span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. It is
- capable of reading colored patches one at a time.<br>
- <br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP41"></a>DTP41 reflective, DTP41T
- reflective/transmissive spectrometers<br>
- <br>
- <img alt="" src="DTP41.jpg" style="width: 263px; height: 298px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP41</span> and <span
- style="font-weight: bold;">DTP41T</span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. <br>
- <br>
- The series II instruments (<span style="font-weight: bold;">DTP41B</span>
- and <span style="font-weight: bold;">DTP41TB</span>) offer both
- serial and USB connection. Note that currently only serial operation
- using Argyll is possible with these instruments.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <a name="dtp51"></a><span style="font-weight: bold;">DTP51
- reflective colorimeter<br>
- <br>
- <img alt="" src="DTP51.jpg" style="width: 263px; height: 223px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP51</span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. <br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"><br>
- </span></span>The DTP51's switch is triggered by inserting a strip
- into the slot.<br>
- <br>
- <br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="DTP92"></a>DTP92 CRT display colorimeter<br>
- <br>
- <img alt="" src="DTP92.jpg" style="width: 223px; height: 180px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP92</span><span
- style="font-weight: bold;"></span> from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument.&nbsp; It may still be available second hand. It will
- only read CRT technology displays.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+ is a currently available instrument. It is noted for it's speed,
+ high precision, and ability to measure to very low light
+ levels.This is a high end instruments capable of contact and tele
+ - emissive, and ambient measurements, and are often used for
+ monitor, projector and cinema calibration and characterization. <br>
+ </p>
+ <p>Note that unlike the operation of other instruments, the Ambient
+ mode is purely manual - the diffuser must be fitted and then the
+ appropriate calibration setting chosen (Typically with "Lux" in
+ the name).<br>
+ </p>
+ <p>By default, more measurements are taken and averaged together
+ when the light level is low. This can be disabled and a single
+ measurement taken per reading, to gain maximum speed by using the
+ -Y A flag.<br>
+ </p>
+ <p>The <b>K-1</b>, <b>K-8</b> and&nbsp; <b>K-10</b> are also
+ reported to work. </p>
+ <p> </p>
+ <hr size="2" width="100%">
+ <p><br>
+ </p>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><a name="ColorMunki"></a><span
+ style="font-weight: bold;">ColorMunki </span>Design or Photo <span
+ style="font-weight: bold;">reflective/emissive spectrometer</span><br>
+ <br>
+ <img style="width: 272px; height: 243px;" alt="" title="ColorMunki
+ (White)" src="ColorMunki.jpg">&nbsp;&nbsp; <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">ColorMunki</span> <span
+ style="font-weight: bold;">Design or Photo </span>from <a
+ href="http://www.xrite.com/">X-Rite</a>&nbsp; is currently
+ available in two different packages from the manufacturer. These
+ packages differ in what features the manufacturers software
+ provides, as well as cosmetic differences between the instrument
+ (white and black). This comparison <a
+ href="http://www.colormunki.com/product/show?page=2">chart</a>
+ illustrates the differences. Used with Argyll, there are no
+ differences in operation of a ColorMunki instrument, irrespective of
+ which package it came with. The ColorMunki Design has the lowest
+ RRP, but the Photo package may be cheaper with discounting .<br>
+ <br>
+ <span style="font-weight: bold;">Limitations &amp; Features:</span><br>
+ <br>
+ Unlike the Eye-One Pro, the ColorMunki is only available in a U.V.
+ Cut (ie. "Ultra Violet filtered") model. This means that it is not
+ suitable for use with the&nbsp; Fluorescent Whitener Additive
+ Compensation option in Argyll (see <a href="FWA.html">here</a> for
+ a discussion about what FWA compensation is).<br>
+ <br>
+ Like the Eye-One Pro, this instrument does support the <a
+ href="spotread.html#H">high resolution</a> spectral mode.<br>
+ <br>
+ <span style="font-weight: bold;">OS X and X-Rite drivers</span><br>
+ <br>
+ Please note the installation <a
+ href="Installing_OSX.html#ColorMunki">instructions</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Tips &amp; Tricks:<br>
+ <br>
+ </span>In handling the instrument when about to make a reading, be
+ very careful not to accidentally press the switch - it is large and
+ easily pressed by accident. A guide of some sort (ie. a plastic
+ ruler) can help a lot in&nbsp; keeping the instrument over a line
+ of&nbsp; patches. <br>
+ <br>
+ <span style="font-weight: bold;">Patch recognition:</span><br>
+ <br>
+ For the best chances of good patch recognition, the instrument
+ should be drawn smoothly and not too rapidly over the strip. (This
+ can be a little tricky due to the two small rubber feet on the
+ bottom of the device that aid its spot reading guide.) If there is a
+ misread, try slowing down slightly. Generally a higher quality set
+ of readings will result if slower scans are used, since there will
+ then be more samples averaged for each patch. <br>
+ <br>
+ In <a href="chartread.html">chartread</a>, the -<span
+ style="font-weight: bold;">T ratio</span> argument modifies the
+ patch consistency tolerance threshold for the ColorMunki. In
+ recognizing patches in a strip, the instrument takes multiple
+ readings as the strip is read, and then divide the readings up into
+ each patch. It then check the consistency of the multiple readings
+ corresponding to each patch, and reject the measurement if they are
+ too inconsistent. For some media (ie. a coarser screens, fabric
+ etc.) the default tolerance may be unreasonably tight, so the <span
+ style="font-weight: bold;">-T ratio</span> argument can be used to
+ modify this criteria. To loosen the tolerance, use a number greater
+ than 1.0 (ie. 1.5, 2.0). <br>
+ <br>
+ Note that <a href="printtarg.html">printtarg</a> provides the <a
+ href="printtarg.html#h">-h</a> option that allows the choice of
+ two different patch row widths with ColorMunki test charts. [Some
+ people have successfully used the i1Pro patch layout with the
+ ColorMunki, by making a guide to keep it over the much narrower
+ patchs.]<br>
+ <br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP20"></a></span><span style="font-weight: bold;">DTP20
+ "Pulse" reflective spectrometer<br>
+ <br>
+ </span><span style="font-weight: bold;"><img title="DTP20" alt=""
+ src="DTP20.jpg" style="width: 304px; height: 210px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP20</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> was discontinued during
+ 2007, but may still be available from old stock or second hand. <br>
+ <br>
+ <span style="font-weight: bold;">Special features:</span><br>
+ <br>
+ The <span style="font-weight: bold;">DTP20</span> has a couple of
+ unique features that Argyll can take advantage of. One is that it
+ can operate un-tethered (off line). A whole chart can be read
+ un-tethered by first clearing any previous readings in the
+ instrument, then reading the chart TID strip, before reading all the
+ other strips. The instrument can then be connected up to <span
+ style="font-weight: bold;">chartread</span>, which will recognize
+ the chart, and download all the measurements.<br>
+ If there is no chart in the instrument when chartread connects to
+ it, then it will use the strip by strip tethered mode, just like the
+ other strip instruments. If the right number of spot readings are
+ present in the instrument, these will be used by <span
+ style="font-weight: bold;">chartread</span> too.<br>
+ <br>
+ Un-tethered spot measurements can also be read in using&nbsp; <span
+ style="font-weight: bold;">spotread</span>, which will notice the
+ stored readings, and offer to print them out, or they can be
+ ignored, and tethered readings taken. This will clear any saved spot
+ readings.<br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that tethered (on-line)
+ strip reading will only work if the firmware in the device is
+ version 1.03 or greater. You can check the firmware version by
+ running with the verbose option: <span style="font-weight: bold;">-v<br>
+ <br>
+ Chart printing:<br>
+ <span style="font-weight: bold;"><br>
+ </span></span>Because the DTP20 measures exact distances using the
+ markings on its ruler, it's critical that the chart be printed out
+ exactly the right size. If the chart gets re-sized at all in the
+ process of printing it, the DTP20 is likely to fail in reading it.
+ If you have a problem with this, you might want to increase the page
+ margins using the <span style="font-weight: bold;">printtarg -m</span>
+ parameter, or find a printing path that preserves the test chart
+ size correctly.<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;">Operation:<br>
+ <br>
+ </span>When reading in tethered (on-line) mode, that the instrument
+ takes <span style="font-weight: bold;">several seconds</span> to
+ download the measurements after each strip, and that the indicator
+ will be in "rainbow" mode while this occurs. <span
+ style="text-decoration: underline;">Wait</span> until the
+ indicator turns solid green again before starting to measure the
+ next strip.<br>
+ <br>
+ To <span style="font-weight: bold;">reset</span> the instrument and
+ clear any stored readings: press the button three times in quick
+ succession. The indicator will turn solid blue. Then hold the button
+ down until the instrument beeps and the indicator goes out. Release
+ the button and the indicator should flash then return to solid green
+ (ready).<br>
+ <br>
+ To <span style="font-weight: bold;">calibrate</span> the
+ instrument, place it on its calibration tile, then press the button
+ three times in quick succession.The indicator will turn solid blue.
+ Click the button another three times in quick succession, and the
+ indicator should turn yellow. Then hold the button down until the
+ instrument beeps and the indicator goes out. Release the button and
+ the instrument should flash and then turn solid green.<br>
+ <br>
+ If the chart is particularly <span style="font-weight: bold;">small</span>,
+ the patches may end up printed very close to the edge of the chart,
+ and therefore it may be difficult to confine your scan to the chart,
+ and passing<br>
+ the instrument over the edge of the chart may prevent it reading
+ successfully. One way of working around this is to place the chart
+ on a larger piece of paper of the same type.<br>
+ <br>
+ The <span style="font-weight: bold;">speed</span> of scan can be
+ quite critical with this instrument. In particular, it doesn't work
+ very well if the scan is too <span style="font-weight: bold;">slow</span>.
+ You don't want to go too fast either, as this reduces the number of
+ samples per patch.<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP22"></a></span><span style="font-weight: bold;">DTP22
+ Digital Swatchbook reflective spectrometer</span><br>
+ <span style="font-weight: bold;"><br>
+ <img alt="" src="DTP22.jpg" style="width: 222px; height: 193px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP22</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. It is
+ capable of reading colored patches one at a time.<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP41"></a>DTP41 reflective, DTP41T
+ reflective/transmissive spectrometers<br>
+ <br>
+ <img alt="" src="DTP41.jpg" style="width: 263px; height: 298px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP41</span> and <span
+ style="font-weight: bold;">DTP41T</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. <br>
+ <br>
+ The series II instruments (<span style="font-weight: bold;">DTP41B</span>
+ and <span style="font-weight: bold;">DTP41TB</span>) offer both
+ serial and USB connection. Note that currently only serial operation
+ using Argyll is possible with these instruments.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <a name="dtp51"></a><span style="font-weight: bold;">DTP51
+ reflective colorimeter<br>
+ <br>
+ <img alt="" src="DTP51.jpg" style="width: 263px; height: 223px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP51</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. <br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"><br>
+ </span></span>The DTP51's switch is triggered by inserting a strip
+ into the slot.<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP92"></a>DTP92 CRT display colorimeter<br>
+ <br>
+ <img alt="" src="DTP92.jpg" style="width: 223px; height: 180px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP92</span><span
+ style="font-weight: bold;"></span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. It will
+ only read CRT technology displays.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -1777,33 +1777,33 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
-
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type [Default, CB2].<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="DTP94"></a>DTP94, </span><font
- size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro" <span
- style="font-weight: bold;">display colorimetrers</span><br>
- <span style="font-weight: bold;"><br>
- <img title="DTP94" alt="" src="DTP94.jpg" style="width: 138px;
- height: 171px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
- &nbsp; &nbsp; <img alt="" title="Optix XR/Pro" src="moxxr.jpg"
- style="width: 155px; height: 190px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">DTP94 </span>from <a
- href="http://www.xrite.com/">X-Rite</a> is a discontinued
- instrument, although it is still being supplied to OEMs.&nbsp; It
- may still be available as old stock, or second hand. It was sold as
- an instrument without software as the DTP94, and packaged with
- software from the manufacturer as the "Optix XR" range.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type [Default, CB2].<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="DTP94"></a>DTP94, </span><font
+ size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro" <span
+ style="font-weight: bold;">display colorimetrers</span><br>
+ <span style="font-weight: bold;"><br>
+ <img title="DTP94" alt="" src="DTP94.jpg" style="width: 138px;
+ height: 171px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; <img alt="" title="Optix XR/Pro" src="moxxr.jpg"
+ style="width: 155px; height: 190px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP94 </span>from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument, although it is still being supplied to OEMs.&nbsp; It
+ may still be available as old stock, or second hand. It was sold as
+ an instrument without software as the DTP94, and packaged with
+ software from the manufacturer as the "Optix XR" range.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -1846,9 +1846,9 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
-
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type [default, CB1].<br>
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type [default, CB1].<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -1896,24 +1896,24 @@ href="http://www.image-engineering.de/iq-products/iq-tools/measurement-devices/e
-
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type [CB2].<br>
- &nbsp;&nbsp;&nbsp; <b>g</b>&nbsp;&nbsp;&nbsp;
- Generic&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Generic
- display [CB3]<br>
- &nbsp;&nbsp; <br>
- <br>
- <span style="font-weight: bold;"></span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="sl"></a>Spectrolino reflective/emissive spectrometer<br>
- <br>
- <img alt="" src="sl.jpg" style="width: 239px; height: 200px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type [CB2].<br>
+ &nbsp;&nbsp;&nbsp; <b>g</b>&nbsp;&nbsp;&nbsp;
+ Generic&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Generic
+ display [CB3]<br>
+ &nbsp;&nbsp; <br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="sl"></a>Spectrolino reflective/emissive spectrometer<br>
+ <br>
+ <img alt="" src="sl.jpg" style="width: 239px; height: 200px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
</span>The <span style="font-weight: bold;">Spectrolino </span>from
Gretag
@@ -1962,226 +1962,226 @@ Gretag
-
- MacBeth (Now X-Rite) is a discontinued instrument. It is often
- available second hand. If buying it second hand, make sure it comes
- with all it's accessories, including white reference, spot reading
- adapter, display reading adapters, filters (UV, polarizing, D65),
- serial cable adapter and power supply.<br>
- <span style="font-weight: bold;"><br>
- </span>
- <hr style="width: 100%; height: 2px;"><span style="font-weight:
- bold;"><br>
- <a name="ss"></a>SpectroScan reflective/emissive and SpectroScanT
- reflective/emissive/transmissive spectrometers<br>
- <br>
- <img style="width: 336px; height: 294px;" alt="" src="ss.jpg"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">SpectroScan</span> and
- <span style="font-weight: bold;">SpectroScanT</span> from Gretag
- MacBeth (Now X-Rite) is a discontinued instrument. It is the
- combination of an X-Y table and the <span style="font-weight:
- bold;">Spectrolino</span> instrument. The <span
- style="font-weight: bold;">SpectroScanT</span> is capable of
- measuring transparency. It is often available second hand. If buying
- it second hand, make sure it comes with all it's accessories,
- including white reference, spot reading adapter, display reading
- adapters, filters (UV, polarizing, D65) and power supply.<br>
- <br>
- If measuring transparencies using a SpectroScanT, the <b>Enter</b>
- key on the instrument may be used to trigger each reading. It will
- be recognized after each previous reading has been completed.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <br>
- <span style="font-weight: bold;"><a name="i1p2"></a>Eye-One Pro2:</span><br>
- <img style=" width: 357px; height: 234px;" alt="Eye-One Pro 2"
- src="i1pro2.jpg"><br>
- <br>
- There is support for some of the new features of the Eye-One Pro2
- (also known as the Eye-One Pro Rev E), in particular the&nbsp; Rev E
- measurement mode, spectrometer stray light reduction, wavelength
- calibration, and improved black level tracking. This new support can
- be disabled and an Eye-One Pro2 operated in legacy mode by setting
- the environment variable ARGYLL_DISABLE_I1PRO2_DRIVER. See <a
- href="instruments.html#i1p">Eye-One Pro reflective/emissive
- spectrometer</a><span style="font-weight: bold;"> </span>below
- for details on the operation of this type of instrument.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1p"></a>Eye-One Pro and
- Eye-One Pro2 reflective/emissive spectrometer<br>
- <br>
- <img alt="" src="i1p.jpg" style="width: 347px; height: 234px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Eye-One Pro</span> from
- <a href="http://www.xrite.com/">X-Rite</a> (was Gretag MacBeth) is
- available in two packages from the manufacturer. These packages
- differ partly in what accessories come with the instrument, but
- primarily in what features the manufacturers software provides. This
- comparison <a
- href="http://www.xrite.com/product_overview.aspx?ID=812">chart</a>
- illustrates the differences. Used with Argyll, there are no
- differences in operation of an Eye-One Pro instrument, irrespective
- of which package it came with. The lowest cost package is the <a
- href="http://www.xrite.com/product_overview.aspx?ID=1461">i1 Basic
- Pro</a>.<br>
- <br>
- The EFI ES-1000 (which is a re-badged Eye-One Pro) is also reported
- to work with Argyll.<br>
- <br>
- Unless you know what you're doing, and have a very specific reason
- to buy an instrument fitted with a UV (Ultra Violet) filter, make
- sure that you buy an instrument without the filter. A UV filtered
- instrument can't deal intelligently with FWA (Fluorescent Whitener
- Additive) effects in paper. (Look <a href="FWA.html">here</a> for
- more information about FWA compensation.) Using FWA compensation you
- can make measurements using ISO 13655:2009 M0, M1 and M2 conditions.
- The M2 condition emulates a UV cut instrument.<br>
- <br>
- There have been four revisions of the Eye-One Pro, Rev. A, B, D and
- E (AKA Eye-One Pro2). The rev B, D and E are capable of sampling
- twice as fast as the Rev. A version of the instrument, and are also
- available with an ambient light reading capability.<br>
- <br>
- <span style="font-weight: bold;">NOTE</span> for those running on
- older versions of Linux with a Rev. D, there was a problem with the
- Linux USB stack that causes the instrument to stop working once it
- has been used. The only workaround is to unplug and replug the
- instrument in again, whereupon it can be used one time again. A fix
- for this problem was in the&nbsp; Linux 2.6.26 kernel release.<br>
- <br>
- See also <a href="i1proDriver.html">How can I have confidence in
- the i1pro Driver ?</a><br>
- <br>
- <span style="font-weight: bold;">Patch recognition:</span><br>
- <br>
- For the best chances of good patch recognition, the instrument
- should be drawn smoothly and not too rapidly over the strip. If
- there is a misread, try slowing down slightly. The Rev A and B.
- instruments have a slower sampling rate than the latter revision
- instruments, and hence must be used a bit more slowly. Generally a
- higher quality set of readings will result if slower scans are used,
- since there will then be more samples averaged for each patch.<br>
- <br>
- In <a href="chartread.html">chartread</a>, the -<span
- style="font-weight: bold;">T ratio</span> argument modifies the
- patch consistency tolerance threshold for the Eye-One Pro. In
- recognizing patches in a strip, the instrument takes multiple
- readings as the strip is read, and then divide the readings up into
- each patch. It then check the consistency of the multiple readings
- corresponding to each patch, and reject the measurement if they are
- too inconsistent. For some media (ie. a coarser screens, fabric
- etc.) the default tolerance may be unreasonably tight, so the <span
- style="font-weight: bold;">-T ratio</span> argument can be used to
- modify this criteria. To loosen the tolerance, use a number greater
- than 1.0 (ie. 1.5, 2.0). <span style="font-weight: bold;"></span><br>
- <br>
- <span style="font-weight: bold;">Special features:</span><br>
- <br>
- A feature unique to Argyll when used with the Eye-One Pro, is the
- high resolution spectral mode. This returns spectral measurements at
- 3.333 nm spacing, rather than the default 10nm spacing, and also
- extends the range of wavelengths very slightly. This high resolution
- may assist in giving better accuracy for "peaky" emissive sources
- such as illuminants and displays. The high resolution mode is
- selected by using the <span style="font-weight: bold;">-H</span>
- flag on the command line to <span style="font-weight: bold;">dispcal</span>,
- <span style="font-weight: bold;">dispread</span>, <span
- style="font-weight: bold;">chartread</span>, and <span
- style="font-weight: bold;">spotread</span>. It can also be toggled
- on and off within <span style="font-weight: bold;">spotread</span>
- using the <span style="font-weight: bold;">h</span> key.<br>
- <br>
- Note that while finer spectral resolution will worsen the signal to
- noise ratio of the individual spectral values, the signal to noise
- ratio of the resulting tri-stimulus color values will be identical
- to normal resolution mode, since the same overall integration is
- performed. <br>
- <br>
- See <a href="i1proHiRes.html">Does the i1pro High Resolution mode
- improve accuracy ?</a><br>
- <br>
- <img alt="High res. and standard res. spectrum."
- src="Fluorescent.jpg" style="width: 750px; height: 375px;"><br>
- <br>
- <img alt="C.R.T high res. and standard res. spectrum."
- src="CRTspectrum.jpg" style="width: 750px; height: 375px;"><br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1m"></a>Eye-One Monitor
- emissive spectrometer<br>
- <br>
- <img alt="" src="i1m.jpg" style="width: 347px; height: 234px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Eye-One Monitor</span>
- from <a href="http://www.xrite.com/">X-Rite</a> (was Gretag
- MacBeth) is a discontinued instrument. It was a lower cost version
- of the <span style="font-weight: bold;">Eye-One Pro</span> without
- reflective measurement capability. See <a href="#i1p">Eye-One Pro
- reflective/emissive spectrometer</a><span style="font-weight:
- bold;"> </span>for details on the operation of this instrument.<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1d"></a>Eye-One Display
- 1, Eye-One Display 2, Eye-One Display LT, ColorMunki Create,
- ColorMunki Smile colorimeters,<br>
- <br>
- <img style=" width: 124px; height: 168px;" alt="ColorMunki Smile"
- src="Smile.jpg"><img alt="Eye-One Display 2" src="i1d.jpg"
- style="width: 145px; height: 168px;"> <img style="width: 133px;
- height: 168px;" alt="ColorMunki Create"
- src="ColorMunkiCreate.jpg"><br>
- <br>
- Instrument Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">ColorMunki Smile</span>
- colorimeter is a currently available instrument.<br>
- The <span style="font-weight: bold;">Eye-One Display LT</span> and
- <span style="font-weight: bold;">Eye-One Display 2</span> are
- discontinued products, although they may still be available from
- some retailers, second hand, and may still be shipped with some
- displays as part of their calibration capability.<br>
- The <span style="font-weight: bold;">ColorMunki Create</span>
- colorimeter is a discontinued product, although they may still be
- available from some retailers or second hand,can also be used. They
- will appear as an i1Display2 colorimeter.<br>
- The <span style="font-weight: bold;">HP DreamColor</span>
- colorimeter can also be used, and will appear as an i1Display2
- colorimeter [note that it is calibrated for the DreamColor display].<br>
- The <span style="font-weight: bold;">HP APS</span> (Advanced
- Profiling Solution) colorimeter is also reported to work, and will
- appear as an i1Display2.<br>
- The <span style="font-weight: bold;">CalMAN X2</span> colorimeter
- is also reported to work, and will appear as an i1Display2
- colorimeter.<br>
- The&nbsp; <span style="font-weight: bold;">Lacie Blue Eye</span> <span
- style="font-weight: bold;"></span> colorimeter is also reported to
- work, and will appear as an i1Display2 colorimeter.<br>
- <br>
- <span style="font-weight: bold;"></span>The <span
- style="font-weight: bold;">Eye-One Display 1</span> is a
- discontinued instrument. <br>
- <br>
- The Eye-One Display LT came with a less expensive<span
- style="text-decoration: underline;"></span> package with more
- limited software from the manufacture.<br>
- The Eye-One Display 2 package came with more software
- features,&nbsp; but the instruments are virtually identical, and
- will operate identically using Argyll.<br>
- The ColorMunki Create<span style="text-decoration: underline;"></span>
- package is another alternative, and will operate identically using
- Argyll.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
+
+ MacBeth (Now X-Rite) is a discontinued instrument. It is often
+ available second hand. If buying it second hand, make sure it comes
+ with all it's accessories, including white reference, spot reading
+ adapter, display reading adapters, filters (UV, polarizing, D65),
+ serial cable adapter and power supply.<br>
+ <span style="font-weight: bold;"><br>
+ </span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="ss"></a>SpectroScan reflective/emissive and SpectroScanT
+ reflective/emissive/transmissive spectrometers<br>
+ <br>
+ <img style="width: 336px; height: 294px;" alt="" src="ss.jpg"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">SpectroScan</span> and
+ <span style="font-weight: bold;">SpectroScanT</span> from Gretag
+ MacBeth (Now X-Rite) is a discontinued instrument. It is the
+ combination of an X-Y table and the <span style="font-weight:
+ bold;">Spectrolino</span> instrument. The <span
+ style="font-weight: bold;">SpectroScanT</span> is capable of
+ measuring transparency. It is often available second hand. If buying
+ it second hand, make sure it comes with all it's accessories,
+ including white reference, spot reading adapter, display reading
+ adapters, filters (UV, polarizing, D65) and power supply.<br>
+ <br>
+ If measuring transparencies using a SpectroScanT, the <b>Enter</b>
+ key on the instrument may be used to trigger each reading. It will
+ be recognized after each previous reading has been completed.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <br>
+ <span style="font-weight: bold;"><a name="i1p2"></a>Eye-One Pro2:</span><br>
+ <img style=" width: 357px; height: 234px;" alt="Eye-One Pro 2"
+ src="i1pro2.jpg"><br>
+ <br>
+ There is support for some of the new features of the Eye-One Pro2
+ (also known as the Eye-One Pro Rev E), in particular the&nbsp; Rev E
+ measurement mode, spectrometer stray light reduction, wavelength
+ calibration, and improved black level tracking. This new support can
+ be disabled and an Eye-One Pro2 operated in legacy mode by setting
+ the environment variable ARGYLL_DISABLE_I1PRO2_DRIVER. See <a
+ href="instruments.html#i1p">Eye-One Pro reflective/emissive
+ spectrometer</a><span style="font-weight: bold;"> </span>below
+ for details on the operation of this type of instrument.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1p"></a>Eye-One Pro and
+ Eye-One Pro2 reflective/emissive spectrometer<br>
+ <br>
+ <img alt="" src="i1p.jpg" style="width: 347px; height: 234px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Eye-One Pro</span> from
+ <a href="http://www.xrite.com/">X-Rite</a> (was Gretag MacBeth) is
+ available in two packages from the manufacturer. These packages
+ differ partly in what accessories come with the instrument, but
+ primarily in what features the manufacturers software provides. This
+ comparison <a
+ href="http://www.xrite.com/product_overview.aspx?ID=812">chart</a>
+ illustrates the differences. Used with Argyll, there are no
+ differences in operation of an Eye-One Pro instrument, irrespective
+ of which package it came with. The lowest cost package is the <a
+ href="http://www.xrite.com/product_overview.aspx?ID=1461">i1 Basic
+ Pro</a>.<br>
+ <br>
+ The EFI ES-1000 (which is a re-badged Eye-One Pro) is also reported
+ to work with Argyll.<br>
+ <br>
+ Unless you know what you're doing, and have a very specific reason
+ to buy an instrument fitted with a UV (Ultra Violet) filter, make
+ sure that you buy an instrument without the filter. A UV filtered
+ instrument can't deal intelligently with FWA (Fluorescent Whitener
+ Additive) effects in paper. (Look <a href="FWA.html">here</a> for
+ more information about FWA compensation.) Using FWA compensation you
+ can make measurements using ISO 13655:2009 M0, M1 and M2 conditions.
+ The M2 condition emulates a UV cut instrument.<br>
+ <br>
+ There have been four revisions of the Eye-One Pro, Rev. A, B, D and
+ E (AKA Eye-One Pro2). The rev B, D and E are capable of sampling
+ twice as fast as the Rev. A version of the instrument, and are also
+ available with an ambient light reading capability.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> for those running on
+ older versions of Linux with a Rev. D, there was a problem with the
+ Linux USB stack that causes the instrument to stop working once it
+ has been used. The only workaround is to unplug and replug the
+ instrument in again, whereupon it can be used one time again. A fix
+ for this problem was in the&nbsp; Linux 2.6.26 kernel release.<br>
+ <br>
+ See also <a href="i1proDriver.html">How can I have confidence in
+ the i1pro Driver ?</a><br>
+ <br>
+ <span style="font-weight: bold;">Patch recognition:</span><br>
+ <br>
+ For the best chances of good patch recognition, the instrument
+ should be drawn smoothly and not too rapidly over the strip. If
+ there is a misread, try slowing down slightly. The Rev A and B.
+ instruments have a slower sampling rate than the latter revision
+ instruments, and hence must be used a bit more slowly. Generally a
+ higher quality set of readings will result if slower scans are used,
+ since there will then be more samples averaged for each patch.<br>
+ <br>
+ In <a href="chartread.html">chartread</a>, the -<span
+ style="font-weight: bold;">T ratio</span> argument modifies the
+ patch consistency tolerance threshold for the Eye-One Pro. In
+ recognizing patches in a strip, the instrument takes multiple
+ readings as the strip is read, and then divide the readings up into
+ each patch. It then check the consistency of the multiple readings
+ corresponding to each patch, and reject the measurement if they are
+ too inconsistent. For some media (ie. a coarser screens, fabric
+ etc.) the default tolerance may be unreasonably tight, so the <span
+ style="font-weight: bold;">-T ratio</span> argument can be used to
+ modify this criteria. To loosen the tolerance, use a number greater
+ than 1.0 (ie. 1.5, 2.0). <span style="font-weight: bold;"></span><br>
+ <br>
+ <span style="font-weight: bold;">Special features:</span><br>
+ <br>
+ A feature unique to Argyll when used with the Eye-One Pro, is the
+ high resolution spectral mode. This returns spectral measurements at
+ 3.333 nm spacing, rather than the default 10nm spacing, and also
+ extends the range of wavelengths very slightly. This high resolution
+ may assist in giving better accuracy for "peaky" emissive sources
+ such as illuminants and displays. The high resolution mode is
+ selected by using the <span style="font-weight: bold;">-H</span>
+ flag on the command line to <span style="font-weight: bold;">dispcal</span>,
+ <span style="font-weight: bold;">dispread</span>, <span
+ style="font-weight: bold;">chartread</span>, and <span
+ style="font-weight: bold;">spotread</span>. It can also be toggled
+ on and off within <span style="font-weight: bold;">spotread</span>
+ using the <span style="font-weight: bold;">h</span> key.<br>
+ <br>
+ Note that while finer spectral resolution will worsen the signal to
+ noise ratio of the individual spectral values, the signal to noise
+ ratio of the resulting tri-stimulus color values will be identical
+ to normal resolution mode, since the same overall integration is
+ performed. <br>
+ <br>
+ See <a href="i1proHiRes.html">Does the i1pro High Resolution mode
+ improve accuracy ?</a><br>
+ <br>
+ <img alt="High res. and standard res. spectrum."
+ src="Fluorescent.jpg" style="width: 750px; height: 375px;"><br>
+ <br>
+ <img alt="C.R.T high res. and standard res. spectrum."
+ src="CRTspectrum.jpg" style="width: 750px; height: 375px;"><br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1m"></a>Eye-One Monitor
+ emissive spectrometer<br>
+ <br>
+ <img alt="" src="i1m.jpg" style="width: 347px; height: 234px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Eye-One Monitor</span>
+ from <a href="http://www.xrite.com/">X-Rite</a> (was Gretag
+ MacBeth) is a discontinued instrument. It was a lower cost version
+ of the <span style="font-weight: bold;">Eye-One Pro</span> without
+ reflective measurement capability. See <a href="#i1p">Eye-One Pro
+ reflective/emissive spectrometer</a><span style="font-weight:
+ bold;"> </span>for details on the operation of this instrument.<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1d"></a>Eye-One Display
+ 1, Eye-One Display 2, Eye-One Display LT, ColorMunki Create,
+ ColorMunki Smile colorimeters,<br>
+ <br>
+ <img style=" width: 124px; height: 168px;" alt="ColorMunki Smile"
+ src="Smile.jpg"><img alt="Eye-One Display 2" src="i1d.jpg"
+ style="width: 145px; height: 168px;"> <img style="width: 133px;
+ height: 168px;" alt="ColorMunki Create"
+ src="ColorMunkiCreate.jpg"><br>
+ <br>
+ Instrument Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">ColorMunki Smile</span>
+ colorimeter is a currently available instrument.<br>
+ The <span style="font-weight: bold;">Eye-One Display LT</span> and
+ <span style="font-weight: bold;">Eye-One Display 2</span> are
+ discontinued products, although they may still be available from
+ some retailers, second hand, and may still be shipped with some
+ displays as part of their calibration capability.<br>
+ The <span style="font-weight: bold;">ColorMunki Create</span>
+ colorimeter is a discontinued product, although they may still be
+ available from some retailers or second hand,can also be used. They
+ will appear as an i1Display2 colorimeter.<br>
+ The <span style="font-weight: bold;">HP DreamColor</span>
+ colorimeter can also be used, and will appear as an i1Display2
+ colorimeter [note that it is calibrated for the DreamColor display].<br>
+ The <span style="font-weight: bold;">HP APS</span> (Advanced
+ Profiling Solution) colorimeter is also reported to work, and will
+ appear as an i1Display2.<br>
+ The <span style="font-weight: bold;">CalMAN X2</span> colorimeter
+ is also reported to work, and will appear as an i1Display2
+ colorimeter.<br>
+ The&nbsp; <span style="font-weight: bold;">Lacie Blue Eye</span> <span
+ style="font-weight: bold;"></span> colorimeter is also reported to
+ work, and will appear as an i1Display2 colorimeter.<br>
+ <br>
+ <span style="font-weight: bold;"></span>The <span
+ style="font-weight: bold;">Eye-One Display 1</span> is a
+ discontinued instrument. <br>
+ <br>
+ The Eye-One Display LT came with a less expensive<span
+ style="text-decoration: underline;"></span> package with more
+ limited software from the manufacture.<br>
+ The Eye-One Display 2 package came with more software
+ features,&nbsp; but the instruments are virtually identical, and
+ will operate identically using Argyll.<br>
+ The ColorMunki Create<span style="text-decoration: underline;"></span>
+ package is another alternative, and will operate identically using
+ Argyll.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
The Display Selections for the <span style="font-weight: bold;">ColorMunki
@@ -2214,13 +2214,13 @@ Gretag
-
- Smile</span> are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f</span>
- &nbsp;&nbsp; LCD with CCFL back-light&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses a Cold
- Cathode Fluorescent back lighting. [Default, CB1]<br>
+
+ Smile</span> are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f</span>
+ &nbsp;&nbsp; LCD with CCFL back-light&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses a Cold
+ Cathode Fluorescent back lighting. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>&nbsp;&nbsp;&nbsp;
@@ -2251,13 +2251,13 @@ Gretag
-
- LCD with LED back-light&nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses
- Light Emitting Diode back lighting.<br>
- <br>
- other instruments will offer:<br>
- <br>
+
+ LCD with LED back-light&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses
+ Light Emitting Diode back lighting.<br>
+ <br>
+ other instruments will offer:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2305,9 +2305,9 @@ Gretag
-
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2355,55 +2355,55 @@ Gretag
-
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
- Cathode Ray Tube display, that is of the Refresh type. [CB2]<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="i1d3"></a></span>&nbsp; <span
- style="font-weight: bold;">i1 DisplayPro and ColorMunki Display<span
- style="font-weight: bold;"> colorimeters (i1 Display 3)</span><br>
- <br>
- <img alt="i1 Display Pro" src="i1d3_1.jpg" style="width: 194px;
- height: 223px;"> <img style="width: 176px; height: 222px;"
- alt="ColorMunki Display" src="i1d3_2.jpg"><br>
- <br>
- Instrument Availability:<br>
- <br>
- </span>Both instruments are currently available..<br>
- <br>
- The ColorMunki Display is a less expensive <a
-href="http://xritephoto.com/ph_product_overview.aspx?id=1513&amp;catid=149">package</a>
- with more limited software from the manufacture, and takes a
- noticeably longer time to make most measurements (a minimum of 1
- second), but both instruments will take longer for very dark
- samples, and under these conditions the speed difference is less
- significant.<br>
- <br>
- The i1Display Pro <a
-href="http://xritephoto.com/ph_product_overview.aspx?id=1454&amp;catid=109">package</a>
- comes with i1Profiler, and the instrument is generally faster than
- the ColorMunki Display, but other than this and the software
- package, the instruments appear to be virtually identical. (Note
- though that the ColorMunki Display is <u>unable</u> to measure the
- refresh period, so is less repeatable in this mode than the
- i1Display Pro).<br>
- <br>
- Both instruments are capable of using CCSS (<a
- href="File_Formats.html#ccss">Colorimeter Calibration Spectral
- Sample</a>) files, and this also gives the instrument the
- capability of using a non-default standard observer. CCSS files can
- be created using the <a href="ccxxmake.html">ccxxmake</a> tool, and
- installed or translated from the .EDR files that are provided with
- the instrument CD using the <a href="oeminst.html">oeminst</a>
- utility using a spectrometer as a reference.<br>
- <br>
- There are some OEM versions of this instrument around too, and the <a
- href="http://www.spectracal.com/">SpectraCal OEM i1Display</a>, <a
- href="http://www.chromapure.com/">ChromaPure</a>, <a
- href="http://www.necdisplay.com/p/sensors/mdsvsensor3">NEC
- SpectraSensor Pro</a> and <a
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
+ Cathode Ray Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1d3"></a></span>&nbsp; <span
+ style="font-weight: bold;">i1 DisplayPro and ColorMunki Display<span
+ style="font-weight: bold;"> colorimeters (i1 Display 3)</span><br>
+ <br>
+ <img alt="i1 Display Pro" src="i1d3_1.jpg" style="width: 194px;
+ height: 223px;"> <img style="width: 176px; height: 222px;"
+ alt="ColorMunki Display" src="i1d3_2.jpg"><br>
+ <br>
+ Instrument Availability:<br>
+ <br>
+ </span>Both instruments are currently available..<br>
+ <br>
+ The ColorMunki Display is a less expensive <a
+href="http://xritephoto.com/ph_product_overview.aspx?id=1513&amp;catid=149">package</a>
+ with more limited software from the manufacture, and takes a
+ noticeably longer time to make most measurements (a minimum of 1
+ second), but both instruments will take longer for very dark
+ samples, and under these conditions the speed difference is less
+ significant.<br>
+ <br>
+ The i1Display Pro <a
+href="http://xritephoto.com/ph_product_overview.aspx?id=1454&amp;catid=109">package</a>
+ comes with i1Profiler, and the instrument is generally faster than
+ the ColorMunki Display, but other than this and the software
+ package, the instruments appear to be virtually identical. (Note
+ though that the ColorMunki Display is <u>unable</u> to measure the
+ refresh period, so is less repeatable in this mode than the
+ i1Display Pro).<br>
+ <br>
+ Both instruments are capable of using CCSS (<a
+ href="File_Formats.html#ccss">Colorimeter Calibration Spectral
+ Sample</a>) files, and this also gives the instrument the
+ capability of using a non-default standard observer. CCSS files can
+ be created using the <a href="ccxxmake.html">ccxxmake</a> tool, and
+ installed or translated from the .EDR files that are provided with
+ the instrument CD using the <a href="oeminst.html">oeminst</a>
+ utility using a spectrometer as a reference.<br>
+ <br>
+ There are some OEM versions of this instrument around too, and the <a
+ href="http://www.spectracal.com/">SpectraCal OEM i1Display</a>, <a
+ href="http://www.chromapure.com/">ChromaPure</a>, <a
+ href="http://www.necdisplay.com/p/sensors/mdsvsensor3">NEC
+ SpectraSensor Pro</a> and <a
href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
@@ -2424,84 +2424,84 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- DreamColor</a> instruments are also reported to work. They will
- appear as a be a the same as the i1Display Pro.<br>
- <span style="font-weight: bold;">[Note</span> that if you have an
- OEM version of this instrument, it's worth checking if they come
- with any extra .edr files, that can then be translated for use with
- ArgyllCMS using <a href="oeminst.html">oeminst</a>.]<br>
- <br>
- On MSWindows, if you have installed the Manufacturers applications,
- you may have to shut the i1Profiler tray application down before
- Argyll can open the instrument.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp; A
- non-refresh type display [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
- &nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh period
- is measured, and the integration time adjusted appropriately. [CB2]<br>
- <br>
- With the manufacturers .edr files &amp; reference Argyll .ccss files
- installed, the following selections are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
- non-refresh type display [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
- &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh
- period is measured, and the integration time adjusted appropriately.
- [CB2]<br>
- &nbsp;&nbsp;&nbsp; <b>c</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRT
- (Hitachi CM2112MET, Diamond View 1772ie)<br>
- &nbsp;&nbsp;&nbsp; <b>l</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
- IPS (CCFL AC EIZO HP with CORRECTION)<br>
- &nbsp;&nbsp;&nbsp; <b>L</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
- Wide Gamut IPS (WG CCFL NEC241 271)<br>
- &nbsp;&nbsp;&nbsp; <b>b&nbsp;</b>&nbsp;&nbsp;&nbsp;&nbsp; LCD RGB
- LED IPS (RGBLED HP SOYO)<br>
- &nbsp;&nbsp;&nbsp; <b>e</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD White
- LED IPS (WLED AC LG Samsung)<br>
- &nbsp;&nbsp;&nbsp; <b>p</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Projector
- (Marantz HP Panasonic Projectors Hybrid EDR)<br>
- <br>
- By default the integration time is adaptive, taking longer when the
- light level is low. This can be disabled and a fixed integration
- time used to gain maximum speed at the cost of greatly reduced low
- light accuracy, by using the -Y A flag.<br>
- <br>
- <b>Note when measuring CRT displays:<br>
- </b><br>
- The small magnet in the ambient light cover used to signal what
- position it is in, can interfere in the operation of the CRT
- display, particularly if the ambient cover is in it's natural
- position at 180 degrees away from the measuring lens. One way of
- minimizing this is to swing the cover down so that it touches the
- display adjacent to the lens, thereby moving the magnet away from
- the display surface. A more thorough but inconvenient way of
- avoiding this problem is to unclip the ambient light cover and slide
- it down the cable.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="Huey"></a>Huey colorimeter<br>
- <br>
- <img alt="" src="Huey.jpg" style="width: 128px; height: 202px;"><br>
- <br>
- Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Huey </span>and <b>Huey
- Pro</b> are discontinued instruments. They may still be available
- as old stock, or second hand. <br>
- <span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+ DreamColor</a> instruments are also reported to work. They will
+ appear as a be a the same as the i1Display Pro.<br>
+ <span style="font-weight: bold;">[Note</span> that if you have an
+ OEM version of this instrument, it's worth checking if they come
+ with any extra .edr files, that can then be translated for use with
+ ArgyllCMS using <a href="oeminst.html">oeminst</a>.]<br>
+ <br>
+ On MSWindows, if you have installed the Manufacturers applications,
+ you may have to shut the i1Profiler tray application down before
+ Argyll can open the instrument.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
+ &nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh period
+ is measured, and the integration time adjusted appropriately. [CB2]<br>
+ <br>
+ With the manufacturers .edr files &amp; reference Argyll .ccss files
+ installed, the following selections are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh
+ period is measured, and the integration time adjusted appropriately.
+ [CB2]<br>
+ &nbsp;&nbsp;&nbsp; <b>c</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRT
+ (Hitachi CM2112MET, Diamond View 1772ie)<br>
+ &nbsp;&nbsp;&nbsp; <b>l</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
+ IPS (CCFL AC EIZO HP with CORRECTION)<br>
+ &nbsp;&nbsp;&nbsp; <b>L</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
+ Wide Gamut IPS (WG CCFL NEC241 271)<br>
+ &nbsp;&nbsp;&nbsp; <b>b&nbsp;</b>&nbsp;&nbsp;&nbsp;&nbsp; LCD RGB
+ LED IPS (RGBLED HP SOYO)<br>
+ &nbsp;&nbsp;&nbsp; <b>e</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD White
+ LED IPS (WLED AC LG Samsung)<br>
+ &nbsp;&nbsp;&nbsp; <b>p</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Projector
+ (Marantz HP Panasonic Projectors Hybrid EDR)<br>
+ <br>
+ By default the integration time is adaptive, taking longer when the
+ light level is low. This can be disabled and a fixed integration
+ time used to gain maximum speed at the cost of greatly reduced low
+ light accuracy, by using the -Y A flag.<br>
+ <br>
+ <b>Note when measuring CRT displays:<br>
+ </b><br>
+ The small magnet in the ambient light cover used to signal what
+ position it is in, can interfere in the operation of the CRT
+ display, particularly if the ambient cover is in it's natural
+ position at 180 degrees away from the measuring lens. One way of
+ minimizing this is to swing the cover down so that it touches the
+ display adjacent to the lens, thereby moving the magnet away from
+ the display surface. A more thorough but inconvenient way of
+ avoiding this problem is to unclip the ambient light cover and slide
+ it down the cable.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="Huey"></a>Huey colorimeter<br>
+ <br>
+ <img alt="" src="Huey.jpg" style="width: 128px; height: 202px;"><br>
+ <br>
+ Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Huey </span>and <b>Huey
+ Pro</b> are discontinued instruments. They may still be available
+ as old stock, or second hand. <br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2549,9 +2549,9 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2599,34 +2599,34 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type. [CB2]<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="mox"></a>MonacoOPTIX
- colorimeters<br>
- <br>
- <img alt="" src="mox.jpg" style="width: 115px; height: 147px;">
- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img alt="" src="Chroma4.jpg"
- style="width: 135px; height: 146px;"><br>
- <br>
- Instrument Availability:<br>
- </span><br>
- <span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">MonacoOPTIX</span> from
- Monaco Soft is a discontinued instrument.&nbsp; It may still be
- available as old stock, or second hand. It was sold packaged with
- software from the manufacturer. The Sequel Chroma 4 appears to be a
- similar instrument, and both seem to operate as if they were an
- Eye-One Display 1 using Argyll.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="mox"></a>MonacoOPTIX
+ colorimeters<br>
+ <br>
+ <img alt="" src="mox.jpg" style="width: 115px; height: 147px;">
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img alt="" src="Chroma4.jpg"
+ style="width: 135px; height: 146px;"><br>
+ <br>
+ Instrument Availability:<br>
+ </span><br>
+ <span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">MonacoOPTIX</span> from
+ Monaco Soft is a discontinued instrument.&nbsp; It may still be
+ available as old stock, or second hand. It was sold packaged with
+ software from the manufacturer. The Sequel Chroma 4 appears to be a
+ similar instrument, and both seem to operate as if they were an
+ Eye-One Display 1 using Argyll.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2674,9 +2674,9 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type.<br>
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type.<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2724,42 +2724,42 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display, that is of the Non-Refresh type.<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd2"></a>Spyder 2
- colorimeter<br>
- <br>
- <img alt="" src="Spyd2.jpg" style="width: 218px; height: 232px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder 2 </span><span
- style="font-weight: bold;"></span>has been superseded by the
- Spyder 5, but may be available second hand.<br>
- [The Spyder 1 has also been reported as working, but this has not
- been confirmed.]<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- <span style="font-weight: bold;">Important Note </span>about the
- ColorVision Spyder 2 instrument support:<br>
- <br>
- This instrument cannot function without the driver software having
- access to the vendor supplied PLD firmware pattern for it.<br>
- This firmware is not provided with Argyll, since it is not available
- under a compatible license.<br>
- <br>
- The purchaser of a Spyder 2 instrument should have received a copy
- of this firmware along with their instrument, and should therefore
- be able to enable the Argyll driver for this instrument by using the
- <a href="oeminst.html">oeminst</a> tool.<span style="font-weight:
- bold;"></span><br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd2"></a>Spyder 2
+ colorimeter<br>
+ <br>
+ <img alt="" src="Spyd2.jpg" style="width: 218px; height: 232px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder 2 </span><span
+ style="font-weight: bold;"></span>has been superseded by the
+ Spyder 5, but may be available second hand.<br>
+ [The Spyder 1 has also been reported as working, but this has not
+ been confirmed.]<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ ColorVision Spyder 2 instrument support:<br>
+ <br>
+ This instrument cannot function without the driver software having
+ access to the vendor supplied PLD firmware pattern for it.<br>
+ This firmware is not provided with Argyll, since it is not available
+ under a compatible license.<br>
+ <br>
+ The purchaser of a Spyder 2 instrument should have received a copy
+ of this firmware along with their instrument, and should therefore
+ be able to enable the Argyll driver for this instrument by using the
+ <a href="oeminst.html">oeminst</a> tool.<span style="font-weight:
+ bold;"></span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -2807,9 +2807,9 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; A Liquid Crystal
- Display, that is of the Non-Refresh type. [Default, CB1]<br>
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; A Liquid Crystal
+ Display, that is of the Non-Refresh type. [Default, CB1]<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -2857,134 +2857,134 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display, that is of the Refresh type. [CB2]<br>
- <br>
- <br>
- <span style="font-weight: bold;">Linux USB hub problems:<br>
- <br>
- </span>Note that the Spyder doesn't appear to operate at all well on
- Linux if attached to a secondary USB hub. You may have such a
- secondary hub built into your motherboard. If Argyll has difficulty
- in reliably talking to the Spyder, try connecting it directly to the
- computer rather than via a usb hub, or try using a USB port on your
- computer that connects directly to a root hub. This is probably due
- to a bug in the Linux EHCI driver, and a fix is due to appear in the
- Linux kernel sometime after July 2011. The name of the fix is "EHCI:
- fix direction handling for interrupt data toggles".<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd3"></a>Spyder 3
- colorimeter<br>
- <br>
- <img style="width: 262px; height: 220px;" alt="Spyder3"
- src="Spyd3.jpg"> <img style="width: 193px; height: 220px;"
- alt="Spyder3Express" src="Spyd3x.jpg"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder3Elite</span>, <span
- style="font-weight: bold;">Spyder3Pro</span> and <span
- style="font-weight: bold;">Spyder3Express</span> have being
- superseded by the Spyder 5, but may still stocked by some dealers,
- and may be available second hand. The <span style="font-weight:
- bold;">Spyder3Elite</span> and <span style="font-weight: bold;">Spyder3Pro</span>
- appear to be identical hardware with different software from the
- manufacturer. The <span style="font-weight: bold;">Spyder3Express</span>
- lacks the ambient sensor.<br>
- <br>
- [Note that this instrument doesn't seem particularly suited to
- measuring CRT displays, since it no longer seems to synchronise its
- readings to a CRT refresh, and you can no longer remove the LCD
- filter, reducing its sensitivity compared to the Spyder 2 in CRT
- mode. The Spyder 2 or one of the other instruments may be a better
- choice if you particularly need to measure CRTs or Refresh
- displays.]<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- The ambient light sensor can be used with the <span
- style="font-weight: bold;">Spyder3Elite</span> and <span
- style="font-weight: bold;">Spyder3Pro</span> instruments, but is
- only capable of monochrome readings.<span style="font-weight: bold;"><br>
- </span><br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
- style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp; A
- non-refresh type display [Default, CB1]<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span>
- &nbsp;&nbsp;&nbsp; A refresh type display. [CB2]<br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd4"></a>Spyder 4
- colorimeter<br>
- <br>
- <img style=" width: 262px; height: 220px;" alt="Spyder4"
- src="Spyd4.jpg"> <br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder4Elite</span>, <span
- style="font-weight: bold;">Spyder4Pro</span> and <span
- style="font-weight: bold;">Spyder4Express</span> have being
- superseded by the Spyder 5, but may still stocked by some dealers,
- and may be available second hand.&nbsp; The <span
- style="font-weight: bold;">Spyder4Elite</span> and <span
- style="font-weight: bold;">Spyder4Pro</span> appear to be
- identical hardware with different software from the manufacturer.
- The <span style="font-weight: bold;">Spyder4Express</span> lacks
- the ambient sensor.<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- These instruments are capable of using using CCSS (<a
- href="File_Formats.html#ccss">Colorimeter Calibration Spectral
- Sample</a>) files, and this also gives the instrument the
- capability of using a non-default standard observer. CCSS files can
- be created using the <a href="ccxxmake.html">ccxxmake</a> tool
- using a spectrometer as a reference.<br>
- <br>
- <span style="font-weight: bold;">Important Note </span>about the
- DataColor Spyder 4 vendor display type/calibration support:<br>
- <br>
- This instrument does not have a full range of display type
- calibration selections available without the vendor supplied
- calibration data for it.<br>
- This calibration data is not provided with Argyll, since it is not
- available under a compatible license.<br>
- You can use CCSS files as an alternative (see above), or as the
- purchaser of a Spyder 4 instrument you should have received a copy
- of the calibration data along with the instrument, and should
- therefore be able to enable the full range of display type
- selections in Argyll by using the <a href="oeminst.html">oeminst</a>
- tool.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
- style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp; A non-refresh type display with a generic calibration
- [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
- refresh type display with a generic calibration.[CB2]<br>
- <br>
- The Display Selections for this instrument when the manufacturers
- calibration information has been installed is:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
- calibration [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
- calibration.[CB2]<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;">Linux USB hub problems:<br>
+ <br>
+ </span>Note that the Spyder doesn't appear to operate at all well on
+ Linux if attached to a secondary USB hub. You may have such a
+ secondary hub built into your motherboard. If Argyll has difficulty
+ in reliably talking to the Spyder, try connecting it directly to the
+ computer rather than via a usb hub, or try using a USB port on your
+ computer that connects directly to a root hub. This is probably due
+ to a bug in the Linux EHCI driver, and a fix is due to appear in the
+ Linux kernel sometime after July 2011. The name of the fix is "EHCI:
+ fix direction handling for interrupt data toggles".<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd3"></a>Spyder 3
+ colorimeter<br>
+ <br>
+ <img style="width: 262px; height: 220px;" alt="Spyder3"
+ src="Spyd3.jpg"> <img style="width: 193px; height: 220px;"
+ alt="Spyder3Express" src="Spyd3x.jpg"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder3Elite</span>, <span
+ style="font-weight: bold;">Spyder3Pro</span> and <span
+ style="font-weight: bold;">Spyder3Express</span> have being
+ superseded by the Spyder 5, but may still stocked by some dealers,
+ and may be available second hand. The <span style="font-weight:
+ bold;">Spyder3Elite</span> and <span style="font-weight: bold;">Spyder3Pro</span>
+ appear to be identical hardware with different software from the
+ manufacturer. The <span style="font-weight: bold;">Spyder3Express</span>
+ lacks the ambient sensor.<br>
+ <br>
+ [Note that this instrument doesn't seem particularly suited to
+ measuring CRT displays, since it no longer seems to synchronise its
+ readings to a CRT refresh, and you can no longer remove the LCD
+ filter, reducing its sensitivity compared to the Spyder 2 in CRT
+ mode. The Spyder 2 or one of the other instruments may be a better
+ choice if you particularly need to measure CRTs or Refresh
+ displays.]<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder3Elite</span> and <span
+ style="font-weight: bold;">Spyder3Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"><br>
+ </span><br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span>
+ &nbsp;&nbsp;&nbsp; A refresh type display. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd4"></a>Spyder 4
+ colorimeter<br>
+ <br>
+ <img style=" width: 262px; height: 220px;" alt="Spyder4"
+ src="Spyd4.jpg"> <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder4Elite</span>, <span
+ style="font-weight: bold;">Spyder4Pro</span> and <span
+ style="font-weight: bold;">Spyder4Express</span> have being
+ superseded by the Spyder 5, but may still stocked by some dealers,
+ and may be available second hand.&nbsp; The <span
+ style="font-weight: bold;">Spyder4Elite</span> and <span
+ style="font-weight: bold;">Spyder4Pro</span> appear to be
+ identical hardware with different software from the manufacturer.
+ The <span style="font-weight: bold;">Spyder4Express</span> lacks
+ the ambient sensor.<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ These instruments are capable of using using CCSS (<a
+ href="File_Formats.html#ccss">Colorimeter Calibration Spectral
+ Sample</a>) files, and this also gives the instrument the
+ capability of using a non-default standard observer. CCSS files can
+ be created using the <a href="ccxxmake.html">ccxxmake</a> tool
+ using a spectrometer as a reference.<br>
+ <br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ DataColor Spyder 4 vendor display type/calibration support:<br>
+ <br>
+ This instrument does not have a full range of display type
+ calibration selections available without the vendor supplied
+ calibration data for it.<br>
+ This calibration data is not provided with Argyll, since it is not
+ available under a compatible license.<br>
+ You can use CCSS files as an alternative (see above), or as the
+ purchaser of a Spyder 4 instrument you should have received a copy
+ of the calibration data along with the instrument, and should
+ therefore be able to enable the full range of display type
+ selections in Argyll by using the <a href="oeminst.html">oeminst</a>
+ tool.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; A non-refresh type display with a generic calibration
+ [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
+ refresh type display with a generic calibration.[CB2]<br>
+ <br>
+ The Display Selections for this instrument when the manufacturers
+ calibration information has been installed is:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
+ calibration [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
+ calibration.[CB2]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3032,18 +3032,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- - normal gamut Liquid Crystal Display with standard Cold Cathode
- Fluorescent Lamp backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
- Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
- Display with Cold Cathode Fluorescent Lamps backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
- LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
- gamut Liquid Crystal Display with a White LED backlight.<br>
+
+ - normal gamut Liquid Crystal Display with standard Cold Cathode
+ Fluorescent Lamp backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
+ Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
+ Display with Cold Cathode Fluorescent Lamps backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
+ LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
+ gamut Liquid Crystal Display with a White LED backlight.<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">B</span>&nbsp;&nbsp;
@@ -3091,13 +3091,13 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
- Backlight - wide gamut Liquid Crystal Display with RGB LED
- backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
- Type 2
+
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
+ Backlight - wide gamut Liquid Crystal Display with RGB LED
+ backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+ Type 2
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3145,90 +3145,90 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- - normal gamut Liquid Crystal Display with alternative Cold Cathode
- Fluorescent Lamp backlight (Laptop ?)<br>
- <br>
- The ambient light sensor can be used with the <span
- style="font-weight: bold;">Spyder4Elite</span> and <span
- style="font-weight: bold;">Spyder4Pro</span> instruments, but is
- only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
- <br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
- <span style="font-weight: bold;"><a name="spyd5"></a>Spyder 5
- colorimeter<br>
- <br>
- <img style="width: 262px; height: 220px;" alt="Spyder4"
- src="Spyd5.jpg" width="449" height="350"> <br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;">Spyder5Elite</span>, <span
- style="font-weight: bold;">Spyder5Pro</span> and <span
- style="font-weight: bold;">Spyder5Express</span> are a currently
- available instruments. The <span style="font-weight: bold;">Spyder5Elite</span>
- and <span style="font-weight: bold;">Spyder5Pro</span> appear to be
- identical hardware with different software from the manufacturer.
- The <span style="font-weight: bold;">Spyder5Express</span> lacks
- the ambient sensor.<br>
- <span style="font-weight: bold;"><br>
- </span><span style="font-weight: bold;">Operation:<br>
- </span><br>
- These instruments are capable of using using CCSS (<a
- href="File_Formats.html#ccss">Colorimeter
+
+ - normal gamut Liquid Crystal Display with alternative Cold Cathode
+ Fluorescent Lamp backlight (Laptop ?)<br>
+ <br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder4Elite</span> and <span
+ style="font-weight: bold;">Spyder4Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd5"></a>Spyder 5
+ colorimeter<br>
+ <br>
+ <img style="width: 262px; height: 220px;" alt="Spyder4"
+ src="Spyd5.jpg" width="449" height="350"> <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder5Elite</span>, <span
+ style="font-weight: bold;">Spyder5Pro</span> and <span
+ style="font-weight: bold;">Spyder5Express</span> are a currently
+ available instruments. The <span style="font-weight: bold;">Spyder5Elite</span>
+ and <span style="font-weight: bold;">Spyder5Pro</span> appear to be
+ identical hardware with different software from the manufacturer.
+ The <span style="font-weight: bold;">Spyder5Express</span> lacks
+ the ambient sensor.<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ These instruments are capable of using using CCSS (<a
+ href="file:///D:/src/argyll/doc/File_Formats.html#ccss">Colorimeter
-
- Calibration Spectral Sample</a>) files, and this also gives the
- instrument the capability of using a non-default standard observer.
- CCSS files can be created using the <a
- href="ccxxmake.html">ccxxmake</a> tool
- using a spectrometer as a reference.<br>
- <br>
- <span style="font-weight: bold;">Important Note </span>about the
- DataColor Spyder 5 vendor display type/calibration support:<br>
- <br>
- This instrument does not have a full range of display type
- calibration selections available without the vendor supplied
- calibration data for it.<br>
- This calibration data is not provided with Argyll, since it is not
- available under a compatible license.<br>
- You can use CCSS files as an alternative (see above), or as the
- purchaser of a Spyder 5 instrument you should have received a copy
- of the calibration data along with the instrument or have been
- directed to download it from the manufacturers website, and should
- therefore be able to enable the full range of display type
- selections in Argyll by using the <a
- href="oeminst.html">oeminst</a> tool.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
- style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp; A non-refresh type display with a generic calibration
- [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
- refresh type display with a generic calibration.[CB2]<br>
- <br>
- The Display Selections for this instrument when the manufacturers
- calibration information has been installed is:<br>
- <br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
- style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
- calibration [Default, CB1].<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
- style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
- calibration.[CB2]<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+
+ Calibration Spectral Sample</a>) files, and this also gives the
+ instrument the capability of using a non-default standard observer.
+ CCSS files can be created using the <a
+ href="file:///D:/src/argyll/doc/ccxxmake.html">ccxxmake</a> tool
+ using a spectrometer as a reference.<br>
+ <br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ DataColor Spyder 5 vendor display type/calibration support:<br>
+ <br>
+ This instrument does not have a full range of display type
+ calibration selections available without the vendor supplied
+ calibration data for it.<br>
+ This calibration data is not provided with Argyll, since it is not
+ available under a compatible license.<br>
+ You can use CCSS files as an alternative (see above), or as the
+ purchaser of a Spyder 5 instrument you should have received a copy
+ of the calibration data along with the instrument or have been
+ directed to download it from the manufacturers website, and should
+ therefore be able to enable the full range of display type
+ selections in Argyll by using the <a
+ href="file:///D:/src/argyll/doc/oeminst.html">oeminst</a> tool.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; A non-refresh type display with a generic calibration
+ [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
+ refresh type display with a generic calibration.[CB2]<br>
+ <br>
+ The Display Selections for this instrument when the manufacturers
+ calibration information has been installed is:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
+ calibration [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
+ calibration.[CB2]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3276,18 +3276,18 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- - normal gamut Liquid Crystal Display with standard Cold Cathode
- Fluorescent Lamp backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
- Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
- Display with Cold Cathode Fluorescent Lamps backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
- LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
- gamut Liquid Crystal Display with a White LED backlight.<br>
+
+ - normal gamut Liquid Crystal Display with standard Cold Cathode
+ Fluorescent Lamp backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
+ Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
+ Display with Cold Cathode Fluorescent Lamps backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
+ LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
+ gamut Liquid Crystal Display with a White LED backlight.<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">B</span>&nbsp;&nbsp;
@@ -3335,13 +3335,13 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
- Backlight - wide gamut Liquid Crystal Display with RGB LED
- backlight.<br>
- &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
- &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
- Type 2
+
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
+ Backlight - wide gamut Liquid Crystal Display with RGB LED
+ backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+ Type 2
Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3389,23 +3389,23 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- - normal gamut Liquid Crystal Display with alternative Cold Cathode
- Fluorescent Lamp backlight (Laptop ?)<br>
- <br>
- The ambient light sensor can be used with the <span
- style="font-weight: bold;">Spyder5Elite</span> and <span
- style="font-weight: bold;">Spyder5Pro</span> instruments, but is
- only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
- <span style="font-weight: bold;"></span><br>
- <hr style="width: 100%; height: 2px;"><a name="HCFR"></a><span
- style="font-weight: bold;" class="titre">Colorimètre HCFR
- colorimeter<br>
- <br>
- <img alt="" src="HCFR.jpg" style="width: 203px; height: 194px;"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
+
+ - normal gamut Liquid Crystal Display with alternative Cold Cathode
+ Fluorescent Lamp backlight (Laptop ?)<br>
+ <br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder5Elite</span> and <span
+ style="font-weight: bold;">Spyder5Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"></span><br>
+ <hr style="width: 100%; height: 2px;"><a name="HCFR"></a><span
+ style="font-weight: bold;" class="titre">Colorimètre HCFR
+ colorimeter<br>
+ <br>
+ <img alt="" src="HCFR.jpg" style="width: 203px; height: 194px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
</span>The <span style="font-weight: bold;" class="titre">Colorimètre
@@ -3453,27 +3453,27 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- HCFR Probe</span> is a kit instrument from <span
- style="font-weight: bold;"></span> <a
- href="http://www.homecinema-fr.com/colorimetre/index_en.php">HCFR</a>.
- <br>
- <br>
- <span style="font-weight: bold;">OS X</span><br>
- <br>
- Please note the installation <a href="Installing_OSX.html#HCFR">instructions</a>.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
- The accuracy of this instrument does not seem to be comparable to
- the commercial instruments when used for measuring displays,
- particularly in the area of measuring dark colors, and I've seen the
- best results when used with a CRT display. It may well give good
- results in calibrating projectors, since this was what it was
- designed to do.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+ HCFR Probe</span> is a kit instrument from <span
+ style="font-weight: bold;"></span> <a
+ href="http://www.homecinema-fr.com/colorimetre/index_en.php">HCFR</a>.
+ <br>
+ <br>
+ <span style="font-weight: bold;">OS X</span><br>
+ <br>
+ Please note the installation <a href="Installing_OSX.html#HCFR">instructions</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
+ The accuracy of this instrument does not seem to be comparable to
+ the commercial instruments when used for measuring displays,
+ particularly in the area of measuring dark colors, and I've seen the
+ best results when used with a CRT display. It may well give good
+ results in calibrating projectors, since this was what it was
+ designed to do.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3521,9 +3521,9 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
- Crystal Display [Default].<br>
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display [Default].<br>
&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
@@ -3571,39 +3571,39 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
- Tube display.<br>
- &nbsp;&nbsp;&nbsp; <b>R</b> &nbsp; Raw&nbsp;
- Reading&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Raw sensor readings,
- used for calibration [CB1]<br>
- <br>
- <hr style="width: 100%; height: 2px;"><a name="ColorHug"></a><span
- style="font-weight: bold;" class="titre">ColorHug<br>
- <br>
- <img alt="" src="ColorHug.jpg" style="width: 203px; height:
- 194px;" width="552" height="623"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The <span style="font-weight: bold;" class="titre">ColorHug</span>
- is a low cost display colorimeter instrument from <span
- style="font-weight: bold;"></span> <a
- href="http://www.hughski.com/">Hughski</a>. <br>
- ArgyllCMS will also work with the <a
- href="http://www.hughski.com/colorhug2.html">ColorHug2</a>.<br>
- <br>
- <span style="font-weight: bold;">Operation:</span><br>
- <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
- Due to the nature of its sensor, the ColorHug accuracy is quite
- dependent on the instrument calibration matrix. (The <b>ColorHug2</b>
- is much more forgiving though). A custom .CCMX will greatly assist
- it's accuracy, although a workaround is to calibrate your display
- using its native white point, rather than aiming for some absolute
- white point such as D65.<br>
- <br>
- The Display Selections for this instrument are:<br>
- <br>
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display.<br>
+ &nbsp;&nbsp;&nbsp; <b>R</b> &nbsp; Raw&nbsp;
+ Reading&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Raw sensor readings,
+ used for calibration [CB1]<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="ColorHug"></a><span
+ style="font-weight: bold;" class="titre">ColorHug<br>
+ <br>
+ <img alt="" src="ColorHug.jpg" style="width: 203px; height:
+ 194px;" width="552" height="623"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;" class="titre">ColorHug</span>
+ is a low cost display colorimeter instrument from <span
+ style="font-weight: bold;"></span> <a
+ href="http://www.hughski.com/">Hughski</a>. <br>
+ ArgyllCMS will also work with the <a
+ href="http://www.hughski.com/colorhug2.html">ColorHug2</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
+ Due to the nature of its sensor, the ColorHug accuracy is quite
+ dependent on the instrument calibration matrix. (The <b>ColorHug2</b>
+ is much more forgiving though). A custom .CCMX will greatly assist
+ it's accuracy, although a workaround is to calibrate your display
+ using its native white point, rather than aiming for some absolute
+ white point such as D65.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
&nbsp;&nbsp; <b>l</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3621,8 +3621,8 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- LCD, CCFL Backlight [Default]<br>
+
+ LCD, CCFL Backlight [Default]<br>
&nbsp;&nbsp; <b>c</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3641,8 +3641,8 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- CRT display<br>
+
+ CRT display<br>
&nbsp;&nbsp; <b>p</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3661,8 +3661,8 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- Projector<br>
+
+ Projector<br>
&nbsp;&nbsp; <b>e</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3680,8 +3680,8 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- LCD, White LED Backlight<br>
+
+ LCD, White LED Backlight<br>
&nbsp;&nbsp; <b>F</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3700,8 +3700,8 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- Factory matrix (For Calibration) [CB1]<br>
+
+ Factory matrix (For Calibration) [CB1]<br>
&nbsp;&nbsp;<b> R</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3720,40 +3720,40 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- Raw Reading (For Factory matrix Calibration) [CB2]<br>
- <br>
- <hr style="width: 100%; height: 2px;"><br>
+
+ Raw Reading (For Factory matrix Calibration) [CB2]<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
<a name="SMCube"></a><span style="font-weight: bold;">Palette/SwatchMate
-
- Cube<br>
- <br>
- <img alt="SwatchMate Cube" src="SMCube.jpg" width="169"
- height="205"><br>
- <br>
- </span><span style="font-weight: bold;">Availability:<br>
- <br>
- </span>The Cube from <a href="http://palette.com/cube.html">Palette/SwatchMate</a>
- is a currently available entry level Colorimeter, with <a
- href="http://www.argyllcms.com/doc2/smcube/smcube1.html">somewhat
- limited accuracy</a>. The ArgyllCMS driver provides two
- alternative calibrations that noticably <a
- href="http://www.argyllcms.com/doc2/smcube/smcube2.html">improve
- this accuracy</a>.<br>
- <br>
- The Calibration Selections for this instrument are:<br>
- <br>
- &nbsp;&nbsp; <b>m</b>
+
+ Cube<br>
+ <br>
+ <img alt="SwatchMate Cube" src="SMCube.jpg" width="169"
+ height="205"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The Cube from <a href="http://palette.com/cube.html">Palette/SwatchMate</a>
+ is a currently available entry level Colorimeter, with <a
+ href="http://www.argyllcms.com/doc2/smcube/smcube1.html">somewhat
+ limited accuracy</a>. The ArgyllCMS driver provides two
+ alternative calibrations that noticably <a
+ href="http://www.argyllcms.com/doc2/smcube/smcube2.html">improve
+ this accuracy</a>.<br>
+ <br>
+ The Calibration Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp; <b>m</b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- Matt surfaces [Default]<br>
+
+ Matt surfaces [Default]<br>
&nbsp;&nbsp; <b>g</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -3772,64 +3772,64 @@ href="http://www8.hp.com/us/en/products/oas/product-detail.html?oid=5225568">HP
-
- Gloss surfaces<br>
- &nbsp;&nbsp; <b>N</b>
+
+ Gloss surfaces<br>
+ &nbsp;&nbsp; <b>N</b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
- Native Calibration<br>
- <br>
- <span style="font-weight: bold;">Operation:<br>
- </span><br>
- The Cube must be connected via USB for operation with ArgyllCMS, and
- can be connected either by USB or using Bluetooth LE when used with
- <a href="http://www.argyllpro.com.au/">ArgyllPRO ColorMeter</a> on
- capable Android devices.<br>
- <br>
- The Cube goes to sleep fairly rapidly and must be woken up by
- pressing the top of it before connecting via USB to be recognized by
- ArgyllCMS, although once connected, and with an ArgyllCMS utility
- running, it should stay awake.<br>
- <br>
- When connecting via Bluetooth to ColorMeter, the foreground
- application will be the one that connects to it.<br>
- <br>
- The ability to measure values into its own memory and recover them
- later is not supported, since it is not possible to use the
- ArgyllCMS calibrations with this feature.<br>
- <br>
- <span style="font-weight: bold;">Calibration:</span><br>
- <br>
- As well as the normal white calibration step, the ArgyllCMS driver
- offers two option supplemental calibration steps that can improve
- accuracy, but both require appropriate calibration conditions. You
- can use <a href="spotread.html">spotread</a> with the 'k' command
- to trigger this calibration.<br>
- <br>
- The <b>black calibration</b> requires a light trap, and the easiest
- way of providing this is to place the Cube in a location that is
- dark (i.e. not illuminated directly by any light) and some distance
- from any surface. A practical approach I have used is to place the
- measuring end in a thick black sock, and hide it from direct
- illumination while this calibration step is done.<br>
- <br>
- The <b>gloss calibration</b> requires a black glossy surface. I
- have used a paint catalog gloss paint black sample square for this,
- but some other completely black glossy surface of sufficient size
- such as a glossy black plastic item or a smooth surface painted in
- gloss black paint should also work.<br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- <br>
- </body>
-</html>
+
+ Native Calibration<br>
+ <br>
+ <span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ The Cube must be connected via USB for operation with ArgyllCMS, and
+ can be connected either by USB or using Bluetooth LE when used with
+ <a href="http://www.argyllpro.com.au/">ArgyllPRO ColorMeter</a> on
+ capable Android devices.<br>
+ <br>
+ The Cube goes to sleep fairly rapidly and must be woken up by
+ pressing the top of it before connecting via USB to be recognized by
+ ArgyllCMS, although once connected, and with an ArgyllCMS utility
+ running, it should stay awake.<br>
+ <br>
+ When connecting via Bluetooth to ColorMeter, the foreground
+ application will be the one that connects to it.<br>
+ <br>
+ The ability to measure values into its own memory and recover them
+ later is not supported, since it is not possible to use the
+ ArgyllCMS calibrations with this feature.<br>
+ <br>
+ <span style="font-weight: bold;">Calibration:</span><br>
+ <br>
+ As well as the normal white calibration step, the ArgyllCMS driver
+ offers two option supplemental calibration steps that can improve
+ accuracy, but both require appropriate calibration conditions. You
+ can use <a href="spotread.html">spotread</a> with the 'k' command
+ to trigger this calibration.<br>
+ <br>
+ The <b>black calibration</b> requires a light trap, and the easiest
+ way of providing this is to place the Cube in a location that is
+ dark (i.e. not illuminated directly by any light) and some distance
+ from any surface. A practical approach I have used is to place the
+ measuring end in a thick black sock, and hide it from direct
+ illumination while this calibration step is done.<br>
+ <br>
+ The <b>gloss calibration</b> requires a black glossy surface. I
+ have used a paint catalog gloss paint black sample square for this,
+ but some other completely black glossy surface of sufficient size
+ such as a glossy black plastic item or a smooth surface painted in
+ gloss black paint should also work.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/targen.html b/doc/targen.html
index 81b331b..3aa1bb4 100644
--- a/doc/targen.html
+++ b/doc/targen.html
@@ -1323,12 +1323,12 @@ device
accuracy of measuring and modelling the lighter regions, given a
fixed number of test points and profile quality/grid resolution. The
parameter will also be used in an analogous way to the <small><a
- href="targen.html#p">-p power</a>
+ href="file:///D:/src/argyll/doc/targen.html#p">-p power</a>
value in changing the distribution of </small><small><a
- href="targen.html#s">-s steps</a>, </small><small><a
- href="targen.html#g">-g steps</a>, </small><small><a
- href="targen.html#m">-m steps</a></small>
- and <small><small><a href="targen.html#b">-b
+ href="file:///D:/src/argyll/doc/targen.html#s">-s steps</a>, </small><small><a
+ href="file:///D:/src/argyll/doc/targen.html#g">-g steps</a>, </small><small><a
+ href="file:///D:/src/argyll/doc/targen.html#m">-m steps</a></small>
+ and <small><small><a href="file:///D:/src/argyll/doc/targen.html#b">-b
diff --git a/doc/tiffgamut.html b/doc/tiffgamut.html
index 9534717..6aea52d 100644
--- a/doc/tiffgamut.html
+++ b/doc/tiffgamut.html
@@ -19,9 +19,7 @@
This can be used for visualizing and comparing the gamut of an image
to the colorspace it is in, or a colorspace it might get transformed
into, and can also be used to create an image source gamut for use
- with <a href="collink.html"> collink</a>, something that can be of
- particular importance if your images are encoded in a large gamut
- space such as L*a*b*, ProPhoto, scRGB etc.<br>
+ with <a href="collink.html"> collink</a>.<br>
<br>
<span style="font-weight: bold;">NOTE</span> that if you are
creating an image gamut suitable for use with the <a
@@ -35,7 +33,7 @@
href="Scenarios.html#LP3">Image dependent gamut mapping using
device links</a> for an example workflow.<br>
<br>
- See <a href="3dformat.html">3D Viewing
+ See <a href="file:///D:/src/argyll/doc/3Df.htmlormat">3D Viewing
Format</a> for switching to VRML or X3D output format.<br>
<h3>Usage Summary</h3>
<small><span style="font-family: monospace;">tiffgamut [-v level]
@@ -46,7 +44,6 @@
-
Verbose</span><br style="font-family: monospace;">
&nbsp; <span style="font-family: monospace;">-d
sres&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Surface resolution
@@ -57,7 +54,6 @@ emit
-
X3DOM .x3d.html file as well as CGATS .gam file</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -66,7 +62,6 @@ Don't
-
add X3DOM axes or white/black point</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;-k&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -75,7 +70,6 @@ Add
-
markers for prim. &amp; sec. "cusp" points<br>
&nbsp;-f perc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Filter by
popularity, perc = percent to use<br style="font-family:
@@ -89,7 +83,6 @@ s
-
= saturation, a = absolute (default), d = profile default</span></small><small><span
style="font-family: monospace;"></span></small><br
style="font-family: monospace;">
@@ -104,7 +97,6 @@ r
-
= reverse (priority: monochrome &gt; matrix &gt; lut)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;</span><span
style="font-family: monospace;">-p oride</span><span
@@ -123,7 +115,6 @@ either
-
an enumerated choice, or a parameter:value change</span><span
style="font-family: monospace;"></span><br style="font-family:
monospace;">
@@ -137,7 +128,6 @@ either
-
pe - Print evaluation environment (CIE 116-1995)<br>
</span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;
@@ -145,7 +135,6 @@ either
-
pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
style="font-family: monospace;"></span><span style="font-family:
monospace;"></span><br style="font-family: monospace;">
@@ -158,7 +147,6 @@ either
-
&nbsp; mb - Monitor in bright work environment</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
@@ -185,7 +173,6 @@ s:surround&nbsp;&nbsp;
-
n = auto, a = average, m = dim, d = dark,</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -194,7 +181,6 @@ s:surround&nbsp;&nbsp;
-
&nbsp; &nbsp;&nbsp; c = transparency (default average)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -203,7 +189,6 @@ w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
Adapted white point as XYZ (default media white)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -212,7 +197,6 @@ w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
Adapted white point as x, y</span><br style="font-family:
monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -221,7 +205,6 @@ a:adaptation
-
Adaptation luminance in cd.m^2 (default 50.0)</span><br
style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -230,7 +213,6 @@ b:background
-
Background % of image luminance (default 20)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; l:imagewhite Image
white in cd.m^2 if surround = auto (default 250)</span></small><br
@@ -242,12 +224,11 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
Flare light % of image luminance (default 1)<br>
</span></small>&nbsp;</span><span style="font-family:
monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
g:glare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare light % of ambient
- (default 5)</span><br style="font-family: monospace;">
+ (default 1)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; g:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare color
as XYZ (default media white)</span><br style="font-family:
@@ -256,7 +237,6 @@ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-
g:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare color as
x, y<br>
&nbsp;-O outputfile Override the default output filename &amp;
diff --git a/doc/viewgam.html b/doc/viewgam.html
index fb29e7d..9c3e3f0 100644
--- a/doc/viewgam.html
+++ b/doc/viewgam.html
@@ -16,7 +16,7 @@
This is useful in measuring and visualizing the coverage of one
gamut of another.<br>
<br>
- See <a href="3dformat.html">3D Viewing Format</a> for switching to
+ See <a href="3Df.htmlormat">3D Viewing Format</a> for switching to
VRML or X3D output format.<br>
<h3>Usage<br>
</h3>
diff --git a/doc/xicclu.html b/doc/xicclu.html
index 831977d..cf572fe 100644
--- a/doc/xicclu.html
+++ b/doc/xicclu.html
@@ -435,7 +435,7 @@ light
g:glare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare light % of ambient
- (default 2)</span><br style="font-family: monospace;">
+ (default 1)</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
&nbsp; &nbsp; g:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Glare color
as XYZ (default media white, Abs: D50)</span><br
diff --git a/gamut/gammap.c b/gamut/gammap.c
index e276b99..638a2cd 100644
--- a/gamut/gammap.c
+++ b/gamut/gammap.c
@@ -65,9 +65,13 @@
#undef PLOT_LMAP /* [Und] Plot L map */
#undef PLOT_GAMUTS /* [Und] Save (part mapped) input and output gamuts as */
/* src.wrl, img.wrl, dst.wrl, gmsrc.wrl */
-#undef PLOT_3DKNEES /* [Und] Plot each 3D compression knee */
+#undef PLOT_3DKNEES /* [Und] Plot the 3D compression knees */
#undef CHECK_NEARMAP /* [Und] Check how accurately near map vectors are represented by rspl */
-#undef DUMP_GREY_AXIS_POINTS /* [Und] Dump grey axis map 3d->3d points */
+
+#define USE_GLUMKNF /* [Define] Enable luminence knee function points */
+#define USE_GREYMAP /* [Define] Enable 3D->3D mapping points down the grey axis */
+#define USE_GAMKNF /* [Define] Enable 3D knee function points */
+#define USE_BOUND /* [Define] Enable grid boundary anchor points */
#undef SHOW_NEIGBORS /* [Und] Show nearsmth neigbors in gammap.wrl */
@@ -76,13 +80,6 @@
#define XRES 100 /* [100] Res of plots */
- /* Functionality */
-#define USE_GLUMKNF /* [Define] Enable luminence knee function points else linear */
-#define USE_GREYMAP /* [Define] Enable 3D->3D mapping points down the grey axis */
-#define USE_GAMKNF /* [Define] Enable 3D knee function points */
-#define USE_BOUND /* [Define] Enable grid boundary anchor points */
-
-
/* The locus.ts file can contain source locus(es) that will be plotted */
/* as cones in red, with the destination plotted in white. They can */
/* be created from .tif files using xicc/tiffgmts utility. */
@@ -151,6 +148,7 @@ struct {
#include <fcntl.h>
#include <string.h>
#include <math.h>
+#include "counters.h"
#include "icc.h"
#include "numlib.h"
#include "xicc.h"
@@ -170,17 +168,11 @@ typedef struct {
double satenh; /* Saturation engancement value */
} adjustsat;
-/* Callback context for fixing 1D Lut white and black points */
-typedef struct {
- double twb[2], awb[2]; /* Target and Actual black, white */
-} adjust1wb;
-
/* Callback context for making clut relative to white and black points */
typedef struct {
double mat[3][4];
} adjustwb;
-static void adjust1_wb_func(void *pp, double *out, double *in);
static void inv_grey_func(void *pp, double *out, double *in);
static void adjust_wb_func(void *pp, double *out, double *in);
static void adjust_sat_func(void *pp, double *out, double *in);
@@ -200,7 +192,7 @@ gammapweights pweights[] = {
{
0.1, /* Cusp luminance alignment weighting 0 = none, 1 = full */
0.0, /* Cusp chroma alignment weighting 0 = none, 1 = full */
- 0.2 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ 0.3 /* Cusp hue alignment weighting 0 = none, 1 = full */
},
2.0, /* Alignment twist power, 0 = linear, 1 = curve, 2+ late curve */
1.00 /* Chroma expansion 1 = none */
@@ -214,9 +206,9 @@ gammapweights pweights[] = {
1.0, /* Absolute error overall weight */
0.8, /* Hue dominance vs l+c, 0 - 1 */
- 0.8, /* [0.8] White l dominance vs, c, 0 - 1 */
- 0.45, /* [0.45] Grey l dominance vs, c, 0 - 1 */
- 0.94, /* [0.94] Black l dominance vs, c, 0 - 1 */
+ 0.8, /* White l dominance vs, c, 0 - 1 */
+ 0.5, /* Grey l dominance vs, c, 0 - 1 */
+ 0.97, /* Black l dominance vs, c, 0 - 1 */
0.4, /* White l blend start radius, 0 - 1, at white = 0 */
0.7, /* Black l blend power, linear = 1.0, enhance < 1.0 */
@@ -225,15 +217,14 @@ gammapweights pweights[] = {
10.0 /* L error extra xover threshold in DE */
},
{ /* Relative vector smoothing */
- 20.0, 30.0, /* Relative Smoothing radius L* H* */
- 0.9 /* Degree of smoothing */
+ 25.0, 35.0 /* Relative Smoothing radius L* H* */
},
{ /* Weighting of excessive compression error, which is */
/* the src->dst vector length over the available dst depth. */
/* The depth is half the distance to the intersection of the */
/* vector to the other side of the gamut. (doesn't get triggered much ?) */
- 5.0, /* [5] Compression depth weight */
- 5.0 /* [5] Expansion depth weight */
+ 10.0, /* Compression depth weight */
+ 10.0 /* Expansion depth weight */
},
{
0.0 /* Fine tuning expansion weight, 0 - 1 */
@@ -270,8 +261,7 @@ gammapweights pweights[] = {
-1.0 /* L error xover threshold in DE */
},
{ /* Relative error preservation using smoothing */
- 20.0, 10.0, /* Relative Smoothing radius L* H* */
- 0.5 /* Degree of smoothing */
+ 20.0, 10.0 /* Relative Smoothing radius L* H* */
},
{ /* Weighting of excessive compression error, which is */
/* the src->dst vector length over the available dst depth. */
@@ -303,7 +293,7 @@ gammapweights pweights[] = {
},
{ /* Weighting of absolute error of destination from source */
-1.0, /* Absolute error overall weight */
- -1.0, /* Hue dominance vs l+c, 0 - 1 */
+ 0.8, /* Hue dominance vs l+c, 0 - 1 */
-1.0, /* White l dominance vs, c, 0 - 1 */
-1.0, /* Grey l dominance vs, c, 0 - 1 */
@@ -316,8 +306,7 @@ gammapweights pweights[] = {
-1.0 /* L error xover threshold in DE */
},
{ /* Relative error preservation using smoothing */
- -1.0, 15.0, /* Relative Smoothing radius L* H* */
- -1.0 /* Degree of smoothing */
+ -1.0, 15.0 /* Relative Smoothing radius L* H* */
},
{ /* Weighting of excessive compression error, which is */
/* the src->dst vector length over the available dst depth. */
@@ -335,61 +324,7 @@ gammapweights pweights[] = {
gmm_end,
}
};
-double psmooth = 2.0; /* [2.0] Level of RSPL smoothing for perceptual, 1 = nominal */
-
-/* Lightness Preserving Perceptual mapping weights, where preserving lightness */
-/* and hue has the highest priority, followed by smoothness and proportionality. */
-/* Chroma is basically sacrificed. */
-gammapweights lpweights[] = {
- {
- gmm_default, /* Non hue specific defaults */
- { /* Cusp alignment control */
- {
- 0.0, /* [0.2] Cusp luminance alignment weighting 0 = none, 1 = full */
- 0.0, /* [0.0] Cusp chroma alignment weighting 0 = none, 1 = full */
- 0.0 /* [0.3] Cusp hue alignment weighting 0 = none, 1 = full */
- },
- 2.0, /* Alignment twist power, 0 = linear, 1 = curve, 2+ late curve */
- 1.00 /* Chroma expansion 1 = none */
- },
- { /* Radial weighting (currently broken - need to fix) */
- 0.0, /* Radial error overall weight, 0 + */
- 0.1, /* Radial hue dominance vs l+c, 0 - 1 */
- 1.0 /* Radial l dominance vs, c, 0 - 1 */
- },
- { /* Weighting of absolute error of destination from source */
- 1.0, /* Absolute error overall weight */
- 0.90, /* [0.9] Hue dominance vs l+c, 0 - 1 */
-
- 0.98, /* White l dominance vs, c, 0 - 1 */
- 0.95, /* Grey l dominance vs, c, 0 - 1 */
- 0.99, /* Black l dominance vs, c, 0 - 1 */
-
- 0.4, /* White l blend start radius, 0 - 1, at white = 0 */
- 0.7, /* Black l blend power, linear = 1.0, enhance < 1.0 */
-
- 1.0, /* L error extra power with size, none = 1.0 */
- 100.0 /* L error extra xover threshold in DE */
- },
- { /* Relative vector smoothing */
- 6.0, 30.0, /* Relative Smoothing radius L* H* */
- 0.9 /* [0.9] Degree of smoothing */
- },
- { /* Weighting of excessive compression error, which is */
- /* the src->dst vector length over the available dst depth. */
- /* (This compromizes constanl L near white and black, so minimize) */
- 0.0, /* Compression depth weight */
- 0.0 /* Expansion depth weight */
- },
- {
- 0.0 /* Fine tuning expansion weight, 0 - 1 */
- }
- },
- {
- gmm_end,
- }
-};
-double lpsmooth = 1.0; /* [1.0] Level of RSPL smoothing for ligtness pres perc, 1 = nominal */
+double psmooth = 4.0; /* [5.0] Level of RSPL smoothing for perceptual, 1 = nominal */
/* Saturation mapping weights, where saturation has priority over smoothness */
gammapweights sweights[] = {
@@ -414,25 +349,24 @@ gammapweights sweights[] = {
0.4, /* Hue dominance vs l+c, 0 - 1 */
0.6, /* White l dominance vs, c, 0 - 1 */
- 0.3, /* Grey l dominance vs, c, 0 - 1 */
- 0.7, /* Black l dominance vs, c, 0 - 1 */
+ 0.4, /* Grey l dominance vs, c, 0 - 1 */
+ 0.6, /* Black l dominance vs, c, 0 - 1 */
0.5, /* wl blend start radius, 0 - 1 */
1.0, /* bl blend power, linear = 1.0, enhance < 1.0 */
- 1.5, /* L error extra power with size, none = 1.0 */
- 20.0 /* L error extra xover threshold in DE */
+ 1.0, /* L error extra power with size, none = 1.0 */
+ 10.0 /* L error extra xover threshold in DE */
},
{ /* Relative vector smoothing */
- 15.0, 20.0, /* Relative Smoothing radius L* H* */
- 0.8 /* [0.8] Degree of smoothing */
+ 20.0, 25.0 /* Relative Smoothing radius L* H* */
},
{ /* Weighting of excessive compression error, which is */
/* the src->dst vector length over the available dst depth. */
/* The depth is half the distance to the intersection of the */
/* vector to the other side of the gamut. (doesn't get triggered much ?) */
- 5.0, /* Compression depth weight */
- 5.0 /* Expansion depth weight */
+ 10.0, /* Compression depth weight */
+ 10.0 /* Expansion depth weight */
},
{
0.5 /* Fine tuning expansion weight, 0 - 1 */
@@ -469,8 +403,7 @@ gammapweights sweights[] = {
-1.0 /* L error xover threshold in DE */
},
{ /* Relative error preservation using smoothing */
- 10.0, 15.0, /* Relative smoothing radius */
- 0.5 /* Degree of smoothing */
+ 10.0, 15.0 /* Relative smoothing radius */
},
{ /* Weighting of excessive compression error, which is */
/* the src->dst vector length over the available dst depth. */
@@ -487,9 +420,7 @@ gammapweights sweights[] = {
gmm_end
}
};
-/* The cusp alignment tends to upset the vector smoothing (not exactly sure why), */
-/* so use more rspl smoothing to compensate. */
-double ssmooth = 4.0; /* [1.0] Level of RSPL smoothing for saturation */
+double ssmooth = 2.0; /* Level of RSPL smoothing for saturation */
/*
* Notes:
@@ -520,7 +451,7 @@ static void map_trans(void *cntx, double out[3], double in[3]);
gammap *new_gammap(
int verb, /* Verbose flag */
gamut *sc_gam, /* Source colorspace gamut */
- gamut *isi_gam, /* Input source image gamut (NULL if none) */
+ gamut *si_gam, /* Source image gamut (NULL if none) */
gamut *d_gam, /* Destination colorspace gamut */
icxGMappingIntent *gmi, /* Gamut mapping specification */
int src_kbp, /* Use K only black point as src gamut black point */
@@ -532,10 +463,9 @@ gammap *new_gammap(
double *mx, /* for rspl grid. */
char *diagname /* If non-NULL, write a gamut mapping diagnostic WRL */
) {
- gammap *s; /* This */
- gamut *si_gam = NULL; /* Source image gamut (intersected with sc_gam) */
- gamut *scl_gam; /* Source colorspace gamut with rotation and L mapping applied */
- gamut *sil_gam; /* Source image gamut with rotation and L mapping applied */
+ gammap *s; /* This */
+ gamut *scl_gam; /* Source colorspace gamut with rotation and L mapping applied */
+ gamut *sil_gam; /* Source image gamut with rotation and L mapping applied */
double s_cs_wp[3]; /* Source colorspace white point */
double s_cs_bp[3]; /* Source colorspace black point */
@@ -561,11 +491,7 @@ gammap *new_gammap(
double d_mt_wp[3]; /* Overall destination mapping white point (used for finetune) */
double d_mt_bp[3]; /* Overall destination mapping black point (used for finetune) */
-#ifdef USE_BOUND
- int surfpnts = 1; /* Add grid surface anchor points */
-#else
- int surfpnts = 0; /* Don't add grid surface points */
-#endif
+ int defrgrid = 6; /* mapping range surface default anchor point resolution */
int nres = 512; /* Neutral axis resolution */
cow lpnts[10]; /* Mapping points to create grey axis map */
int revrspl = 0; /* Reverse grey axis rspl construction */
@@ -578,14 +504,10 @@ gammap *new_gammap(
# pragma message("################ A gammap.c PLOT is #defined #########################")
#endif
-#ifndef USE_BOUND
-# pragma message("################ gammap.c USE_BOUND not set #########################")
-#endif
-
if (verb) {
xicc_dump_gmi(gmi);
printf("Gamut map resolution: %d\n",mapres);
- if (isi_gam != NULL)
+ if (si_gam != NULL)
printf("Image gamut supplied\n");
}
@@ -600,15 +522,18 @@ gammap *new_gammap(
/* Now create everything */
- /* Grab the colorspace white and black points */
+ /* Grab the white and black points */
if (src_kbp) {
- if (sc_gam->getwb(sc_gam, s_cs_wp, NULL, s_cs_bp, NULL, NULL, NULL)) {
+ // ~~99 Hmm. Shouldn't this be colorspace rather than gamut ????
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s_cs_wp, NULL, s_cs_bp)) {
+// if (sc_gam->getwb(sc_gam, s_cs_wp, NULL, s_cs_bp, NULL, NULL, NULL))
fprintf(stderr,"gamut map: Unable to read source colorspace white and black points\n");
free(s);
return NULL;
}
} else {
- if (sc_gam->getwb(sc_gam, s_cs_wp, s_cs_bp, NULL, NULL, NULL, NULL)) {
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s_cs_wp, s_cs_bp, NULL)) {
+// if (sc_gam->getwb(sc_gam, s_cs_wp, s_cs_bp, NULL, NULL, NULL, NULL))
fprintf(stderr,"gamut map: Unable to read source colorspace white and black points\n");
free(s);
return NULL;
@@ -616,40 +541,16 @@ gammap *new_gammap(
}
/* If source space is source gamut */
- if (isi_gam == NULL || isi_gam == sc_gam) {
+ if (si_gam == NULL) {
si_gam = sc_gam;
for (j = 0; j < 3; j++) {
s_ga_wp[j] = s_cs_wp[j];
s_ga_bp[j] = s_cs_bp[j];
}
- /* Else have explicit image gamut */
+ /* Else have explicit sourcegamut */
} else {
-#ifdef VERBOSE
- if (verb) { /* Check that image gamut is within colorspace */
- double scwp[3], scbp[3];
- double imwp[3], imbp[3];
-
- sc_gam->getwb(sc_gam, NULL, NULL, NULL, scwp, scbp, NULL);
- isi_gam->getwb(isi_gam, NULL, NULL, NULL, imwp, imbp, NULL);
-
- if (imwp[0] > (scwp[0] + 1e-4)
- || imbp[0] < (scbp[0] - 1e-4)) {
- printf("Warning: image gamut is bigger than src colorspace!\n");
- }
-
- }
-#endif
- /* Intersect it with the source colorspace gamut in case */
- /* something strange is going on. (mismatched appearance params ?) */
- if ((si_gam = new_gamut(0.0, 0, 0)) == NULL) {
- fprintf(stderr,"gamut map: new_gamut failed\n");
- free(s);
- return NULL;
- }
- si_gam->intersect(si_gam, isi_gam, sc_gam);
-
if (src_kbp) {
if (si_gam->getwb(si_gam, NULL, NULL, NULL, s_ga_wp, NULL, s_ga_bp)) {
fprintf(stderr,"gamut map: Unable to read source gamut white and black points\n");
@@ -663,21 +564,42 @@ gammap *new_gammap(
return NULL;
}
}
+
+ /* Guard against silliness. Image must be within colorspace */
+ if (s_ga_wp[0] > s_cs_wp[0]) {
+ int j;
+ double t;
+#ifdef VERBOSE
+ if (verb)
+ printf("Fixing wayward image white point\n");
+#endif
+ t = (s_cs_wp[0] - s_ga_bp[0])/(s_ga_wp[0] - s_ga_bp[0]);
+ for (j = 0; j < 3; j++)
+ s_ga_wp[j] = s_ga_bp[j] + t * (s_ga_wp[j] - s_ga_bp[j]);
+
+ }
+ if (s_ga_bp[0] < s_cs_bp[0]) {
+ int j;
+ double t;
+#ifdef VERBOSE
+ if (verb)
+ printf("Fixing wayward image black point\n");
+#endif
+ t = (s_cs_bp[0] - s_ga_wp[0])/(s_ga_bp[0] - s_ga_wp[0]);
+ for (j = 0; j < 3; j++)
+ s_ga_bp[j] = s_ga_wp[j] + t * (s_ga_bp[j] - s_ga_wp[j]);
+ }
}
if (dst_kbp) {
if (d_gam->getwb(d_gam, NULL, NULL, NULL, d_cs_wp, NULL, d_cs_bp)) {
fprintf(stderr,"gamut map: Unable to read destination white and black points\n");
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
free(s);
return NULL;
}
} else {
if (d_gam->getwb(d_gam, NULL, NULL, NULL, d_cs_wp, d_cs_bp, NULL)) {
fprintf(stderr,"gamut map: Unable to read destination white and black points\n");
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
free(s);
return NULL;
}
@@ -950,7 +872,7 @@ glumknf = 1.0;
/* If we have a gamut (ie. image) range that is smaller than the */
/* L range of the colorspace, then use its white and black L values */
/* as the source to be compressed to the destination L range. */
- /* We expand only a colorspace range, not an image gamut range. */
+ /* We expand only a colorspace range, not a gamut/image range. */
{
double swL, dwL; /* Source and destination white point L */
double sbL, dbL; /* Source and destination black point L */
@@ -963,14 +885,14 @@ glumknf = 1.0;
dwL = gmi->glumwexf * dr_cs_wp[0] + (1.0 - gmi->glumwexf) * sr_cs_wp[0];
} else {
- if (sr_cs_wp[0] > dr_cs_wp[0]) { /* Colorspace needs compression */
+ if (sr_ga_wp[0] > dr_cs_wp[0]) { /* Gamut or colorspace needs compression */
- swL = (1.0 - gmi->glumwcpf) * dr_cs_wp[0] + gmi->glumwcpf * sr_cs_wp[0];
+ swL = (1.0 - gmi->glumwcpf) * dr_cs_wp[0] + gmi->glumwcpf * sr_ga_wp[0];
dwL = dr_cs_wp[0];
} else { /* Neither needed */
- swL = sr_cs_wp[0];
- dwL = sr_cs_wp[0];
+ swL = sr_ga_wp[0];
+ dwL = sr_ga_wp[0];
}
}
@@ -980,14 +902,14 @@ glumknf = 1.0;
dbL = gmi->glumbexf * dr_cs_bp[0] + (1.0 - gmi->glumbexf) * sr_cs_bp[0];
} else {
- if (sr_cs_bp[0] < dr_cs_bp[0]) { /* Colorspace needs compression */
+ if (sr_ga_bp[0] < dr_cs_bp[0]) { /* Gamut or colorspace needs compression */
- sbL = (1.0 - gmi->glumbcpf) * dr_cs_bp[0] + gmi->glumbcpf * sr_cs_bp[0];
+ sbL = (1.0 - gmi->glumbcpf) * dr_cs_bp[0] + gmi->glumbcpf * sr_ga_bp[0];
dbL = dr_cs_bp[0];
} else { /* Neither needed */
- sbL = sr_cs_bp[0];
- dbL = sr_cs_bp[0];
+ sbL = sr_ga_bp[0];
+ dbL = sr_ga_bp[0];
}
}
@@ -1046,21 +968,24 @@ glumknf = 1.0;
lpnts[ngreyp].v[0] = dbL;
lpnts[ngreyp++].w = 10.0; /* Must go through here */
-#ifndef USE_GLUMKNF
- /* make sure curve is firmly anchored */
- lpnts[ngreyp].p[0] = 0.3 * lpnts[ngreyp-1].p[0] + 0.7 * lpnts[ngreyp-2].p[0];
- lpnts[ngreyp].v[0] = 0.3 * lpnts[ngreyp-1].v[0] + 0.7 * lpnts[ngreyp-2].v[0];
- lpnts[ngreyp++].w = 1.0;
-
- lpnts[ngreyp].p[0] = 0.7 * lpnts[ngreyp-2].p[0] + 0.3 * lpnts[ngreyp-3].p[0];
- lpnts[ngreyp].v[0] = 0.7 * lpnts[ngreyp-2].v[0] + 0.3 * lpnts[ngreyp-3].v[0];
- lpnts[ngreyp++].w = 1.0;
-#else /* USE_GLUMKNF */
- {
- double cppos = 0.50; /* [0.50] Center point ratio between black and white */
+#ifdef USE_GLUMKNF
+ if (gmi->glumknf < 0.05)
+#endif /* USE_GLUMKNF */
+ { /* make sure curve is firmly anchored */
+ lpnts[ngreyp].p[0] = 0.3 * lpnts[ngreyp-1].p[0] + 0.7 * lpnts[ngreyp-2].p[0];
+ lpnts[ngreyp].v[0] = 0.3 * lpnts[ngreyp-1].v[0] + 0.7 * lpnts[ngreyp-2].v[0];
+ lpnts[ngreyp++].w = 1.0;
+
+ lpnts[ngreyp].p[0] = 0.7 * lpnts[ngreyp-2].p[0] + 0.3 * lpnts[ngreyp-3].p[0];
+ lpnts[ngreyp].v[0] = 0.7 * lpnts[ngreyp-2].v[0] + 0.3 * lpnts[ngreyp-3].v[0];
+ lpnts[ngreyp++].w = 1.0;
+ }
+#ifdef USE_GLUMKNF
+ else { /* There is at least some weight in knee points */
+ double cppos = 0.50; /* Center point ratio between black and white */
double cpll, cplv; /* Center point location and value */
- double kpwpos = 0.30; /* [0.30] White knee point location prop. towards center */
- double kpbpos = 0.15; /* [0.15] Black knee point location prop. towards center */
+ double kpwpos = 0.30; /* White knee point location prop. towards center */
+ double kpbpos = 0.20; /* Black knee point location prop. towards center */
double kwl, kbl, kwv, kbv; /* Knee point values and locations */
double kwx, kbx; /* Knee point extra */
@@ -1069,20 +994,20 @@ glumknf = 1.0;
printf("%sdbL = %f, dwL = %f\n", revrspl ? "(swapped) ": "", dbL,dwL);
#endif
- /* Center point location. Make lightly weighted */
- /* center the perceptual source, to try and maintain */
- /* the absolute source grey in the output, while */
- /* still allowing some of the knee compression/expansion to creep */
- /* into the other half. */
+ /* Center point location */
cpll = cppos * (swL - sbL) + sbL;
+ // ~~?? would this be better if the output
+ // was scaled by dwL/swL ?
cplv = cppos * (swL - sbL) + sbL;
#ifdef PLOT_LMAP
printf("cpll = %f, cplv = %f\n",cpll, cplv);
#endif
- /* Add weakish center point */
+
+#ifdef NEVER /* Don't use a center point */
lpnts[ngreyp].p[0] = cpll;
lpnts[ngreyp].v[0] = cplv;
- lpnts[ngreyp++].w = 0.5;
+ lpnts[ngreyp++].w = 5.0;
+#endif
//printf("~1 black half diff = %f\n",dbL - sbL);
//printf("~1 white half diff = %f\n",dwL - swL);
@@ -1096,7 +1021,7 @@ glumknf = 1.0;
// ~~ weigting of black point and white point differences
kwx = 0.6 * (dbL - sbL) + 1.0 * (swL - dwL);
kbx = 1.0 * (dbL - sbL) + 0.6 * (swL - dwL);
-
+
//kwx = 0.0;
//kbx = 0.0;
//glumknf = 0.0;
@@ -1110,6 +1035,7 @@ glumknf = 1.0;
if (kbv < dbL) /* Sanity check */
kbv = dbL;
+
#ifdef PLOT_LMAP
printf("using kbl = %f, kbv = %f\n",kbl, kbv);
printf("using kwl = %f, kwv = %f\n",kwl, kwv);
@@ -1119,110 +1045,68 @@ glumknf = 1.0;
lpnts[ngreyp].p[0] = kwl;
lpnts[ngreyp].v[0] = kwv;
lpnts[ngreyp++].w = gmi->glumknf * gmi->glumknf;
-
+
/* Emphasise points to cause black "knee" curve */
lpnts[ngreyp].p[0] = kbl;
lpnts[ngreyp].v[0] = kbv;
lpnts[ngreyp++].w = 1.5 * gmi->glumknf * 1.5 * gmi->glumknf;
}
#endif /* USE_GLUMKNF */
+ }
- /* Create RSPL */
- {
- datai il, ih;
- datao ol, oh;
- double avgdev[MXDO];
- int gres = 256;
-
- /* Create a 1D rspl, that is used to */
- /* form the overall L compression mapping. */
- if ((s->grey = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) /* Allocate 1D -> 1D */
- error("gamut: grey new_rspl failed");
-
- il[0] = -1.0; /* Set possible input range */
- ih[0] = 101.0;
- ol[0] = 0.0; /* Set normalisation output range */
- oh[0] = 100.0;
+ /* We now create the 1D rspl L map, that compresses or expands the luminence */
+ /* range, independent of grey axis alignment, or gamut compression. */
+ /* Because the rspl isn't symetrical when we swap X & Y, and we would */
+ /* like a conversion from profile A to B to be the inverse of profile B to A */
+ /* (as much as possible), we contrive here to always create a compression */
+ /* RSPL, and create an inverse for it, and swap the two of them so that */
+ /* the transform is correct and has an accurate inverse available. */
+ {
+ datai il, ih;
+ datao ol, oh;
+ double avgdev[MXDO];
+ int gres = 256;
+
+ /* Create a 1D rspl, that is used to */
+ /* form the overall L compression mapping. */
+ if ((s->grey = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) /* Allocate 1D -> 1D */
+ error("gamut: grey new_rspl failed");
+
+ il[0] = -1.0; /* Set possible input range */
+ ih[0] = 101.0;
+ ol[0] = 0.0; /* Set normalisation output range */
+ oh[0] = 100.0;
#ifdef NEVER /* Dump out the L mapping points */
- {
- int i;
- printf("1D rspl L mapping points:\n");
- for (i = 0; i < ngreyp; i++)
- printf("%d %f -> %f (w %f)\n",i,lpnts[i].p[0],lpnts[i].v[0],lpnts[i].w);
- }
+ {
+ int i;
+ printf("1D rspl L mapping points:\n");
+ for (i = 0; i < ngreyp; i++)
+ printf("%d %f -> %f (w %f)\n",i,lpnts[i].p[0],lpnts[i].v[0],lpnts[i].w);
+ }
#endif
- /* Create spline from the data points, with appropriate smoothness. */
- avgdev[0] = GAMMAP_RSPLAVGDEV;
- if (s->grey->fit_rspl_w(s->grey, GAMMAP_RSPLFLAGS, lpnts, ngreyp, il, ih, &gres, ol, oh, 5.0, avgdev, NULL)) {
- fprintf(stderr,"Warning: Grey axis mapping is non-monotonic - may not be very smooth ?\n");
- }
-
- /* Fine tune the rspl, to make sure that the white and black */
- /* point mapping is precise */
- {
- co cp;
- adjust1wb cx; /* Adjustment context */
-
- /* Lookup actual black & white */
- cp.p[0] = sbL;
- s->grey->interp(s->grey, &cp);
- cx.awb[0] = cp.v[0];
-
- cp.p[0] = swL;
- s->grey->interp(s->grey, &cp);
- cx.awb[1] = cp.v[0];
-
- /* Set target black and white */
- cx.twb[0] = dbL;
- cx.twb[1] = dwL;
-
- /* Fine tune the 3D->3D mapping */
- s->grey->re_set_rspl(
- s->grey, /* this */
- 0, /* Combination of flags */
- (void *)&cx, /* Opaque function context */
- adjust1_wb_func /* Function to set from */
- );
-
-#ifdef VERBOSE
- if (verb) {
- printf("Before tuning, L map White/Black is %f %f, should be %f %f\n",
- cx.awb[1], cx.awb[0], dwL, dbL);
-
- /* Lookup fine tuned black & white */
- cp.p[0] = sbL;
- s->grey->interp(s->grey, &cp);
- cx.awb[0] = cp.v[0];
-
- cp.p[0] = swL;
- s->grey->interp(s->grey, &cp);
- cx.awb[1] = cp.v[0];
-
- printf("After tuning, L map White/Black is %f %f, should be %f %f\n",
- cx.awb[1], cx.awb[0], dwL, dbL);
- }
-#endif /* VERBOSE */
- }
-
+ /* Create spline from the data points, with appropriate smoothness. */
+ avgdev[0] = GAMMAP_RSPLAVGDEV;
+ if (s->grey->fit_rspl_w(s->grey, GAMMAP_RSPLFLAGS, lpnts, ngreyp, il, ih, &gres, ol, oh, 5.0, avgdev, NULL)) {
+ fprintf(stderr,"Warning: Grey axis mapping is non-monotonic - may not be very smooth ?\n");
+ }
- /* Create an inverse mapping too, for reverse gamut and/or expansion. */
- il[0] = -1.0; /* Set possible input range */
- ih[0] = 101.0;
- ol[0] = 0.0; /* Set normalisation output range */
- oh[0] = 100.0;
+ /* Create an inverse mapping too, for reverse gamut and/or expansion. */
+ il[0] = -1.0; /* Set possible input range */
+ ih[0] = 101.0;
+ ol[0] = 0.0; /* Set normalisation output range */
+ oh[0] = 100.0;
- if ((s->igrey = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) /* Allocate 1D -> 1D */
- error("gamut: igrey new_rspl failed");
-
- /* Create it from inverse lookups of s->grey */
- s->igrey->set_rspl(s->igrey, 0, (void *)s->grey, inv_grey_func, il, ih, &gres, ol, oh);
+ if ((s->igrey = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) /* Allocate 1D -> 1D */
+ error("gamut: igrey new_rspl failed");
+
+ /* Create it from inverse lookups of s->grey */
+ s->igrey->set_rspl(s->igrey, 0, (void *)s->grey, inv_grey_func, il, ih, &gres, ol, oh);
- if (revrspl) { /* Swap to compensate for swapping of white and black points */
- rspl *tt = s->grey;
- s->grey = s->igrey;
- s->igrey = tt;
- }
+ if (revrspl) { /* Swap to compensate for swapping of white and black points */
+ rspl *tt = s->grey;
+ s->grey = s->igrey;
+ s->igrey = tt;
}
}
@@ -1263,8 +1147,6 @@ glumknf = 1.0;
if ((scl_gam = parttransgamut(s, sc_gam)) == NULL) {
fprintf(stderr,"gamut map: parttransgamut failed\n");
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
free(s);
return NULL;
}
@@ -1275,8 +1157,6 @@ glumknf = 1.0;
else {
if ((sil_gam = parttransgamut(s, si_gam)) == NULL) {
fprintf(stderr,"gamut map: parttransgamut failed\n");
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
free(s);
return NULL;
}
@@ -1289,6 +1169,7 @@ glumknf = 1.0;
cow *gpnts = NULL; /* Mapping points to create gamut mapping */
int max_gpnts;
int nspts; /* Number of source gamut surface points */
+ int rgridpts; /* Number of range surface grid points */
int i, j;
datai il, ih;
datao ol, oh;
@@ -1297,8 +1178,7 @@ glumknf = 1.0;
nearsmth *nsm = NULL; /* Returned list of near smooth points */
int nnsm; /* Number of near smoothed points */
double brad = 0.0; /* Black bend radius */
- gammapweights xpweights[14], xlpweights[14], xsweights[14];
- /* Explicit perceptial, lightnes pp. and sat. weights */
+ gammapweights xpweights[14], xsweights[14]; /* Explicit perceptial and sat. weights */
gammapweights xwh[14]; /* Structure holding blended weights */
double smooth = 1.0; /* Level of 3D RSPL smoothing, blend of psmooth and ssmooth */
vrml *wrl = NULL; /* Gamut mapping illustration (hulls + guide vectors) */
@@ -1313,9 +1193,17 @@ typedef struct {
#endif /* PLOT_3DKNEES */
/* Get the maximum number of points that will be created */
- nspts = near_smooth_np(NULL, scl_gam, sil_gam, d_gam, xvra, 4, surfpnts ? mapres : 0);
+ nspts = near_smooth_np(scl_gam, sil_gam, d_gam, xvra);
- max_gpnts = nres + nspts;
+ rgridpts = 0;
+#ifdef USE_BOUND
+ if (defrgrid >= 2) {
+ rgridpts = defrgrid * defrgrid * defrgrid
+ - (defrgrid -2) * (defrgrid -2) * (defrgrid -2);
+ }
+#endif
+
+ max_gpnts = nres + 3 * nspts + rgridpts;
if ((gpnts = (cow *)malloc(max_gpnts * sizeof(cow))) == NULL) {
fprintf(stderr,"gamut map: Malloc of mapping setup points failed\n");
s->grey->del(s->grey);
@@ -1323,8 +1211,6 @@ typedef struct {
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
scl_gam->del(scl_gam);
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
free(s);
return NULL;
}
@@ -1365,10 +1251,8 @@ typedef struct {
/* Create source grey axis point */
t = i/(nres - 1.0);
-#ifdef NEVER
/* Cover L = 0.0 to 100.0 */
t = ((100.0 * t) - sl_cs_bp[0])/(sl_cs_wp[0] - sl_cs_bp[0]);
-#endif
for (j = 0; j < 3; j++)
gpnts[ngamp].p[j] = sl_cs_bp[j] + t * (sl_cs_wp[j] - sl_cs_bp[j]);
@@ -1413,7 +1297,7 @@ typedef struct {
gpnts[ngamp].w = wt;
//printf("~1 t = %f, blended %f %f %f\n",t, gpnts[ngamp].v[0], gpnts[ngamp].v[1],gpnts[ngamp].v[2]);
-#ifdef DUMP_GREY_AXIS_POINTS
+#ifdef NEVER
printf("Grey axis %d maps %f %f %f -> %f %f %f wit %f\n",ngamp,
gpnts[ngamp].p[0], gpnts[ngamp].p[1], gpnts[ngamp].p[2],
gpnts[ngamp].v[0], gpnts[ngamp].v[1], gpnts[ngamp].v[2],
@@ -1486,7 +1370,6 @@ typedef struct {
/* Convert from compact to explicit hextant weightings */
if (expand_weights(xpweights, pweights)
- || expand_weights(xlpweights, lpweights)
|| expand_weights(xsweights, sweights)) {
fprintf(stderr,"gamut map: expand_weights() failed\n");
s->grey->del(s->grey);
@@ -1494,17 +1377,13 @@ typedef struct {
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
scl_gam->del(scl_gam);
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
free(s);
return NULL;
}
-
- /* Create weights as blend between perceptual, lightness pp. and saturation */
- near_xwblend3(xwh, xpweights, gmi->gampwf, xlpweights, gmi->gamlpwf,
- xsweights, gmi->gamswf);
- if ((gmi->gampwf + gmi->gamlpwf + gmi->gamswf) > 0.1)
- smooth = (gmi->gampwf * psmooth) + (gmi->gamlpwf * lpsmooth) + (gmi->gamswf * ssmooth);
+ /* Create weights as blend between perceptual and saturation */
+ near_xwblend(xwh, xpweights, gmi->gampwf, xsweights, gmi->gamswf);
+ if ((gmi->gampwf + gmi->gamswf) > 0.1)
+ smooth = (gmi->gampwf * psmooth) + (gmi->gamswf * ssmooth);
/* Tweak gamut mappings according to extra cmy cusp flags or rel override */
if (dst_cmymap != 0 || rel_oride != 0) {
@@ -1516,7 +1395,7 @@ typedef struct {
nsm = near_smooth(verb, &nnsm, scl_gam, sil_gam, d_gam, src_kbp, dst_kbp,
dr_cs_bp, xwh, gmi->gamcknf, gmi->gamxknf,
gmi->gamcpf > 1e-6, gmi->gamexf > 1e-6,
- xvra, mapres, smooth, 1.10, surfpnts, il, ih, ol, oh);
+ xvra, mapres, smooth, il, ih, ol, oh);
if (nsm == NULL) {
fprintf(stderr,"Creating smoothed near points failed\n");
s->grey->del(s->grey);
@@ -1524,11 +1403,58 @@ typedef struct {
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
scl_gam->del(scl_gam);
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
free(s);
return NULL;
}
+ /* --------------------------- */
+
+ /* Make sure the input range to encompasss the guide vectors. */
+ for (i = 0; i < nnsm; i++) {
+ for (j = 0; j < 3; j++) {
+ if (nsm[i].sv[j] < il[j])
+ il[j] = nsm[i].sv[j];;
+ if (nsm[i].sv[j] > ih[j])
+ ih[j] = nsm[i].sv[j];
+ }
+ }
+
+#ifdef NEVER
+ if (verb) {
+ fprintf(stderr,"Input bounding box:\n");
+ fprintfstderr,("%f -> %f, %f -> %f, %f -> %f\n",
+ il[0], ih[0], il[1], ih[1], il[2], ih[2]);
+ }
+#endif
+
+ /* Now expand the bounding box by aprox 5% margin, but scale grid res */
+ /* to match, so that the natural or given boundary still lies on the grid. */
+ {
+ int xmapres;
+ double scale;
+
+ xmapres = (int) ((mapres-1) * 0.05 + 0.5);
+ if (xmapres < 1)
+ xmapres = 1;
+
+ scale = (double)(mapres-1 + xmapres)/(double)(mapres-1);
+
+ for (j = 0; j < 3; j++) {
+ double low, high;
+ high = ih[j];
+ low = il[j];
+ ih[j] = (scale * (high - low)) + low;
+ il[j] = (scale * (low - high)) + high;
+ }
+
+ mapres += 2 * xmapres;
+#ifdef NEVER
+ if (verb) {
+ fprintf(stderr,"After incresing mapres to %d, input bounding box for 3D gamut mapping is:\n",mapres);
+ fprintf(stderr,"%f -> %f, %f -> %f, %f -> %f\n",
+ il[0], ih[0], il[1], ih[1], il[2], ih[2]);
+ }
+#endif
+ }
/* ---------------------------------------------------- */
/* Setup for diagnostic plot, that will have elements added */
@@ -1587,25 +1513,18 @@ typedef struct {
for (i = 0; i < nnsm; i++) {
double cpexf; /* The effective compression or expansion factor */
- /* Grid surface point */
- if (nsm[i].uflag != 0) {
- cpexf = gmi->gamcpf; /* Assume compression */
+ if (nsm[i].vflag == 0) { /* Unclear whether compression or expansion */
+ /* Use larger to the the two factors */
+ cpexf = gmi->gamcpf > gmi->gamexf ? gmi->gamcpf : gmi->gamexf;
+
+ } else if (nsm[i].vflag == 1) { /* Compression */
+ cpexf = gmi->gamcpf;
+
+ } else if (nsm[i].vflag == 2) { /* Expansion */
+ cpexf = gmi->gamexf;
- /* Guide vector */
} else {
- if (nsm[i].vflag == 0) { /* Unclear whether compression or expansion */
- /* Use larger to the the two factors */
- cpexf = gmi->gamcpf > gmi->gamexf ? gmi->gamcpf : gmi->gamexf;
-
- } else if (nsm[i].vflag == 1) { /* Compression */
- cpexf = gmi->gamcpf;
-
- } else if (nsm[i].vflag == 2) { /* Expansion */
- cpexf = gmi->gamexf;
-
- } else {
- error("gammap: internal, unknown guide point flag");
- }
+ error("gammap: internal, unknown guide point flag");
}
/* Compute destination value which is a blend */
@@ -1623,14 +1542,14 @@ typedef struct {
gpnts[ngamp].p[j] = nsm[i].sv[j];
gpnts[ngamp].v[j] = nsm[i].div[j];
}
- gpnts[ngamp++].w = nsm[i].w1; /* 1.01 for guide vectors, less for grid surface */
-
+ gpnts[ngamp++].w = 1.01; /* Main gamut surface mapping point */
+ /* (Use 1.01 as a marker value) */
if (ngamp >= max_gpnts)
error("gammap: internal, not enough space for mapping points B (%d > %d)\n",ngamp, max_gpnts);
#ifdef USE_GAMKNF
/* Add sub surface mapping point if available */
- if (nsm[i].uflag == 0 && nsm[i].vflag != 0) { /* Sub surface point is available */
+ if (nsm[i].vflag != 0) { /* Sub surface point is available */
/* Compute destination value which is a blend */
/* between the source value and the knee adjusted destination */
@@ -1670,6 +1589,82 @@ typedef struct {
if (ngamp >= max_gpnts)
error("gammap: internal, not enough space for mapping points (%d > %d)\n",ngamp, max_gpnts);
+ /* Create preliminary gamut mapping rspl, without grid boundary values. */
+ /* We use this to lookup the mapping for points on the source space gamut */
+ /* that result from clipping our grid boundary points */
+#ifdef USE_BOUND
+ for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+ gres[j] = (mapres+1)/2;
+ avgdev[j] = GAMMAP_RSPLAVGDEV;
+ }
+ s->map = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ s->map->fit_rspl_w(s->map, GAMMAP_RSPLFLAGS, gpnts, ngamp, il, ih, gres, ol, oh, smooth, avgdev, NULL);
+
+ /* Add input range grid surface anchor points to improve clipping behaviour. */
+ if (defrgrid >= 2) {
+ DCOUNT(gc, 3, 3, 0, 0, defrgrid);
+ double cent[3];
+
+ sc_gam->getcent(d_gam, cent);
+
+ DC_INIT(gc);
+ for (;;) {
+ /* If point is on the grid surface */
+ if ( gc[0] == 0 || gc[0] == (defrgrid-1)
+ || gc[1] == 0 || gc[1] == (defrgrid-1)
+ || gc[2] == 0 || gc[2] == (defrgrid-1)) {
+ double grid2gamut, gamut2cent, ww;
+ co cp;
+
+ /* Clip the point to the closest location on the source */
+ /* colorspace gamut. */
+ for (j = 0; j < 3; j++)
+ gpnts[ngamp].p[j] = il[j] + gc[j]/(defrgrid-1.0) * (ih[j] - il[j]);
+ sc_gam->nearest(sc_gam, cp.p, gpnts[ngamp].p);
+
+ /* Then lookup the equivalent gamut mapped value */
+ s->map->interp(s->map, &cp);
+
+ for (j = 0; j < 3; j++)
+ gpnts[ngamp].v[j] = cp.v[j];
+
+ /* Compute the distance of the grid surface point to the to the */
+ /* source colorspace gamut, as well as the distance from there */
+ /* to the gamut center point. */
+ for (grid2gamut = gamut2cent = 0.0, j = 0; j < 3; j++) {
+ double tt;
+ tt = gpnts[ngamp].p[j] - cp.p[j];
+ grid2gamut += tt * tt;
+ tt = cp.p[j] - cent[j];
+ gamut2cent += tt * tt;
+ }
+ grid2gamut = sqrt(grid2gamut);
+ gamut2cent = sqrt(gamut2cent);
+
+ /* Make the weighting inversely related to distance, */
+ /* to reduce influence on in gamut mapping shape, */
+ /* while retaining some influence at the edge of the */
+ /* grid. */
+ ww = grid2gamut / gamut2cent;
+ if (ww > 1.0)
+ ww = 1.0;
+
+ /* A low weight seems to be enough ? */
+ /* the lower the better in terms of geting best hull mapping fidelity */
+ gpnts[ngamp++].w = 0.05 * ww;
+
+ if (ngamp >= max_gpnts)
+ error("gammap: internal, not enough space for mapping points E (%d > %d)\n",ngamp, max_gpnts);
+ }
+ DC_INC(gc);
+ if (DC_DONE(gc))
+ break;
+ }
+ }
+#else /* !USE_BOUND */
+ printf("!!!! Warning - gammap boundary points disabled !!!!\n");
+#endif /* !USE_BOUND */
+
/* --------------------------- */
/* Compute the output bounding values, and check input range hasn't changed */
for (i = 0; i < ngamp; i++) {
@@ -1696,9 +1691,14 @@ typedef struct {
#endif
/* Create the final gamut mapping rspl. */
- /* [ How about converting to a delta filer ? ie. */
- /* create current filter, then create point list of delta from */
- /* smoothed value, filtering that and then un-deltering it ?? ] */
+ /* [ The smoothing is not as useful as it should be, because */
+ /* if it is increased it tends to push colors out of gamut */
+ /* where they get clipped. Some cleverer scheme which makes */
+ /* sure that smoothness errs on the side of more compression */
+ /* is needed. - Addressed in nearsmth now ? ] */
+ /* How about converting to a delta filer ? ie. */
+ /* create curren filter, then create point list of delta from */
+ /* smoothed value, filtering that and then un-deltering it ?? */
if (s->map != NULL)
s->map->del(s->map);
if (verb)
@@ -1720,24 +1720,20 @@ typedef struct {
/* (This isn't a good indication now that vectors have been adjusted */
/* to counteract the rspl smoothing at the edges.) */
if (verb) {
- double de, avgde = 0.0, maxde = 0.0, num = 0.0; /* DE stats */
+ double de, avgde = 0.0, maxde = 0.0; /* DE stats */
for (i = 0; i < nnsm; i++) {
double av[3];
- if (nsm[i].uflag != 0) /* Ignore grid boundary points */
- continue;
-
/* Compute the mapping error */
dopartialmap2(s, av, nsm[i].sv); /* Just the rspl */
de = icmLabDE(nsm[i].div, av);
avgde += de;
- num++;
if (de > maxde)
maxde = de;
}
- printf("Gamut hull fit to guides: = avg %f, max %f\n",avgde/num,maxde);
+ printf("Gamut hull fit to guides: = avg %f, max %f\n",avgde/nnsm,maxde);
}
#endif /* CHECK_NEARMAP */
@@ -1834,10 +1830,6 @@ typedef struct {
/* Show all neighbours */
wrl->start_line_set(wrl, 0);
for (i = 0; i < nnsm; i++) {
-
- if (nsm[i].uflag != 0) /* Ignore grid boundary points */
- continue;
-
for (j = 0; j < XNNB; j++) {
nearsmth *np = nsm[i].n[j]; /* Pointer to neighbor */
@@ -1873,8 +1865,6 @@ typedef struct {
/* Locate the nearest source point */
for (ix = 0; ix < nnsm; ix++) {
double dist = icmNorm33(pp, nsm[ix].sv);
- if (nsm[i].uflag != 0) /* Ignore grid boundary points */
- continue;
if (dist < bdist) {
bdist = dist;
bix = ix;
@@ -1957,9 +1947,6 @@ typedef struct {
double *ccc;
double mdst[3];
- if (nsm[i].uflag != 0) /* Ignore grid boundary points */
- continue;
-
#if defined(SHOW_ACTUAL_VECTORS) || defined(SHOW_ACTUAL_VEC_DIFF)
# ifdef SHOW_ACTUAL_VECTORS
wrl->add_col_vertex(wrl, 0, nsm[i].sv, yellow);
@@ -1996,8 +1983,6 @@ typedef struct {
#if defined(SHOW_VECTOR_INDEXES) || defined(SHOW_SUB_PNTS)
for (i = 0; i < nnsm; i++) {
- if (nsm[i].uflag != 0) /* Ignore grid boundary points */
- continue;
#ifdef SHOW_VECTOR_INDEXES
{
double cream[3] = { 0.7, 0.7, 0.5 };
@@ -2139,7 +2124,7 @@ typedef struct {
icmMul3By3x4(vec, mat, vec);
/* Intersect it with the source gamut */
- if (sil_gam->vector_isect(sil_gam, vec, cpoint, isect,
+ if (si_gam->vector_isect(si_gam, vec, cpoint, isect,
NULL, NULL, NULL, NULL, NULL) == 0) {
continue;
}
@@ -2194,7 +2179,7 @@ typedef struct {
icmMul3By3x4(vec, mat, vec);
/* Intersect it with the source gamut */
- if (sil_gam->vector_isect(sil_gam, vec, cpoint, isect,
+ if (si_gam->vector_isect(si_gam, vec, cpoint, isect,
NULL, NULL, NULL, NULL, NULL) == 0) {
warning("Ring %d vect %d diagnostic vector intersect failed",i,j);
continue;
@@ -2276,8 +2261,6 @@ typedef struct {
if (sil_gam != scl_gam)
sil_gam->del(sil_gam);
scl_gam->del(scl_gam);
- if (si_gam != sc_gam)
- si_gam->del(si_gam);
return s;
}
@@ -2468,20 +2451,6 @@ double *in
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/* Function to pass to rspl to re-set output values, */
-/* to adjust the 1D white and black points */
-static void
-adjust1_wb_func(
- void *pp, /* adjust1wb structure */
- double *out, /* output value to be adjusted */
- double *in /* corresponding input value */
-) {
- adjust1wb *p = (adjust1wb *)pp;
-
- /* Do a linear re-mapping from actual to target */
- out[0] = (out[0] - p->awb[0]) * (p->twb[1] - p->twb[0])/(p->awb[1] - p->awb[0]) + p->twb[0];
-}
-
/* Function to pass to rspl to invert grey curve */
static void inv_grey_func(
void *cntx,
diff --git a/gamut/gamut.c b/gamut/gamut.c
index 3fc1c97..dd4f43b 100644
--- a/gamut/gamut.c
+++ b/gamut/gamut.c
@@ -56,7 +56,7 @@
#define TRIANG_TOL 1e-10 /* [1e-10] Triangulation tollerance */
#define NORM_LOG_POW 0.25 /* [0.25] Normal, colorspace lopow value */
-#define RAST_LOG_POW 0.10 /* [0.10] Raster lopow value (is 0.05 too extreme ??) */
+#define RAST_LOG_POW 0.05 /* [0.05] Raster lopow value */
#undef TEST_CONVEX_HULL /* Use pure convex hull, not log hull */
@@ -156,7 +156,6 @@ static int getssvert(gamut *s, double *rad, double pos[3], double norm[3], int i
static void startnexttri(gamut *s);
static int getnexttri(gamut *s, int v[3]);
static double volume(gamut *s);
-static int write_to_vrml(gamut *s, vrml *wrl, double trans, int docusps);
static int write_trans_vrml(gamut *s, char *filename, int doaxes, int docusps,
void (*transform)(void *cntx, double out[3], double in[3]), void *cntx);
static int write_vrml(gamut *s, char *filename, int doaxes, int docusps);
@@ -175,9 +174,8 @@ static int compute_vector_isect(gamut *s, double *p1, double *p2, double *min, d
static int compute_vector_isectns(gamut *s, double *p1, double *p2, gispnt *lp, int ll);
static double log_scale(gamut *s, double ss);
static int intersect(gamut *s, gamut *s1, gamut *s2);
-static int nexpintersect(gamut *s, gamut *s1, gamut *s2);
-static int expdstbysrcmdst(gamut *s, gamut *s1, gamut *s2, gamut *s3,
- void (*cvect)(void *cntx, double *p2, double *p1), void *cntx);
+static int compdstgamut(gamut *s, gamut *img, gamut *src, gamut *dst, int docomp, int doexp,
+ gamut *nedst, void (*cvect)(void *cntx, double *vec, double *pos), void *cntx);
static int vect_intersect(gamut *s, double *rvp, double *ip, double *p1, double *p2, gtri *t);
static void compgawb(gamut *s);
@@ -658,8 +656,7 @@ int isRast /* Flag indicating Raster rather than colorspace */
s->getvert = getvert;
s->volume = volume;
s->intersect = intersect;
- s->nexpintersect = nexpintersect;
- s->expdstbysrcmdst = expdstbysrcmdst;
+ s->compdstgamut = compdstgamut;
s->radial = radial;
s->nradial = nradial;
s->nearest = nearest;
@@ -670,7 +667,6 @@ int isRast /* Flag indicating Raster rather than colorspace */
s->getwb = getwb;
s->setcusps = setcusps;
s->getcusps = getcusps;
- s->write_to_vrml = write_to_vrml;
s->write_vrml = write_vrml;
s->write_trans_vrml = write_trans_vrml;
s->write_gam = write_gam;
@@ -1066,13 +1062,44 @@ double pp[3] /* rectangular coordinate of point */
}
/* ------------------------------------ */
-
-/* intersect implementation */
-/* Assumes s has been initialised. */
-static void intersect_imp(gamut *s, gamut *sa, gamut *sb) {
+/* Initialise this gamut with the intersection of the */
+/* the two given gamuts. Return NZ on error. */
+/* Return 1 if gamuts are not compatible */
+/* (We assume that the this gamut is currently empty) */
+static int intersect(gamut *s, gamut *sa, gamut *sb) {
int i, j, k;
gamut *s1, *s2;
+ if (sa->compatible(sa, sb) == 0)
+ return 1;
+
+ if IS_LIST_EMPTY(sa->tris)
+ triangulate(sa);
+ if IS_LIST_EMPTY(sb->tris)
+ triangulate(sb);
+
+ s->isJab = sa->isJab;
+
+ if (sa->isRast || sb->isRast)
+ s->isRast = 1;
+
+ for (j = 0; j < 3; j++)
+ s->cent[j] = sa->cent[j];
+
+ /* Clear some flags */
+ s->cswbset = 0;
+ s->cswbset = 0;
+ s->dcuspixs = 0;
+
+ /* If either is a raster gamut, make it a raster gamut */
+ if (s->isRast)
+ s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
+ else
+ s->logpow = NORM_LOG_POW;
+
+ /* Don't filter the points (gives a more accurate result ?) */
+ s->nofilter = 1;
+
/* Add each source gamuts verticies that lie within */
/* the other gamut */
for (k = 0; k < 2; k++) {
@@ -1092,7 +1119,6 @@ static void intersect_imp(gamut *s, gamut *sa, gamut *sb) {
continue;
pl = s2->nradial(s2, NULL, s1->verts[i]->p);
-
if (pl <= (1.0 + 1e-9)) {
expand_gamut(s, s1->verts[i]->p);
s1->verts[i]->f &= ~GVERT_ISOS; /* s1 vert is not outside s2 */
@@ -1135,142 +1161,6 @@ static void intersect_imp(gamut *s, gamut *sa, gamut *sb) {
} END_FOR_ALL_ITEMS(tp1);
}
-}
-
-/* Initialise this gamut with the intersection of the */
-/* the two given gamuts. Return NZ on error. */
-/* Return 1 if gamuts are not compatible */
-/* (We assume that the this gamut is currently empty) */
-static int intersect(gamut *s, gamut *sa, gamut *sb) {
- gamut *ss;
- int j;
-
- if (sa->compatible(sa, sb) == 0)
- return 1;
-
- if IS_LIST_EMPTY(sa->tris)
- triangulate(sa);
- if IS_LIST_EMPTY(sb->tris)
- triangulate(sb);
-
- s->sres = sa->sres > sb->sres ? sa->sres : sb->sres;
-
- s->isJab = sa->isJab;
-
- /* Clear some flags */
- s->cswbset = 0;
- s->cswbset = 0;
- s->dcuspixs = 0;
-
- /* If either is a raster gamut, make it a raster gamut */
- if (sa->isRast || sb->isRast)
- s->isRast = 1;
-
- if (s->isRast) {
- s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
- s->no2pass = 1; /* Only do one pass */
- } else {
- s->logpow = NORM_LOG_POW; /* Convex hull compression power */
- s->no2pass = 0; /* Do two passes */
- }
-
- for (j = 0; j < 3; j++)
- s->cent[j] = sa->cent[j];
-
- /* Grab white & black from whichever source has it */
- if (sb->cswbset)
- ss = sb;
- else if (sb->cswbset)
- ss = sa;
-
- if (ss->cswbset) {
- for (j = 0; j < 3; j++) {
- s->cs_wp[j] = ss->cs_wp[j];
- s->cs_bp[j] = ss->cs_bp[j];
- s->cs_kp[j] = ss->cs_kp[j];
- }
- s->cswbset = ss->cswbset;
- }
-
- /* Don't filter the points (gives a more accurate result ?) */
- s->nofilter = 1;
-
- intersect_imp(s, sa, sb);
-
- if (sa->gawbset) {
- compgawb(s);
- }
-
- s->nofilter = 0;
-
- return 0;
-}
-
-/* ------------------------------------ */
-
-/* Initialise this gamut with neutral axis points from sa, */
-/* and then intersected with sb. */
-/* Return NZ on error. */
-/* Expand sb with neutral points, and then intersect */
-/* with sa. */
-
-/* Return 1 if gamuts are not compatible */
-/* (We assume that the this gamut is currently empty) */
-static int nexpintersect(gamut *s, gamut *sa, gamut *sb) {
- int i, j, k;
- gamut *s1, *s2;
-
- if (sa->compatible(sa, sb) == 0)
- return 1;
-
- if IS_LIST_EMPTY(sa->tris)
- triangulate(sa);
- if IS_LIST_EMPTY(sb->tris)
- triangulate(sb);
-
- s->sres = sa->sres > sb->sres ? sa->sres : sb->sres;
-
- s->isJab = sa->isJab;
-
- /* If either is a raster gamut, make it a raster gamut */
- if (sa->isRast || sb->isRast)
- s->isRast = 1;
-
- if (s->isRast) {
- s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
- s->no2pass = 1; /* Only do one pass */
- } else {
- s->logpow = NORM_LOG_POW; /* Convex hull compression power */
- s->no2pass = 0; /* Do two passes */
- }
-
- for (j = 0; j < 3; j++)
- s->cent[j] = sa->cent[j];
-
- /* Clear some flags */
- s->cswbset = 0;
- s->cswbset = 0;
- s->dcuspixs = 0;
-
- /* Don't filter the points (gives a more accurate result ?) */
- s->nofilter = 1;
-
- /* Number of points to generate */
- k = 10;
- if (sa->nv <= 10)
- k = 5;
-
- /* Generate points from black to white */
- for (i = 0; i < k; i++) {
- double pp[3];
- double bf = i/(k-1.0);
-
- icmBlend3(pp, sa->cs_bp, sa->cs_wp, bf);
- expand_gamut(s, pp);
- }
-
- /* let intersect_imp to the hard work */
- intersect_imp(s, sa, sb);
s->nofilter = 0;
@@ -1279,36 +1169,49 @@ static int nexpintersect(gamut *s, gamut *sa, gamut *sb) {
/* ------------------------------------ */
/*
- Initialise this gamut with the image/destination gamut
- expanded by the amount that dest colorspace is outside
- the source colorspace gamut.
+ Initialise this gamut with a destination mapping gamut.
+ s1 is the image gamut (a possible sub-set of the src gamut)
+ s2 is the source gamut
+ s3 is the destination gamut
+
+ if docomp:
+ this gamut will be set to the smaller of the img & dst gamuts
+ else
+ this gamut will be the img gamut
+
+ if doexp
+ this gamut will be expanded by the amount dst is outside the src gamut.
The vector direction of "inwards" is that returned by the
- callback function as p1 -> p2 if it is supplied, or radially
- inwards if it is not. p2 is a "center" point to compute depth to.
+ callback function if it is supplied, or radially inwards
+ if it is not.
Return 1 if gamuts are not compatible.
- (We assume that the _this_ gamut is currently empty)
+ (We assume that the this gamut is currently empty)
*/
#define MXNIS 40 /* Maximum raw intersections handled */
-static int expdstbysrcmdst(
-gamut *s, /* Gamut to be expanded */
-gamut *s1, /* (Image) destination gamut to be expanded */
+static int compdstgamut(
+gamut *s, /* This */
+gamut *s1, /* Image gamut, assumed to be a subset of source gamut */
gamut *s2, /* The source space gamut */
gamut *s3, /* The destination space gamut */
+int docomp, /* Flag, nz if compression is enabled */
+int doexp, /* Flag, nz if expansion is enabled. */
+gamut *nedst, /* Optional - if doexp, then expand nedst with non-expanded dst gamut */
void (*cvect)(void *cntx, double *p2, double *p1), /* Compression direction callback */
-void *cntx /* which returns p2 which is in desired direction from given p1 */
+void *cntx /* Returns p2 which is in desired direction from given p1 */
) {
+#ifdef STATS
+ int tedges, edgestested, testhits;
+#endif
int i, j, k;
gamut *ss[3];
+ gispnt lp1[MXNIS], lp2[MXNIS], lp3[MXNIS]; /* Intersection lists */
int ll1, ll2, ll3; /* Returned list length */
- gispnt lp1[MXNIS], lp2[MXNIS], lp3[MXNIS]; /* Lists of intersections */
int ii, jj, kk; /* List indexes */
-//printf("\n~1 expdstbysrcmdst() called\n");
-
if (s1->compatible(s1, s2) == 0
|| s1->compatible(s2, s3) == 0)
return 1;
@@ -1323,14 +1226,6 @@ void *cntx /* which returns p2 which is in desired direction from given p1 */
s->isJab = s1->isJab;
s->isRast = s1->isRast;
- if (s->isRast) {
- s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
- s->no2pass = 1; /* Only do one pass */
- } else {
- s->logpow = NORM_LOG_POW; /* Convex hull compression power */
- s->no2pass = 0; /* Do two passes */
- }
-
for (j = 0; j < 3; j++)
s->cent[j] = s1->cent[j];
@@ -1339,6 +1234,12 @@ void *cntx /* which returns p2 which is in desired direction from given p1 */
s->cswbset = 0;
s->dcuspixs = 0;
+ /* If s1 is a raster gamut, make output a raster gamut */
+ if (s->isRast)
+ s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
+ else
+ s->logpow = NORM_LOG_POW;
+
/* Don't filter the points (gives a more accurate result ?) */
s->nofilter = 1;
@@ -1346,12 +1247,26 @@ void *cntx /* which returns p2 which is in desired direction from given p1 */
ss[1] = s2;
ss[2] = s3;
- /* Use all the triangle vertices from the two/three gamuts */
+//printf("~1 compdstgamut docomp %d, doexp %d\n",docomp,doexp);
+ /* Reset the above/below flags */
+ /* 1 = img above dst */
+ /* 2 = img below dst */
+ /* 4 = src above dst */
+ /* 8 = src below dst */
+ for (k = 0; k < 3; k++) { /* For img, src & dst */
+ for (i = 0; i < ss[k]->nv; i++) {
+ if (!(ss[k]->verts[i]->f & GVERT_TRI))
+ continue;
+
+ ss[k]->verts[i]->as = 0;
+ }
+ }
+
+ /* Use all the triangle vertices from the three gamuts */
/* as candidate points, because any of them might */
/* determine a surface feature. */
- for (k = 0; k < 3; k++) {
+ for (k = 0; k < 3; k++) { /* For img, src & dst */
- /* For each vertex */
for (i = 0; i < ss[k]->nv; i++) {
double pp[3], ppv, p2[3];
double rr, r4;
@@ -1361,39 +1276,22 @@ void *cntx /* which returns p2 which is in desired direction from given p1 */
icmCpy3(pp, ss[k]->verts[i]->p); /* Point in question */
- if (k == 0) { /* Seed with all points from gamut */
- expand_gamut(s, pp); /* to ensure result can't be less. */
- }
-
//printf("\n~1 k %d, point %d: %f %f %f\n", k,i,pp[0],pp[1],pp[2]);
-
- /* Get the mapping vector */
if (cvect != NULL)
- cvect(cntx, p2, pp); /* Get mapping direction to center */
+ cvect(cntx, p2, pp); /* Get mapping direction */
else
- icmCpy3(p2, ss[k]->cent); /* Radial vector to center */
- icmNormalize33(pp, pp, p2, 1.0); /* Make p2->pp length 1.0 */
-
-//printf("~1 k %d, center %d: %f %f %f\n", k,i,p2[0],p2[1],p2[2]);
-
- /* Locate the intersecting segments for each gamut. */
- /* The returned parameter value will be >= 1.0 at and beyond the center point */
- /* and < 1.0 on the pp side. */
- /* We need intersections for all three for this to be a potential expansion point. */
- if ((ll1 = s1->vector_isectns(s1, pp, p2, lp1, MXNIS)) == 0) { /* Dest gamut */
-//printf("~1 no dst intersection\n");
- continue;
- }
- if ((ll2 = s2->vector_isectns(s2, pp, p2, lp2, MXNIS)) == 0) { /* Src space */
-//printf("~1 no sc intersection\n");
- continue;
- }
-
- if ((ll3 = s3->vector_isectns(s3, pp, p2, lp3, MXNIS)) == 0) { /* Dst space */
-//printf("~1 no dc intersection\n");
- continue;
- }
-
+ icmCpy3(p2, ss[k]->cent); /* Radial vector */
+ icmNormalize33(p2, p2, pp, 1.0);
+
+ /* Locate the intersecting segments for each gamut */
+ ll1 = ll2 = ll3 = 0;
+ ll1 = s1->vector_isectns(s1, pp, p2, lp1, MXNIS); /* Image gamut */
+ if (doexp) /* For dst - src expansion */
+ ll2 = s2->vector_isectns(s2, pp, p2, lp2, MXNIS); /* Src gamut */
+ if (docomp || doexp) /* For img ^ dst or dst - src */
+ ll3 = s3->vector_isectns(s3, pp, p2, lp3, MXNIS); /* Dst gamut */
+
+//printf("~1 ll1 %d, ll2 %d, ll3 %d\n",ll1,ll2,ll3);
#ifdef NEVER
printf("img segments:\n");
for (ii = 0; ii < ll1; ii++)
@@ -1405,120 +1303,264 @@ void *cntx /* which returns p2 which is in desired direction from given p1 */
for (ii = 0; ii < ll3; ii++)
printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp3[ii].pv,lp3[ii].dir,lp3[ii].edge,lp3[ii].tri->n);
#endif
+ /* Now go through each image segment */
+ for (ii = 0; ii < ll1; ii += 2) {
- /* We're only interested in the most outside intersection of each surface */
- /* on the side of the point in question. (we're ignoring and complex */
- /* topology) */
- if (lp1[0].pv > (1.0 - 1e-8)) {
-//printf("~1 dst point is on other side\n");
- continue;
- }
- if (lp2[0].pv > (1.0 - 1e-8)) {
-//printf("~1 sc point is on other side\n");
- continue;
- }
- if (lp3[0].pv > (1.0 - 1e-8)) {
-//printf("~1 sc point is on other side\n");
- continue;
- }
-
- /* Make sure that sc is inside dc, */
- /* and sc is on or above dst */
- if (lp2[0].pv > (lp3[0].pv - 1e-8)
- && lp2[0].pv <= (lp1[0].pv + 1e-8)) {
- double ex[3], sf;
-
- /* Expand point by up to dst - src */
- icmSub3(ex, lp3[0].ip, lp2[0].ip);
-
- /* Make expansion proportional to how far dst */
- /* is to sc */
- sf = (1.0 - lp1[0].pv)/(1.0 - lp2[0].pv);
- icmScale3(ex, ex, sf);
- icmAdd3(pp, lp1[0].ip, ex);
-
-//printf("~1 expanding point by sf %f = %f %f %f\nb",sf,ex[0],ex[1],ex[2]);
-//printf("~1 to %f %f %f\nb",pp[0],pp[1],pp[2]);
+ icmCpy3(pp, lp1[ii].ip);
+ ppv = lp1[ii].pv;
+
+//printf("~1 img pnt at %f\n",lp1[ii].pv);
+ if (docomp) {
+
+ /* Locate a dst segment around or below img point */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if ((lp1[kk+1].pv + 1e-8) >= ppv)
+ break;
+ }
+
+ if (kk >= ll3) { /* No dst segments or none below */
+ ss[k]->verts[i]->as |= 1; /* img above dst */
+//printf("~1 img pnt is outside dst\n");
+ continue;
+ } else {
+//printf("~1 ing %f - %f, dst %f - %f\n", lp1[ii].pv,lp1[ii+1].pv,lp3[kk].pv,lp3[kk+1].pv);
+ /* Use the dst point if it is smaller */
+ if (ppv < lp3[kk].pv) {
+ icmCpy3(pp, lp3[kk].ip);
+ ppv = lp3[kk].pv;
+//printf("~1 dst is smaller %f\n",ppv);
+ ss[k]->verts[i]->as |= 1; /* img above dst */
+ } else {
+//printf("~1 ing is smaller %f\n",ppv);
+ ss[k]->verts[i]->as |= 2; /* img below dst */
+ }
+ }
+ }
+
+ if (nedst != NULL)
+ expand_gamut(nedst, pp);
+
+ while (doexp) {
+ /* Locate a src segment that ing point lies in. */
+ for (jj = 0; jj < ll2; jj += 2) {
+ if (lp1[ii].pv >= (lp2[jj].pv - 1e-8)
+ && lp1[ii].pv <= (lp2[jj+1].pv + 1e-8))
+ break;
+ }
+ if (jj >= ll2) {
+ ss[k]->verts[i]->as |= 4; /* src above dst ?? */
+ break; /* No overlapping segment */
+ }
+
+ /* Locate a dst segment that src point lies in */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if (lp2[jj].pv >= (lp3[kk].pv - 1e-8)
+ && lp2[jj].pv <= (lp3[kk+1].pv + 1e-8))
+ break;
+ }
+ if (kk >= ll2) {
+ ss[k]->verts[i]->as |= 4; /* src above dst ?? */
+ break; /* No overlapping segment */
+ }
+
+ /* if src is outside dst, do nothing */
+ if (lp3[kk].pv >= lp2[jj].pv) {
+ ss[k]->verts[i]->as |= 4; /* src above dst */
+ break;
+ }
+
+ /* Expand point by dst - src */
+ icmAdd3(pp, pp, lp3[kk].ip);
+ icmSub3(pp, pp, lp2[jj].ip);
+ ss[k]->verts[i]->as |= 8; /* src below dst */
+//printf("~1 expanding point by %f - %f\nb",lp3[kk].pv,lp2[jj].pv);
+ break;
+ }
expand_gamut(s, pp);
- } else {
-//printf("~1 lp2 %f <= lp3 %f || lp2 %f > lp2 %f\n",lp2[0].pv,lp3[0].pv - 1e-8, lp2[0].pv, lp1[0].pv + 1e-8);
-//printf("~1 dc is inside sc or sc is inside dst\n");
}
}
}
- /* Generate points along the intersection of sc and dc, map them */
- /* to the image/dest gamut, and add them as well. This is to properly define */
- /* the edges of the expansion zone. */
+#ifdef STATS
+ tedges = edgestested = testhits = 0;
+#endif
- /* For sc on dc and then dc on sc */
- for (k = 0; k < 2; k++) {
- gamut *ss1, *ss2;
- gtri *tp1, *tp2; /* Triangle pointers */
+ /* Add any intersection points between img/dst, and src/dst */
+ for (k = 0; k < 4; k++) {
+ int mask;
+ gamut *sa, *sb;
+ gtri *tpa, *tpb; /* Triangle pointers */
if (k == 0) {
- ss1 = s2;
- ss2 = s3;
- } else {
- ss1 = s3;
- ss2 = s2;
+ if (!docomp)
+ continue;
+ mask = 3;
+ sa = s1; /* img */
+ sb = s3; /* dst */
+ } else if (k == 1) {
+ if (!docomp)
+ continue;
+ mask = 3;
+ sa = s3; /* dst */
+ sb = s1; /* img */
+ } else if (k == 2) {
+ if (!doexp)
+ continue;
+ mask = 12;
+ sa = s2; /* src */
+ sb = s3; /* dst */
+ } else if (k == 3) {
+ if (!doexp)
+ continue;
+ mask = 12;
+ sa = s3; /* dst */
+ sb = s2; /* src */
}
- /* Find the edges that intersect the other gamut */
- tp1 = ss1->tris;
- FOR_ALL_ITEMS(gtri, tp1) { /* For all ss1 triangles */
-
- for (j = 0; j < 3; j++) { /* For all edges in ss1 triangle */
- /* If edge passes through the other gamut */
- if ((tp1->e[j]->v[0]->f ^ tp1->e[j]->v[1]->f) & GVERT_ISOS) {
+ /* Now find the edges that intersect the other gamut */
+ tpa = sa->tris;
+ FOR_ALL_ITEMS(gtri, tpa) {
- /* Exhaustive search of other triangles in ss2, */
- /* to find the one that the edge intersects with. */
- tp2 = ss2->tris;
- FOR_ALL_ITEMS(gtri, tp2) {
+ for (j = 0; j < 3; j++) { /* For each edge */
+#ifdef STATS
+ tedges++;
+#endif
+ /* If edge disposition flags aren't the same */
+ if ((tpa->e[j]->v[0]->as ^ tpa->e[j]->v[1]->as) & mask
+ || (tpa->e[j]->v[0]->as & mask) == 3 || (tpa->e[j]->v[0]->as & mask) == 12
+ || (tpa->e[j]->v[1]->as & mask) == 3 || (tpa->e[j]->v[1]->as & mask) == 12) {
+#ifdef STATS
+ edgestested++;
+#endif
+ /* Exhaustive search of other triangles */
+ tpb = sb->tris;
+ FOR_ALL_ITEMS(gtri, tpb) {
double pv;
double pp[3];
/* Do a min/max intersection elimination test */
for (i = 0; i < 3; i++) {
- if (tp2->mix[1][i] < tp1->mix[0][i]
- || tp2->mix[0][i] > tp1->mix[1][i])
+ if (tpb->mix[1][i] < tpa->mix[0][i]
+ || tpb->mix[0][i] > tpa->mix[1][i])
break; /* min/max don't overlap */
}
if (i < 3)
continue; /* Skip this triangle, it can't intersect */
- if (vect_intersect(ss1, &pv, pp, tp1->e[j]->v[0]->p, tp1->e[j]->v[1]->p, tp2)
+ if (vect_intersect(sa, &pv, pp, tpa->e[j]->v[0]->p, tpa->e[j]->v[1]->p, tpb)
&& pv >= (0.0 - 1e-10) && pv <= (1.0 + 1e-10)) {
- double p2[3];
-
- /* Got intersection point pp. */
-
- /* Get the mapping vector */
+ /* Process intersection point pp the same as the first loop */
+ double ppv, p2[3];
+ double rr, r4;
+#ifdef STATS
+ testhits++;
+#endif
+//printf("\n~1 tri isxn point %f %f %f\n", pp[0],pp[1],pp[2]);
if (cvect != NULL)
- cvect(cntx, p2, pp); /* Get mapping direction to center */
+ cvect(cntx, p2, pp); /* Get mapping direction */
else
- icmCpy3(p2, ss[k]->cent); /* Radial vector to center */
- icmNormalize33(pp, pp, p2, 1.0); /* Make p2->pp length 1.0 */
-
- /* Locate the intersecting segments for the img/dest gamut. */
- /* The returned parameter value will be >= 1.0 at and beyond */
- /* the center point and < 1.0 on the pp side. */
- /* We're only going to bother with the most outside point */
- if ((ll1 = s1->vector_isectns(s1, pp, p2, lp1, MXNIS)) == 0
- || lp1[0].pv > (1.0 - 1e-8)) {
- continue;
+ icmCpy3(p2, sa->cent); /* Radial vector */
+ icmNormalize33(p2, p2, pp, 1.0);
+
+ /* Locate the intersecting segments for each gamut */
+ ll1 = ll2 = ll3 = 0;
+ ll1 = s1->vector_isectns(s1, pp, p2, lp1, MXNIS); /* Image gamut */
+ if (doexp) /* For dst - src expansion */
+ ll2 = s2->vector_isectns(s2, pp, p2, lp2, MXNIS); /* Src gamut */
+ if (docomp || doexp) /* For img ^ dst or dst - src */
+ ll3 = s3->vector_isectns(s3, pp, p2, lp3, MXNIS); /* Dst gamut */
+
+//printf("~1 ll1 %d, ll2 %d, ll3 %d\n",ll1,ll2,ll3);
+#ifdef NEVER
+ printf("img segments:\n");
+ for (ii = 0; ii < ll1; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp1[ii].pv,lp1[ii].dir,lp1[ii].edge,lp1[ii].tri->n);
+ printf("src segments:\n");
+ for (ii = 0; ii < ll2; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp2[ii].pv,lp2[ii].dir,lp2[ii].edge,lp2[ii].tri->n);
+ printf("dst segments:\n");
+ for (ii = 0; ii < ll3; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp3[ii].pv,lp3[ii].dir,lp3[ii].edge,lp3[ii].tri->n);
+#endif
+ /* Now go through each image segment */
+ for (ii = 0; ii < ll1; ii += 2) {
+
+ icmCpy3(pp, lp1[ii].ip);
+ ppv = lp1[ii].pv;
+
+//printf("~1 img pnt at %f\n",lp1[ii].pv);
+ if (docomp) {
+
+ /* Locate a dst segment around or below img point */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if ((lp1[kk+1].pv + 1e-8) >= ppv)
+ break;
+ }
+
+ if (kk >= ll3) { /* No dst segments or none below */
+//printf("~1 img pnt is outside dst\n");
+ continue;
+ } else {
+//printf("~1 ing %f - %f, dst %f - %f\n", lp1[ii].pv,lp1[ii+1].pv,lp3[kk].pv,lp3[kk+1].pv);
+ /* Use the dst point if it is smaller */
+ if (ppv < lp3[kk].pv) {
+ icmCpy3(pp, lp3[kk].ip);
+ ppv = lp3[kk].pv;
+//printf("~1 dst is smaller %f\n",ppv);
+ } else {
+//printf("~1 ing is smaller %f\n",ppv);
+ }
+ }
+ }
+
+ if (nedst != NULL)
+ expand_gamut(nedst, pp);
+
+ while (doexp) {
+ /* Locate a src segment that ing point lies in */
+ for (jj = 0; jj < ll2; jj += 2) {
+ if (lp1[ii].pv >= (lp2[jj].pv - 1e-8)
+ && lp1[ii].pv <= (lp2[jj+1].pv + 1e-8))
+ break;
+ }
+ if (jj >= ll2) {
+ break; /* No overlapping segment */
+ }
+
+ /* Locate a dst segment that src point lies in */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if (lp2[jj].pv >= (lp3[kk].pv - 1e-8)
+ && lp2[jj].pv <= (lp3[kk+1].pv + 1e-8))
+ break;
+ }
+ if (kk >= ll2) {
+ break; /* No overlapping segment */
+ }
+
+ /* if src is outside dst, do nothing */
+ if (lp3[kk].pv >= lp2[jj].pv) {
+ break;
+ }
+
+ /* Expand point by dst - src */
+ icmAdd3(pp, pp, lp3[kk].ip);
+ icmSub3(pp, pp, lp2[jj].ip);
+//printf("~1 expanding point by %f - %f\nb",lp3[kk].pv,lp2[jj].pv);
+ break;
+ }
+ expand_gamut(s, pp);
}
-
- expand_gamut(s, pp);
}
- } END_FOR_ALL_ITEMS(tp2);
+ } END_FOR_ALL_ITEMS(tpb);
}
}
- } END_FOR_ALL_ITEMS(tp1);
+ } END_FOR_ALL_ITEMS(tpa);
}
+#ifdef STATS
+ printf("Total edges %d, edges tested %d, edge hits %d\n", tedges, edgestested, testhits);
+#endif
s->nofilter = 0;
return 0;
@@ -3907,7 +3949,7 @@ double *nin /* Normalised center relative point */
if (fabs(denom) < 1e-9) {
/* Hmm. The ray is paralell to the triangle ? */
- error("radial_point: failed to intersect radial triangle, num %e, denom %e\n",num,denom);
+ error("radial_point: failed to intersect radial triangle\n");
}
rv = num/denom;
@@ -5582,7 +5624,7 @@ int ll /* Size of list. */
return 0; /* Too few to be useful */
}
- /* Now we need to turn the raw intersections into sanitized segment pairs. */
+ /* Now we need to turn th raw intersections into sanitized segment pairs. */
/* Sort the intersections by parameter value */
#define HEAP_COMPARE(A,B) (A.pv < B.pv)
@@ -5759,67 +5801,7 @@ int ll /* Size of list. */
#endif /* INTERSECT_DEBUG */
/* ===================================================== */
-
-/* Append gamut to an open VRML/X3d file */
-/* Return non-zero on error */
-static int write_to_vrml(
- gamut *s,
- vrml *wrl,
- double trans, /* Transparency of gamut */
- int docusps /* Add cusps to vrml */
-) {
- int i;
- gtri *tp; /* Triangle pointer */
-
- if IS_LIST_EMPTY(s->tris)
- triangulate(s);
-
- if (docusps && s->cu_inited != 0) {
- double ccolors[6][3] = {
- { 1.0, 0.1, 0.1 }, /* Red */
- { 1.0, 1.0, 0.1 }, /* Yellow */
- { 0.1, 1.0, 0.1 }, /* Green */
- { 0.1, 1.0, 1.0 }, /* Cyan */
- { 0.1, 0.1, 1.0 }, /* Blue */
- { 1.0, 0.1, 1.0 } /* Magenta */
- };
-
- for (i = 0; i < 6; i++)
- wrl->add_marker(wrl, s->cusps[i], ccolors[i], 2.0);
- }
-
- wrl->start_line_set(wrl, 0);
-
- /* Spit out the vertex values, in order. */
- for (i = 0; i < s->nv; i++) {
- double out[3];
-
- if (!(s->verts[i]->f & GVERT_TRI))
- continue;
-
- /* Show normal gamut surface */
- out[0] = s->verts[i]->p[0];
- out[1] = s->verts[i]->p[1];
- out[2] = s->verts[i]->p[2];
- wrl->add_vertex(wrl, 0, out);
- }
-
- /* Add the surface triangles */
- tp = s->tris;
- FOR_ALL_ITEMS(gtri, tp) {
- int ix[3];
- ix[0] = tp->v[0]->tn;
- ix[1] = tp->v[1]->tn;
- ix[2] = tp->v[2]->tn;
- wrl->add_triangle(wrl, 0, ix);
- } END_FOR_ALL_ITEMS(tp);
-
- wrl->make_triangles_vc(wrl, 0, trans);
-
- return 0;
-}
-
-/* Write gamut to a VRML/X3d file */
+/* Write to a VRML/X3d file */
/* Return non-zero on error */
static int write_vrml(
gamut *s,
@@ -5830,7 +5812,7 @@ int docusps /* Non-zero if cusp points are to be marked */
return write_trans_vrml(s, filename, doaxes, docusps, NULL, NULL);
}
-/* Write gamut to a VRML/X3d file */
+/* Write to a VRML/X3d file */
/* Return non-zero on error */
static int write_trans_vrml(
gamut *s,
@@ -5944,7 +5926,7 @@ void *cntx
ix[2] = tp->v[2]->tn;
wrl->add_triangle(wrl, 0, ix);
} END_FOR_ALL_ITEMS(tp);
-#endif /* !SHOW_BUCKETS */
+#endif /* SHOW_BUCKETS */
{
double rgb[3];
diff --git a/gamut/gamut.h b/gamut/gamut.h
index e70d898..467852f 100644
--- a/gamut/gamut.h
+++ b/gamut/gamut.h
@@ -36,8 +36,6 @@
#define MAXGAMN 10 /* Maximum gamut point neighbors returned */
#define NSLOTS 6 /* Number of maximum direction slots */
-struct _vrml *wrl; /* Declared in vrml.h, which may be #included after this */
-
/* ------------------------------------ */
#define NODE_STRUCT \
int tag; /* Type of node, 1 = vertex, 2 = quad */ \
@@ -74,7 +72,7 @@ struct _gvert {
double sp[3]; /* Point mapped to surface of unit sphere, relative to center */
double ch[3]; /* Point mapped for convex hull testing, relative to center */
- int as; /* Assert checking flag, expdstbysrcmdst flag */
+ int as; /* Assert checking flag, compdstgamut flag */
}; typedef struct _gvert gvert;
/* ------------------------------------ */
@@ -190,7 +188,7 @@ struct _gnn {
struct _gispnt {
double ip[3]; /* Intersecion Point */
double pv; /* Parameter value at intersection */
- int dir; /* Direction: 1 = into gamut, 0 = out of gamut */
+ int dir; /* Direction: 1 = into gamut, 0 = out or gamut */
int edge; /* Edge: 2 = no isect, 1 = on edge, 0 = not on edge */
gtri *tri; /* Pointer to intersection triangle */
}; typedef struct _gispnt gispnt;
@@ -315,14 +313,17 @@ struct _gamut {
/* Initialise this gamut with the intersection of the */
/* the two given gamuts. */
- int (*nexpintersect)(struct _gamut *s, struct _gamut *s1, struct _gamut *s2);
- /* Return s1 expanded with neutral axis points */
- /* and then intersected with s2. */
+#ifdef NEVER /* Deprecated */
+ int (*expandbydiff)(struct _gamut *s, struct _gamut *s1, struct _gamut *s2, struct _gamut *s3, int docomp);
+ /* Initialise this gamut with a gamut which is s1 expanded */
+ /* (but never reduced) by the distance from s2 to s3. */
+ /* If docomp != 0, make gamut trace s3 if it's smaller than s1 */
+#endif
- int (*expdstbysrcmdst)(struct _gamut *s,
- struct _gamut *dst, struct _gamut *sc, struct _gamut *dc,
- void (*cvect)(void *cntx, double *p2, double *p1), void *cntx);
- /* Expand dst by ((dc - sc) > 0) */
+ int (*compdstgamut)(struct _gamut *s, struct _gamut *img, struct _gamut *src,
+ struct _gamut *dst, int docomp, int doexpp, struct _gamut *nedst,
+ void (*cvect)(void *cntx, double *p2, double *p1), void *cntx);
+ /* Initialise this gamut with a destination mapping gamut. */
double (*radial)(struct _gamut *s, double out[3], double in[3]);
/* return point on surface in same radial direction. */
@@ -383,8 +384,6 @@ struct _gamut {
/* nz if no cusps available. */
/* Following return nz on error: */
- int (*write_to_vrml)(struct _gamut *s, struct _vrml *wrl, double trans, int docusps);
- /* Append gamut surface to vrml. See also vrml->make_gamut_surface() etc. */
int (*write_vrml)(struct _gamut *s, char *filename,
int doaxes, int docusps); /* Write to a VRML .wrl/.x3d file */
int (*write_gam)(struct _gamut *s, char *filename); /* Write to a CGATS .gam file */
diff --git a/gamut/maptest.c b/gamut/maptest.c
index 433e719..3a33453 100644
--- a/gamut/maptest.c
+++ b/gamut/maptest.c
@@ -192,7 +192,6 @@ main(int argc, char *argv[]) {
gmi.gampwf = 1.0; /* Gamut Perceptual Map weighting factor, 0.0 - 1.0 */
gmi.gamswf = 0.0; /* Gamut Saturation Map weighting factor, 0.0 - 1.0 */
}
- gmi.gamlpwf = 0.0; /* Gamut Lightness preserving perceptual Map whtg. factor, 0.0 - 1.0 */
gmi.satenh = 0.0; /* Saturation enhancement factor */
gmi.desc = "mapetest";
gmi.icci = 0;
@@ -206,7 +205,7 @@ main(int argc, char *argv[]) {
0, 0, /* Normal black points */
0, /* Normal CMY cusp mapping */
0, /* No relative weighting override */
- 19, /* rspl resolution of 17 */
+ 17, /* rspl resolution of 17 */
NULL, /* No input range override */
NULL,
gammapwrl /* Diagnostic plot */
diff --git a/gamut/nearsmth.c b/gamut/nearsmth.c
index c65704e..c0bd2be 100644
--- a/gamut/nearsmth.c
+++ b/gamut/nearsmth.c
@@ -52,7 +52,6 @@
#include <fcntl.h>
#include <string.h>
#include <math.h>
-#include "counters.h"
#include "icc.h"
#include "numlib.h"
#include "rspl.h"
@@ -61,14 +60,12 @@
#include "vrml.h"
#undef SAVE_VRMLS /* [Und] Save various vrml's */
-#undef PLOT_SMOOTHING_CHANGE /* [Und] Dest point change due to smoothing in "dst_smvec.wrl" */
#undef PLOT_MAPPING_INFLUENCE /* [Und] Plot sci_gam colored by dominant guide influence: */
/* Absolute = red, Relative = yellow, Radial = blue, Depth = green */
#undef PLOT_AXES /* [Und] */
#undef PLOT_EVECTS /* [Und] Create VRML of error correction vectors */
#undef VERB /* [Und] [0] If <= 1, print progress headings */
/* if > 1, print information about everything */
-#undef SHOW_NEIGB /* [Und] Show the neighborhood point group in src */
#undef SHOW_NEIGB_WEIGHTS /* [Und] Show the weighting for each point of neighbours in turn */
#undef DIAG_POINTS /* [Und] Short circuite mapping and show vectors of various */
@@ -81,8 +78,9 @@
#define DARK_L 5.0 /* "dark" L/J value */
#define NEUTRAL_C 20.0 /* "neutral" C value */
#define NO_TRIALS 6 /* [6] Number of random trials */
-#define VECADJPASSES 8 /* [8] Vector smoothing and adjust passes. */
-#define RSPLPASSES 4 /* [4] Number of rspl smoothing & adjustment passes */
+#define VECSMOOTHING /* [Def] Enable vector smoothing */
+#define VECADJPASSES 3 /* [3] Adjust vectors after smoothing to be on dest gamut */
+#define RSPLPASSES 4 /* [4] Number of rspl adjustment passes */
#define RSPLSCALE 1.8 /* [1.8] Offset within gamut for rspl smoothing to aim for */
#define SHRINK 5.0 /* [5.0] Shrunk destination evect surface factor */
#define CYLIN_SUBVEC /* [Def] Make sub-vectors always cylindrical direction */
@@ -116,7 +114,7 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if defined(SAVE_VRMLS) && defined(PLOT_MAPPING_INFLUENCE)
-static void create_influence_plot(nearsmth *smp, int nmpts, int mapres);
+static void create_influence_plot(nearsmth *smp, int nmpts);
#endif
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -196,7 +194,7 @@ double sumpow /* Sum power. 0.0 == 2.0 */
/* Compute the LCh differences squared of in1 - in2 */
/* (This is like the CIE DE94) */
-static void diffLChsq(
+static void diffLCh(
double out[3],
double in1[3], /* Destination location */
double in2[3] /* Source location */
@@ -260,7 +258,7 @@ double dcratio, /* Depth compression ratio of mapping */
double dxratio /* Depth expansion ratio of mapping */
) {
double a_o;
- double va, vr, vd, vv = 0.0;
+ double va, vr = 0.0, vl, vd, vv = 0.0;
/* Absolute, Delta E^2 between test point and destination closest */
/* aodv is already positioned acording to the LCh weights, */
@@ -269,7 +267,7 @@ double dxratio /* Depth expansion ratio of mapping */
va = wdesq(dtp, aodv, a_o, a_o, a_o, SUM_POW);
/* Radial. Delta E^2 between test point and source mapped radially to dest gamut */
- vr = wdesq(dtp, drv, w->rl.l, w->rl.c, w->rl.h, SUM_POW);
+ vl = wdesq(dtp, drv, w->rl.l, w->rl.c, w->rl.h, SUM_POW);
/* Depth ratio error^2. */
vd = w->d.co * dcratio * dcratio
@@ -278,16 +276,17 @@ double dxratio /* Depth expansion ratio of mapping */
/* Diagnostic values */
p->dbgv[0] = va;
p->dbgv[1] = vr;
- p->dbgv[2] = vd;
+ p->dbgv[2] = vl;
+ p->dbgv[3] = vd;
- vv = va + vr + vd; /* Sum of squares */
-// vv = sqrt(va) + sqrt(vr) + sqrt(vd); /* Linear sum is better ? */
-// vv = pow(va, 0.7) + pow(vr, 0.7) + pow(vd, 0.7); /* Linear sum is better ? */
+ vv = va + vr + vl + vd; /* Sum of squares */
+// vv = sqrt(va) + sqrt(vr) + sqrt(vl) + sqrt(vd); /* Linear sum is better ? */
+// vv = pow(va, 0.7) + pow(vr, 0.7) + pow(vl, 0.7) + pow(vd, 0.7); /* Linear sum is better ? */
#ifdef NEVER
printf("~1 dtp %f %f %f\n", dtp[0], dtp[1], dtp[2]);
printf("~1 va = %f from aodv %f %f %f, weight %f\n", va, aodv[0], aodv[1], aodv[2], a_o);
- printf("~1 vr = %f from drv %f %f %f, weights %f %f %f\n", vr, drv[0], drv[1], drv[2], w->rl.l, w->rl.c, w->rl.h);
+ printf("~1 vl = %f from drv %f %f %f, weights %f %f %f\n", vl, drv[0], drv[1], drv[2], w->rl.l, w->rl.c, w->rl.h);
printf("~1 vd = %f from d.co %f d.xo %f, weights %f %f\n", vd, w->d.co,w->d.xo,dcratio * dcratio,dxratio * dxratio);
printf("~1 return vv = %f\n", vv);
#endif /* NEVER */
@@ -301,13 +300,12 @@ double dxratio /* Depth expansion ratio of mapping */
/* and cusp mapping function. */
struct _smthopt {
/* optimisation */
- int debug; /* debug flag */
int pass; /* Itteration round */
int ix; /* Index of point being optimized */
nearsmth *p; /* Point being optimised */
int useexp; /* Flag indicating whether expansion is permitted */
- double *wn; /* Target of weighted nearest */
- gamut *wngam; /* for optfunc1 and optfunc1a */
+ int debug; /* debug flag */
+ gamut *shgam; /* for optfunc1a */
/* Setup state */
int isJab; /* Flag indicating Jab rather than Lab space */
@@ -336,7 +334,7 @@ struct _smthopt {
}; typedef struct _smthopt smthopt;
-static void init_ce(smthopt *s, gamut *sc_gam, gamut *si_gam, gamut *d_gam, int src_kbp, int dst_kbp, double d_bp[3]);
+static void init_ce(smthopt *s, gamut *sc_gam, gamut *d_gam, int src_kbp, int dst_kbp, double d_bp[3]);
static void comp_ce(smthopt *s, double out[3], double in[3], gammapweights *wt);
static void inv_comp_ce(smthopt *s, double out[3], double in[3], gammapweights *wt);
static double comp_naxbf(smthopt *s, double in[3]);
@@ -359,97 +357,84 @@ static void spow3(double *out, double *in, double ex) {
}
}
-/* Absolute error function, used by optfunc1() & optfunc1a() */
-static double aerrf(
- nearsmth *p,
- double *dv,
- double *sv
+/* Powell optimisation function for setting minimal absolute error target point. */
+/* We get a 2D plane in the 3D space, of the destination point, */
+/* who's location we are optimizing. */
+static double optfunc1(
+void *fdata,
+double *_dv
) {
- double delch[3], rv;
+ smthopt *s = (smthopt *)fdata;
+ nearsmth *p = s->p; /* Point being optimised */
+ int i, j, k;
+ double dv[3]; /* 3D point in question */
+ double ddv[3]; /* Point in question mapped to dst surface */
+ double delch[3];
+ double rv; /* Out of gamut, return value */
+
+ /* Convert from 2D to 3D. */
+ dv[2] = _dv[1];
+ dv[1] = _dv[0];
+ dv[0] = 50.0;
+ icmMul3By3x4(dv, p->m3d, dv);
+
+//printf("~1 optfunc1 got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
+ p->dgam->radial(p->dgam, ddv, dv); /* Map to dst surface to check current location */
+//printf("~1 optfunc1 got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
+
+ if (p->swap) {
+ /* This is actually a point on the real source gamut, so */
+ /* convert to cusp mapped rotated source gamut value */
+ comp_ce(s, ddv, ddv, &p->wt);
+//printf("~1 after cusp rot got %f %f %f\n",ddv[0],ddv[1],ddv[2]);
+ }
#ifdef NEVER
/* Absolute weighted delta E between source and dest test point */
- rv = wdesq(dv, sv, p->wt.ra.l, p->wt.ra.c, p->wt.ra.h, SUM_POW);
+ rv = wdesq(ddv, p->sv, p->wt.ra.l, p->wt.ra.c, p->wt.ra.h, SUM_POW);
#else
{
- double ppp = p->wt.a.lxpow; /* Extra power when L de is over thr */
+ double ppp = p->wt.a.lxpow;
double thr = p->wt.a.lxthr; /* Xover between normal and power */
double sumpow = SUM_POW;
- double del;
- diffLChsq(delch, dv, sv);
- del = sqrt(delch[0]); /* delta L */
+ diffLCh(delch, ddv, p->sv);
if (sumpow == 0.0 || sumpow == 2.0) { /* Normal sum of squares */
#ifdef LINEAR_HUE_SUM
double ll, cc, hh;
- ll = p->wt.ra.l * pow(delch[0], 1.0 + (ppp - 1.0) * del/(del + thr));
+ ll = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp);
cc = p->wt.ra.c * delch[1];
hh = p->wt.ra.h * delch[2];
rv = sqrt(ll + cc) + sqrt(hh);
rv *= rv;
#else
- rv = p->wt.ra.l * pow(delch[0], 1.0 + (ppp - 1.0) * del/(del + thr))
+ rv = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp)
+ p->wt.ra.c * delch[1]
+ p->wt.ra.h * delch[2];
#endif
} else {
sumpow *= 0.5;
- rv = p->wt.ra.l * pow(delch[0], (1.0 + (ppp - 1.0) * del/(del + thr)) * sumpow)
+
+ rv = p->wt.ra.l * pow(delch[0], ppp * sumpow) * thr/pow(thr, ppp * sumpow)
+ p->wt.ra.c * pow(delch[1], sumpow)
+ p->wt.ra.h * pow(delch[2], sumpow);
}
}
#endif
- return rv;
-}
-
-/* Powell optimisation function for setting minimal absolute error target point, */
-/* with a correction for swap. */
-/* We get a 2D plane in the 3D space, of the destination point, */
-/* who's location we are optimizing to wngam. */
-static double optfunc1(
-void *fdata,
-double *_dv
-) {
- smthopt *s = (smthopt *)fdata;
- nearsmth *p = s->p; /* Point being optimised */
- int i, j, k;
- double dv[3]; /* 3D point in question */
- double ddv[3]; /* Point in question mapped to wngam surface */
- double rv; /* Out of gamut, return value */
-
- /* Convert from 2D to 3D. */
- dv[2] = _dv[1];
- dv[1] = _dv[0];
- dv[0] = 50.0;
- icmMul3By3x4(dv, p->m3d, dv);
-
-//printf("~1 optfunc1 got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
- s->wngam->radial(s->wngam, ddv, dv); /* Map to dst surface to check current location */
-//printf("~1 optfunc1 got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
-
- if (p->swap) {
- /* This is actually a point on the real source gamut, so */
- /* convert to cusp mapped rotated source gamut value */
- comp_ce(s, ddv, ddv, &p->wt);
-//printf("~1 after cusp rot got %f %f %f\n",ddv[0],ddv[1],ddv[2]);
- }
-
- rv = aerrf(p, ddv, s->wn);
if (s->debug)
- printf("debug: rv = %f from %f %f %f -> %f %f %f\n",rv, s->wn[0], s->wn[1], s->wn[2], ddv[0], ddv[1], ddv[2]);
+ printf("debug: rv = %f from %f %f %f\n",rv, ddv[0], ddv[1], ddv[2]);
-//printf("~1 sv %4.2f %4.2f %4.2f, ddv %4.2f %4.2f %4.2f\n", p->wm[0], p->wm[1], p->wm[2], ddv[0], ddv[1], ddv[2]);
+//printf("~1 sv %4.2f %4.2f %4.2f, ddv %4.2f %4.2f %4.2f\n", p->sv[0], p->sv[1], p->sv[2], ddv[0], ddv[1], ddv[2]);
//printf("~1 rv = %f\n",rv);
return rv;
}
/* Powell optimisation function for setting minimal absolute error target point, */
-/* with no correction for swap. */
+/* from dest gamut to shrunk destination gamut. */
/* We get a 2D plane in the 3D space, of the destination point, */
-/* who's location we are optimizing to wngam. */
+/* who's location we are optimizing. */
static double optfunc1a(
void *fdata,
double *_dv
@@ -458,8 +443,9 @@ double *_dv
nearsmth *p = s->p; /* Point being optimised */
int i, j, k;
double dv[3]; /* 3D point in question */
- double ddv[3]; /* Point in question mapped to wngam surface */
- double rv; /* Out of gamut, return value */
+ double ddv[3]; /* Point in question mapped to shgam surface */
+ double delch[3];
+ double rv; /* Out of gamut, return value */
/* Convert from 2D to 3D. */
dv[2] = _dv[1];
@@ -467,16 +453,48 @@ double *_dv
dv[0] = 50.0;
icmMul3By3x4(dv, p->m3d, dv);
-//if (s->debug) printf("~1 optfunc1a got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
- s->wngam->radial(s->wngam, ddv, dv); /* Map to shgam surface to check current location */
-//if (s->debug) printf("~1 optfunc1a got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
+//printf("~1 optfunc1a got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
+ s->shgam->radial(s->shgam, ddv, dv); /* Map to shgam surface to check current location */
+//printf("~1 optfunc1a got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
+
+#ifdef NEVER
+ /* Absolute weighted delta E between source and dest test point */
+ rv = wdesq(ddv, p->sv, p->wt.ra.l, p->wt.ra.c, p->wt.ra.h, SUM_POW);
+#else
+ {
+ double ppp = p->wt.a.lxpow;
+ double thr = p->wt.a.lxthr; /* Xover between normal and power */
+ double sumpow = SUM_POW;
+
+ diffLCh(delch, ddv, p->dv);
- rv = aerrf(p, ddv, s->wn);
+ if (sumpow == 0.0 || sumpow == 2.0) { /* Normal sum of squares */
+#ifdef LINEAR_HUE_SUM
+ double ll, cc, hh;
+ ll = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp);
+ cc = p->wt.ra.c * delch[1];
+ hh = p->wt.ra.h * delch[2];
+ rv = sqrt(ll + cc) + sqrt(hh);
+ rv *= rv;
+#else
+ rv = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp)
+ + p->wt.ra.c * delch[1]
+ + p->wt.ra.h * delch[2];
+#endif
+ } else {
+ sumpow *= 0.5;
+
+ rv = p->wt.ra.l * pow(delch[0], ppp * sumpow) * thr/pow(thr, ppp * sumpow)
+ + p->wt.ra.c * pow(delch[1], sumpow)
+ + p->wt.ra.h * pow(delch[2], sumpow);
+ }
+ }
+#endif
if (s->debug)
- printf("debug: rv = %f from %f %f %f -> %f %f %f\n",rv, s->wn[0], s->wn[1], s->wn[2], ddv[0], ddv[1], ddv[2]);
+ printf("debug: rv = %f from %f %f %f\n",rv, ddv[0], ddv[1], ddv[2]);
-//if (s->debug) printf("~1 sv %4.2f %4.2f %4.2f, ddv %4.2f %4.2f %4.2f\n", p->wm[0], p->wm[1], p->wm[2], ddv[0], ddv[1], ddv[2]);
+//printf("~1 sv %4.2f %4.2f %4.2f, ddv %4.2f %4.2f %4.2f\n", p->sv[0], p->sv[1], p->sv[2], ddv[0], ddv[1], ddv[2]);
//printf("~1 rv = %f\n",rv);
return rv;
}
@@ -545,7 +563,7 @@ double *dv /* 3D Location being evaluated */
}
}
-/* Powell optimisation function for overall non-relative smoothed error optimization. */
+/* Powell optimisation function for non-relative error optimization. */
/* We get a 2D point in the 3D space. */
static double optfunc2(
void *fdata,
@@ -564,8 +582,8 @@ double *_dv
//printf("~1 optfunc2 got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
p->dgam->radial(p->dgam, ddv, dv); /* Map to dst surface to check current location */
-
//printf("~1 optfunc2 got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
+
//printf("~1 optfunc2 sv %4.2f %4.2f %4.2f, dv %4.2f %4.2f %4.2f\n", p->sv[0], p->sv[1], p->sv[2], ddv[0], ddv[1], ddv[2]);
/* Compute available depth errors p->dcratio and p->dxratio */
@@ -579,13 +597,12 @@ double *_dv
printf("~1 dv = %f %f %f\n", ddv[0], ddv[1], ddv[2]);
printf("~1 aodv = %f %f %f\n", p->aodv[0], p->aodv[1], p->aodv[2]);
printf("~1 drv = %f %f %f\n", p->drv[0], p->drv[1], p->drv[2]);
- printf("~1 va = %f, vr = %f, vd = %f\n", p->dbgv[0], p->dbgv[1], p->dbgv[2]);
printf("debug:%d: rv = %f from %f %f %f\n",s->ix, rv, dv[0], dv[1], dv[2]);
}
//printf("~1 rv = %f from %f %f\n",rv, _dv[0], _dv[1]);
-//printf("~1 rv = %f\n\n",rv);
+//printf("~1 rv = %f\n\n",rv);
return rv;
}
@@ -595,7 +612,6 @@ double *_dv
static void init_ce(
smthopt *s, /* Context for cusp mapping being set. */
gamut *sc_gam, /* Source colorspace gamut */
-gamut *si_gam, /* Source image gamut */
gamut *d_gam, /* Destination colorspace gamut */
int src_kbp, /* Use K only black point as src gamut black point */
int dst_kbp, /* Use K only black point as dst gamut black point */
@@ -624,9 +640,9 @@ double d_bp[3] /* Override destination target black point (may be NULL) */
/* Set some default values for src white/black/grey */
- /* Get the colorspace white and black point info */
+ /* Get the white and black point info */
if (src_kbp) {
- if (sc_gam->getwb(sc_gam, s->cusps[0][6], NULL, s->cusps[0][7], NULL, NULL, NULL) != 0) {
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s->cusps[0][6], NULL, s->cusps[0][7]) != 0) {
VB(("getting src wb points failed\n"));
s->cusps[0][6][0] = 100.0;
s->cusps[0][7][0] = 0.0;
@@ -634,7 +650,7 @@ double d_bp[3] /* Override destination target black point (may be NULL) */
s->donaxis = 0;
}
} else {
- if (sc_gam->getwb(sc_gam, s->cusps[0][6], s->cusps[0][7], NULL, NULL, NULL, NULL) != 0) {
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s->cusps[0][6], s->cusps[0][7], NULL) != 0) {
VB(("getting src wb points failed\n"));
s->cusps[0][6][0] = 100.0;
s->cusps[0][7][0] = 0.0;
@@ -644,7 +660,7 @@ double d_bp[3] /* Override destination target black point (may be NULL) */
}
if (dst_kbp) {
- if (d_gam->getwb(d_gam, s->cusps[1][6], NULL, s->cusps[1][7], NULL, NULL, NULL) != 0) {
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, s->cusps[1][6], NULL, s->cusps[1][7]) != 0) {
VB(("getting dest wb points failed\n"));
s->cusps[1][6][0] = 100.0;
s->cusps[1][7][0] = 0.0;
@@ -652,7 +668,7 @@ double d_bp[3] /* Override destination target black point (may be NULL) */
s->donaxis = 0;
}
} else {
- if (d_gam->getwb(d_gam, s->cusps[1][6], s->cusps[1][7], NULL, NULL, NULL, NULL) != 0) {
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, s->cusps[1][6], s->cusps[1][7], NULL) != 0) {
VB(("getting dest wb points failed\n"));
s->cusps[1][6][0] = 100.0;
s->cusps[1][7][0] = 0.0;
@@ -664,21 +680,6 @@ double d_bp[3] /* Override destination target black point (may be NULL) */
icmCpy3(s->cusps[1][7], d_bp);
}
-#ifdef NEVER
- {
- double iwp[3] = { -1, -1, -1}, ibp[3] = { -1, -1, -1};
- if (src_kbp) {
- si_gam->getwb(si_gam, NULL, NULL, NULL, iwp, NULL, ibp);
- } else {
- si_gam->getwb(si_gam, NULL, NULL, NULL, iwp, ibp, NULL);
- }
- printf("~1 src white = %f, black = %f\n",s->cusps[0][6][0],s->cusps[0][7][0]);
- printf("~1 img white = %f, black = %f\n",s->cusps[0][6][0],s->cusps[0][7][0]);
- printf("~1 dst white = %f, black = %f\n",s->cusps[1][6][0],s->cusps[1][7][0]);
- }
-
-#endif /* NEVER */
-
/* Get the cusp info */
if (sc_gam->getcusps(sc_gam, s->cusps[0]) != 0 || d_gam->getcusps(d_gam, s->cusps[1]) != 0) {
int isJab;
@@ -1165,7 +1166,6 @@ gammapweights *src
NSCOPY(r.rdl);
NSCOPY(r.rdh);
- NSCOPY(r.dsm);
NSCOPY(d.co);
NSCOPY(d.xo);
@@ -1207,50 +1207,6 @@ gammapweights *src2, double wgt2
NSBLEND(r.rdl);
NSBLEND(r.rdh);
- NSBLEND(r.dsm);
-
- NSBLEND(d.co);
- NSBLEND(d.xo);
-
- NSBLEND(f.x);
-#undef NSBLEND
-}
-
-/* Blend a three groups of individual weights into one, given three weightings */
-void near_wblend3(
-gammapweights *dst,
-gammapweights *src1, double wgt1,
-gammapweights *src2, double wgt2,
-gammapweights *src3, double wgt3
-) {
-
-#define NSBLEND(xxx) dst->xxx = wgt1 * src1->xxx + wgt2 * src2->xxx + wgt3 * src3->xxx
-
- NSBLEND(c.w.l);
- NSBLEND(c.w.c);
- NSBLEND(c.w.h);
- NSBLEND(c.tw);
- NSBLEND(c.cx);
-
- NSBLEND(l.o);
- NSBLEND(l.h);
- NSBLEND(l.l);
-
- NSBLEND(a.o);
- NSBLEND(a.h);
- NSBLEND(a.wl);
- NSBLEND(a.gl);
- NSBLEND(a.bl);
-
- NSBLEND(a.wlth);
- NSBLEND(a.blpow);
-
- NSBLEND(a.lxpow);
- NSBLEND(a.lxthr);
-
- NSBLEND(r.rdl);
- NSBLEND(r.rdh);
- NSBLEND(r.dsm);
NSBLEND(d.co);
NSBLEND(d.xo);
@@ -1393,9 +1349,8 @@ void tweak_weights(gammapweights out[14], int dst_cmymap, int rel_oride) {
}
if (rel_oride == 1) { /* A high saturation "clip" like mapping */
- out[i].r.rdl = 1.0; /* No relative neighbourhood/smoothing */
- out[i].r.rdh = 1.0; /* No relative neighbourhood/smoothing */
- out[i].r.dsm = 0.0; /* No relative neighbourhood/smoothing */
+ out[i].r.rdl = 1.0; /* No relative neighbourhood */
+ out[i].r.rdh = 1.0; /* No relative neighbourhood */
out[i].d.co = 0.0; /* No depth weighting */
out[i].d.xo = 0.0; /* No depth weighting */
@@ -1406,7 +1361,7 @@ void tweak_weights(gammapweights out[14], int dst_cmymap, int rel_oride) {
}
}
-/* Blend two expanded groups of individual weights into one */
+/* Blend a two expanded groups of individual weights into one */
void near_xwblend(
gammapweights *dst,
gammapweights *src1, double wgt1,
@@ -1417,18 +1372,6 @@ gammapweights *src2, double wgt2
near_wblend(&dst[i], &src1[i], wgt1, &src2[i], wgt2);
}
-/* Blend three expanded groups of individual weights into one */
-void near_xwblend3(
-gammapweights *dst,
-gammapweights *src1, double wgt1,
-gammapweights *src2, double wgt2,
-gammapweights *src3, double wgt3
-) {
- int i;
- for (i = 0; i < 14; i++)
- near_wblend3(&dst[i], &src1[i], wgt1, &src2[i], wgt2, &src3[i], wgt3);
-}
-
/* Convert overall, hue dom & l dom to iweight */
static void comp_iweight(iweight *iw, double o, double h, double l) {
double c, lc;
@@ -1593,15 +1536,14 @@ void interp_xweights(gamut *gam, gammapweights *out, double pos[3],
}
}
-/* Callback used by expdstbysrcmdst() to establish the expected compression */
-/* mapping direction. p2 should be the center point, so depth from the center */
-/* can be computed. We return a point on the neutral axis. */
+/* Callback used by compdstgamut() to establish the expected compression */
+/* mapping direction. */
static void cvect(
void *cntx, /* smthopt * */
double *p2, /* Return point displaced from p1 in desired direction */
double *p1 /* Given point */
) {
- double vv, lv[3];
+ double vv, gv[3], lv[3];
smthopt *s = (smthopt *)cntx;
gammapweights out;
@@ -1617,26 +1559,18 @@ double *p1 /* Given point */
/* Parameter along neutral axis black to white */
vv = (p1[0] - s->cusps[0][7][0])/(s->cusps[0][6][0] - s->cusps[0][7][0]);
-
/* lv is point at same L on neutral axis */
lv[0] = p1[0];
lv[1] = vv * (s->cusps[0][6][1] - s->cusps[0][7][1]) + s->cusps[0][7][1];
lv[2] = vv * (s->cusps[0][6][2] - s->cusps[0][7][2]) + s->cusps[0][7][2];
+ icmSub3(lv, lv, p1); /* Vector */
+ icmNormalize3(lv, lv, out.ra.l);
- /* Normalise l * c weight to sum to 1.0 */
- vv = fabs(out.ra.l + out.ra.c);
- if (vv < 1e-7) { /* Hmm. */
- out.ra.l = out.ra.c = 0.5;
- } else {
- out.ra.l /= vv;
- out.ra.c /= vv;
- }
+ icmSub3(gv, s->cusps[0][8], p1); /* Grey vector */
+ icmNormalize3(gv, gv, out.ra.c);
- /* Make p2 the weighted sum of equivalent L value and grey value on */
- /* the neutral axis. */
- icmScale3(lv, lv, out.ra.l);
- icmScale3(p2, s->cusps[0][8], out.ra.c);
- icmAdd3(p2, p2, lv);
+ icmAdd3(p2, gv, p1);
+ icmAdd3(p2, lv, p2); /* Combined destination */
//printf("~1 p2 %f %f %f\n", p2[0], p2[1], p2[2]);
}
@@ -1753,23 +1687,18 @@ double p1[3] /* Point */
/* ============================================ */
/* Return the maximum number of points that will be generated */
-/* (This isn't accurate due to manipulation of the gamuts in nearsmth!) */
int near_smooth_np(
- gamut **pp_gam, /* Return gamut that was used for points */
gamut *sc_gam, /* Source colorspace gamut */
gamut *si_gam, /* Source image gamut (== sc_gam if none) */
- gamut *dc_gam, /* Destination colorspace gamut */
- double xvra, /* Extra vertex ratio */
- int gmult, /* Guide point multiplier, typically 4 */
- int surfgres /* surface grid point resolution, 0 for none */
+ gamut *d_gam, /* Destination colorspace gamut */
+ double xvra /* Extra vertex ratio */
) {
gamut *p_gam; /* Gamut used for points - either source colorspace or image */
int ntpts, nmpts, nspts, nipts, ndpts;
- int hsurfgres = (surfgres + 1)/2; /* near_smooth uses half */
nspts = sc_gam->nverts(sc_gam);
nipts = si_gam->nverts(si_gam);
- ndpts = dc_gam->nverts(dc_gam);
+ ndpts = d_gam->nverts(d_gam);
p_gam = sc_gam;
/* Target number of points is max of any gamut */
@@ -1785,16 +1714,6 @@ int near_smooth_np(
xvra = ntpts/(double)nspts;
nmpts = p_gam->nssverts(p_gam, xvra); /* Stratified Sampling source points */
- nmpts *= gmult; /* Allow for sub-surface points etc. */
-
- if (hsurfgres >= 4) {
- nmpts += hsurfgres * hsurfgres * hsurfgres
- - (hsurfgres -4) * (hsurfgres -4) * (hsurfgres -4);
- }
-
- if (pp_gam != NULL)
- *pp_gam = p_gam;
-
return nmpts;
}
@@ -1807,7 +1726,7 @@ int verb, /* Verbose flag */
int *npp, /* Return the actual number of points returned */
gamut *sc_gam, /* Source colorspace gamut - uses cusp info if availablle */
gamut *si_gam, /* Source image gamut (== sc_gam if none), just used for surface. */
-gamut *dc_gam, /* Destination colorspace gamut */
+gamut *d_gam, /* Destination colorspace gamut */
int src_kbp, /* Use K only black point as src gamut black point */
int dst_kbp, /* Use K only black point as dst gamut black point */
double d_bp[3], /* Override destination target black point - may be NULL */
@@ -1819,22 +1738,22 @@ int useexp, /* Flag indicating whether smoothed expanded value will be used
double xvra, /* Extra number of vertexes ratio */
int mapres, /* Grid res for 3D RSPL */
double mapsmooth, /* Target smoothing for 3D RSPL */
-double gexp, /* Grid expansion ratio, none = 1.0 */
-int surfpnts, /* Flag - add surface grid points */
-datai map_il, /* Return expanded input range */
+datai map_il, /* Preliminary rspl input range */
datai map_ih,
-datao map_ol, /* Return expanded output range */
+datao map_ol, /* Preliminary rspl output range */
datao map_oh
) {
smthopt opts; /* optimisation and cusp mapping context */
int ix, i, j, k;
- gamut *p_gam; /* Gamut used for points == either source colorspace or image */
- gamut *src_gam; /* Intersection of src and img gamut gamut */
- gamut *dst_gam; /* Modified destination gamut suitable for mapping from src_gam. */
- /* If compression, this is the intersection of src_gam and dc_gam. */
- /* If expansion, this is the src_gam expanded by dc_gam - sc_gam. */
- gamut *nedst_gam;/* Same as above, but not expanded. */
- int mxnmpts; /* Allocated number of mapping points */
+ gamut *p_gam; /* Gamut used for points - either source colorspace or image */
+ gamut *sci_gam; /* Intersection of src and img gamut gamut */
+ gamut *di_gam; /* Modified destination gamut suitable for mapping from sci_gam. */
+ /* If just compression, this is the smaller of sci_gam and d_gam. */
+ /* If just expansion, this is the sci_gam expanded by d_gam - sc_gam. */
+ /* If both exp & comp, then where
+ d_gam is outside sci_gam this is sci_gam expanded by d_gam - sc_gam
+ else it is the smaller of sci_gam and d_gam */
+ gamut *nedi_gam;/* Same as above, but not expanded. */
int nmpts; /* Number of mapping gamut points */
nearsmth *smp; /* Absolute delta E weighting */
int pass;
@@ -1843,21 +1762,39 @@ datao map_oh
double codf; /* Itteration overshoot/damping factor */
double mxmv; /* Maximum a point gets moved */
int nmxmv; /* Number of maxmoves less than stopping threshold */
- int dmapres = 1; /* Change in mapres when applying gexp */
- int hmapres; /* Half mapres */
- int hdmapres; /* Half change in mapres */
- rspl *lastmap = NULL; /* Last gamut mapping map created, if any */
/* Check gamuts are compatible */
- if (sc_gam->compatible(sc_gam, dc_gam) == 0
+ if (sc_gam->compatible(sc_gam, d_gam) == 0
|| (si_gam != NULL && sc_gam->compatible(sc_gam, si_gam) == 0)) {
fprintf(stderr,"gamut map: Gamuts aren't compatible\n");
*npp = 0;
return NULL;
}
- mxnmpts = near_smooth_np(&p_gam, sc_gam, si_gam, dc_gam, xvra, 1, surfpnts ? mapres : 0);
- nmpts = 0;
+ {
+ int ntpts, nspts, nipts, ndpts;
+
+ nspts = sc_gam->nverts(sc_gam);
+ nipts = si_gam->nverts(si_gam);
+ ndpts = d_gam->nverts(d_gam);
+ p_gam = sc_gam;
+
+ /* Target number of points is max of any gamut */
+ ntpts = nspts > nipts ? nspts : nipts;
+ ntpts = ntpts > ndpts ? ntpts : ndpts;
+ ntpts = (int)(ntpts * xvra + 0.5);
+
+ /* Use image gamut if it exists */
+ if (nspts < nipts || si_gam != sc_gam) {
+ nspts = nipts; /* Use image gamut instead */
+ p_gam = si_gam;
+ }
+ xvra = ntpts/(double)nspts;
+ nmpts = p_gam->nssverts(p_gam, xvra); /* Stratified Sampling source points */
+
+ if (verb) printf("Vertex count: mult. = %f, src %d, img %d dst %d, target %d\n",
+ xvra,nspts,nipts,ndpts,nmpts);
+ }
/* Setup opts structure */
opts.useexp = useexp; /* Expansion used ? */
@@ -1868,106 +1805,80 @@ datao map_oh
/* Setup source & dest neutral axis transform if white/black available. */
/* If cusps are available, also figure out the transformations */
/* needed to map source cusps to destination cusps */
- init_ce(&opts, sc_gam, si_gam, dc_gam, src_kbp, dst_kbp, d_bp);
+ init_ce(&opts, sc_gam, d_gam, src_kbp, dst_kbp, d_bp);
/* Allocate our guide points */
- if ((smp = (nearsmth *)calloc(mxnmpts, sizeof(nearsmth))) == NULL) {
+ if ((smp = (nearsmth *)calloc(nmpts, sizeof(nearsmth))) == NULL) {
fprintf(stderr,"gamut map: Malloc of near smooth points failed\n");
*npp = 0;
return NULL;
}
- /* Create a source gamut surface that is the image gamut intersected */
- /* with the source colorspace gamut, in case something strange with the */
- /* image gamut. (gammap.c may have already done this) */
- src_gam = sc_gam; /* Alias to source space gamut */
+ /* Create a source gamut surface that is the intersection of the src colorspace */
+ /* and image gamut, in case (for some strange reason) the image gamut. */
+ /* exceeds the source colorspace size. */
+ sci_gam = sc_gam; /* Alias to source space gamut */
if (si_gam != sc_gam) {
- if ((src_gam = new_gamut(0.0, 0, 0)) == NULL) {
+ if ((sci_gam = new_gamut(0.0, 0, 0)) == NULL) {
fprintf(stderr,"gamut map: new_gamut failed\n");
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
}
- src_gam->intersect(src_gam, si_gam, sc_gam);
+ sci_gam->intersect(sci_gam, sc_gam, si_gam);
#ifdef SAVE_VRMLS
{
- char src_gam_name[40] = "si_gam";
-
- printf("###### gamut/nearsmth.c: writing diagnostic si_gam%s, src_gam%s\n",vrml_ext(),vrml_ext());
-
- strcat(src_gam_name, vrml_ext());
- src_gam->write_vrml(si_gam, src_gam_name, 1, 0);
-
- strcpy(src_gam_name, "src_gam");
- strcat(src_gam_name, vrml_ext());
- src_gam->write_vrml(src_gam, src_gam_name, 1, 0);
+ char sci_gam_name[40] = "sci_gam";
+ strcat(sci_gam_name, vrml_ext());
+ printf("###### gamut/nearsmth.c: writing diagnostic sci_gam%s and di_gam%s\n",vrml_ext(),vrml_ext());
+ sci_gam->write_vrml(sci_gam, sci_gam_name, 1, 0);
}
#endif
}
- dst_gam = src_gam; /* Default no compress or expand */
-
- /* non-expanded dst_gam for testing double back img points against: */
- nedst_gam = src_gam; /* Default same as dst_gam */
-
- /* Convert dst_gam to compress and/or expand target for mapping src_gam to. */
+ di_gam = sci_gam; /* Default no compress or expand */
if (usecomp || useexp) {
-
- if ((nedst_gam = dst_gam = new_gamut(0.0, 0, 0)) == NULL) {
+ if ((di_gam = new_gamut(0.0, 0, 0)) == NULL) {
fprintf(stderr,"gamut map: new_gamut failed\n");
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
}
- /* For compression only, nedst_gam and dst_gam are smaller of src_gam and dc_gam space. */
- /* Augment the dst_gam with neutral axis points in case the source gamut */
- /* has a "spike" that separates it from the neutral axis, allowing */
- /* mapping. */
- nedst_gam->nexpintersect(nedst_gam, dc_gam, src_gam);
-
if (useexp) {
- /* No image gamut - dest colorspace is target */
- if (si_gam == sc_gam) {
- dst_gam = dc_gam; /* Expanded dest is colorspace dest */
-
- /* There is an image gamut, so */
- /* Expand nedst_gam to create dst_gam expanded in proportion to where */
- /* dc_gam is outside sc_gam */
- } else {
- if ((dst_gam = new_gamut(0.0, 0, 0)) == NULL) {
- fprintf(stderr,"gamut map: new_gamut failed\n");
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- free_nearsmth(smp, nmpts);
- *npp = 0;
- return NULL;
- }
-
- /* Initialise this gamut with the nedst_gam expanded by ((dc_gam - sc_gam) > 0) */
- dst_gam->expdstbysrcmdst(dst_gam, nedst_gam, sc_gam, dc_gam, cvect, &opts);
+ /* Non-expand di_gam for testing double back img points against */
+ if ((nedi_gam = new_gamut(0.0, 0, 0)) == NULL) {
+ fprintf(stderr,"gamut map: new_gamut failed\n");
+ di_gam->del(di_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ return NULL;
}
+ } else {
+ nedi_gam = di_gam;
}
+
+ /* Initialise this gamut with a destination mapping gamut. */
+ /* This will be the smaller of the image and destination gamut if compressing, */
+ /* and will be expanded by the (dst - src) if expanding. */
+ di_gam->compdstgamut(di_gam, sci_gam, sc_gam, d_gam, usecomp, useexp, nedi_gam,
+ cvect, &opts);
}
#ifdef SAVE_VRMLS
{
- char dst_gam_name[30] = "dst_gam";
-
- printf("###### gamut/nearsmth.c: writing diagnostic dst_gam%s, nedst_gam%s\n",vrml_ext(),vrml_ext());
- strcat(dst_gam_name, vrml_ext());
- dst_gam->write_vrml(dst_gam, dst_gam_name, 1, 0);
-
- strcpy(dst_gam_name, "nedst_gam");
- strcat(dst_gam_name, vrml_ext());
- nedst_gam->write_vrml(nedst_gam, dst_gam_name, 1, 0);
+ char di_gam_name[30] = "di_gam";
+ strcat(di_gam_name, vrml_ext());
+ di_gam->write_vrml(di_gam, di_gam_name, 1, 0);
}
#endif
/* Create a list of the mapping guide points, setup for a null mapping */
VA(("Creating the mapping guide point list\n"));
- for (ix = i = 0; i < mxnmpts; i++) {
+ for (ix = i = 0; i < nmpts; i++) {
double imv[3], imr; /* Image gamut source point and radius */
double inorm[3]; /* Normal of image gamut surface at src point */
@@ -1979,12 +1890,12 @@ datao map_oh
//printf("~1 got point %d out of %d\n",i+1,nmpts);
if (p_gam != sc_gam) { /* If src colorspace point, map to img gamut surface */
- imr = src_gam->radial(src_gam, imv, imv);
+ imr = sci_gam->radial(sci_gam, imv, imv);
}
/* If point is within non-expanded modified destination gamut, */
- /* then it is a "double back"/convex image point, and should be ignored. */
- if (nedst_gam->radial(nedst_gam, NULL, imv) > (imr + 1e-4)) {
+ /* then it is a "double back" image point, and should be ignored. */
+ if (nedi_gam->radial(nedi_gam, NULL, imv) > (imr + 1e-4)) {
VB(("Rejecting point %d because it's inside destination\n",i));
i--;
continue;
@@ -1992,18 +1903,17 @@ datao map_oh
/* Lookup radialy equivalent point on modified destination gamut, */
/* in case we need it for compression or expansion */
- smp[i].drr = dst_gam->radial(dst_gam, smp[i].drv, imv);
+ smp[i].drr = di_gam->radial(di_gam, smp[i].drv, imv);
/* Default setup a null mapping of source image space point to source image point */
- smp[i].uflag = smp[i].vflag = smp[i].gflag = 0;
+ smp[i].vflag = smp[i].gflag = 0;
smp[i].dr = smp[i].sr = smp[i]._sr = imr;
smp[i].dv[0] = smp[i].sv[0] = smp[i]._sv[0] = imv[0];
smp[i].dv[1] = smp[i].sv[1] = smp[i]._sv[1] = imv[1];
smp[i].dv[2] = smp[i].sv[2] = smp[i]._sv[2] = imv[2];
- smp[i].w1 = 1.0;
- smp[i].sgam = src_gam;
- smp[i].dgam = src_gam;
- smp[i].dcgam = dc_gam;
+ smp[i].sgam = sci_gam;
+ smp[i].dgam = sci_gam;
+ smp[i].mapres = mapres;
VB(("In Src %d = %f %f %f\n",i,smp[i].sv[0],smp[i].sv[1],smp[i].sv[2]));
@@ -2017,7 +1927,7 @@ datao map_oh
double mv[3], ml; /* Radial inward mapping vector */
double dir;
- icmSub3(mv, src_gam->cent, smp[i].sv); /* Vector to center */
+ icmSub3(mv, sci_gam->cent, smp[i].sv); /* Vector to center */
ml = icmNorm3(mv); /* It's length */
if (ml > 0.001) {
@@ -2037,7 +1947,6 @@ datao map_oh
smp[i].anv[0] = smp[i].aodv[0] = smp[i].dv[0];
smp[i].anv[1] = smp[i].aodv[1] = smp[i].dv[1];
smp[i].anv[2] = smp[i].aodv[2] = smp[i].dv[2];
- smp[i].w1 = 1.01; /* Use 1.01 as marker value */
VB(("Src %d = %f %f %f\n",i,smp[i].sv[0],smp[i].sv[1],smp[i].sv[2]));
VB(("Dst %d = %f %f %f\n",i,smp[i].dv[0],smp[i].dv[1],smp[i].dv[2]));
@@ -2046,17 +1955,17 @@ datao map_oh
*npp = nmpts;
/* Don't need this anymore */
- if (nedst_gam != src_gam && nedst_gam != dst_gam)
- nedst_gam->del(nedst_gam);
- nedst_gam = NULL;
+ if (nedi_gam != di_gam)
+ nedi_gam->del(nedi_gam);
+ nedi_gam = NULL;
/* If nothing to be compressed or expanded, then return */
if (usecomp == 0 && useexp == 0) {
VB(("Neither compression nor expansion defined\n"));
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
return smp;
}
@@ -2069,15 +1978,6 @@ datao map_oh
interp_xweights(opts.sgam, &smp[i].wt, smp[i]._sv, opts.xwh, &opts, 0);
}
- /* ~~ would be nice to eliminate the need for dst_gam that is the intersection
- * of dc_gam and sc/img_gam here. Problem is determining expansion vector
- * direction in a way that is consistent with the absolute error weighting.
- *
- * For the moment leave the current appoach of using the dst_gam that has been
- * expanded in proportion to dc_gam - sc_gam in cvec() direction, since
- * the absolute error weighting is use to map the sv to that surface.
- */
-
VA(("Setting up cusp rotated compression or expansion mappings\n"));
VB(("rimv = Cusp rotated cspace/image gamut source point\n"));
VB(("imv = cspace/image gamut source point\n"));
@@ -2100,7 +2000,7 @@ datao map_oh
/* Compute the cusp rotated version of the cspace/image points */
comp_ce(&opts, rimv, imv, &smp[i].wt);
VB(("%f de, ix %d: cusp mapped %f %f %f -> %f %f %f\n", icmNorm33(rimv,imv), i, imv[0], imv[1], imv[2], rimv[0], rimv[1], rimv[2]));
- rimr = icmNorm33(rimv, src_gam->cent);
+ rimr = icmNorm33(rimv, sci_gam->cent);
/* Default setup a no compress or expand mapping of */
/* source space/image point to modified destination gamut. */
@@ -2108,8 +2008,8 @@ datao map_oh
smp[i].sv[0] = rimv[0]; /* Temporary rotated src point */
smp[i].sv[1] = rimv[1];
smp[i].sv[2] = rimv[2];
- smp[i].sgam = src_gam;
- smp[i].dgam = dst_gam;
+ smp[i].sgam = sci_gam;
+ smp[i].dgam = di_gam;
VB(("\n"));
VB(("point %d:, rimv = %f %f %f, rimr = %f\n",i,rimv[0],rimv[1],rimv[2],rimr));
@@ -2143,7 +2043,7 @@ datao map_oh
double tc[3] = { 0.0, 0.0, 0.0 };
for (ix = 0; ix < nmpts; ix++) {
- /* Compute a rotation that brings the target point location to 50,0,0 */
+ /* Coompute a rotation that brings the target point location to 50,0,0 */
icmVecRotMat(smp[ix].m2d, smp[ix].sv, sc_gam->cent, ta, tc);
/* And inverse */
@@ -2152,149 +2052,171 @@ datao map_oh
}
/* Figure out which neighbors of the source values to use */
- /* for the relative error & smoothing calculations. */
+ /* for the relative error calculations. */
/* Locate the neighbor within the radius for this point, */
/* and weight them with a Gausian filter weight. */
/* The radius is computed on the normalised surface for this point. */
VA(("Establishing filter neighbourhoods\n"));
{
+ double mm[3][4]; /* Tangent alignment rotation */
+ double m2[2][2]; /* Additional matrix to alight a with L axis */
+ double ta[3] = { 50.0, 0.0, 0.0 };
+ double tc[3] = { 0.0, 0.0, 0.0 };
double avgnd = 0.0; /* Total the average number of neighbours */
int minnd = 1e6; /* Minimum number of neighbours */
for (ix = 0; ix < nmpts; ix++) {
- int sit;
- double rr;
- double rrdl, rrdh;
+ double tt[3], rrdl, rrdh, rrdc, dd;
+ double msv[3], ndx[4]; /* Midpoint source value, quadrant distance */
+ double pr; /* Average point radius */
//printf("~1 computing neigbourhood for point %d at %f %f %f\n",ix, smp[ix].sv[0], smp[ix].sv[1], smp[ix].sv[2]);
+ /* Compute a rotation that brings the target point location to 50,0,0 */
+ icmNormalize33(tt, smp[ix].sv, smp[ix].sgam->cent, 1.0);
+ icmVecRotMat(mm, tt, smp[ix].sgam->cent, ta, tc);
+
+ /* Add another rotation to orient it so that [1] corresponds */
+ /* with the L direction, and [2] corresponds with the */
+ /* hue direction. */
+ m2[0][0] = m2[1][1] = 1.0;
+ m2[0][1] = m2[1][0] = 0.0;
+ tt[0] = smp[ix].sv[0] + 1.0;
+ tt[1] = smp[ix].sv[1];
+ tt[2] = smp[ix].sv[2];
+ icmNormalize33(tt, tt, smp[ix].sgam->cent, 1.0);
+ icmMul3By3x4(tt, mm, tt);
+ dd = tt[1] * tt[1] + tt[2] * tt[2];
+ if (dd > 1e-6) { /* There is a sense of L direction */
+
+ /* Create the 2x2 rotation matrix */
+ dd = sqrt(dd);
+ tt[1] /= dd;
+ tt[2] /= dd;
+
+ m2[0][0] = m2[1][1] = tt[1];
+ m2[0][1] = tt[2];
+ m2[1][0] = -tt[2];
+ }
+ /* Make rr inversely proportional to radius, so that */
+ /* filter scope is constant delta E */
rrdl = smp[ix].wt.r.rdl;
rrdh = smp[ix].wt.r.rdh;
-//printf("~1 rdl %f, rdh %f\n",rrdl, rrdh);
-
+//printf("~1 rdl %f, rdh %f\n",smp[ix].wt.r.rdl,smp[ix].wt.r.rdh);
if (rrdl < 1e-3) rrdl = 1e-3;
if (rrdh < 1e-3) rrdh = 1e-3;
- rr = sqrt(smp[ix].sv[1] * smp[ix].sv[1] + smp[ix].sv[2] * smp[ix].sv[2]);
-
- if (rr < 5.0)
- rr = 5.0;
- rr = sqrt(rr / 50.0);
-
- // Scale radius aprox. by cylindrical distance ?? */
- //rrdh *= rr;
-
- rrdl = 1.0/rrdl;
- rrdh = 1.0/rrdh;
-
- smp[ix].nnd = 0;
-
- /* Until we get a minimum number of neighbors */
- for (sit = 0; smp[ix].nnd < 8 && sit < 10; sit++) {
-
- smp[ix].nnd = 0;
-
- /* Search for points within the radius */
- for (i = 0; i < nmpts; i++) {
- double tt, dd, tv;
-
- /* Dot of neighbor color and point */
- tv = smp[i].sv[1] * smp[ix].sv[1] + smp[i].sv[2] * smp[ix].sv[2];
-
- /* Ignore if of the opposote hue */
- if (tv < 0.0)
- continue;
-
- dd = 0.0;
- tt = rrdl * (smp[i].sv[0] - smp[ix].sv[0]);
- dd += tt * tt;
- tt = rrdh * (smp[i].sv[1] - smp[ix].sv[1]);
- dd += tt * tt;
- tt = rrdh * (smp[i].sv[2] - smp[ix].sv[2]);
- dd += tt * tt;
-
- /* If we're within the filtering radius, */
- /* and not of the opposite hue */
- if (dd <= 1.0) {
- double w;
-
- dd = sqrt(dd); /* Convert to radius <= 1.0 */
-
- /* Add this point into the list */
- if (smp[ix].nnd >= smp[ix]._nnd) {
- neighb *nd;
- int _nnd;
- _nnd = 5 + smp[ix]._nnd * 2;
- if ((nd = (neighb *)realloc(smp[ix].nd, _nnd * sizeof(neighb))) == NULL) {
- VB(("realloc of neighbs at vector %d failed\n",ix));
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
- free_nearsmth(smp, nmpts);
- *npp = 0;
- return NULL;
- }
- smp[ix].nd = nd;
- smp[ix]._nnd = _nnd;
+ /* Average radius of source and destination */
+ pr = 0.5 * (smp[ix]._sr + smp[ix].dr);
+
+//printf("~1 pr = %f from _sr %f & dr %f\n",pr,smp[ix]._sr,smp[ix].dr);
+ if (pr < 5.0)
+ pr = 5.0;
+ rrdl *= 50.0/pr;
+ rrdh *= 50.0/pr;
+ rrdc = 0.5 * (rrdl + rrdh); /* Chrominance radius */
+
+ /* Scale the filter radius by the L/C value, */
+ /* so that the filters are largest at the equator, and smallest */
+ /* at the white & black points. This allows the wt.a.lx wt.a.cx to work. */
+ pr = smp[ix].naxbf + 0.1; /* "spherical" type weighting, 0.707 at 45 degrees */
+ rrdl *= pr;
+ rrdh *= pr;
+ rrdc *= pr;
+//printf("~1 at %f %f %f, rrdl = %f, rrdh = %f\n",smp[ix]._sv[0], smp[ix]._sv[1], smp[ix]._sv[2], rrdl, rrdh);
+
+ smp[ix].nnd = 0; /* Nothing in lists */
+
+ /* Search for points within the gausian radius */
+ for (i = 0; i < nmpts; i++) {
+ double x, y, z, tv[3];
+
+ /* compute tangent alignment rotated location */
+ icmNormalize33(tt, smp[i].sv, smp[ix].sgam->cent, 1.0);
+ icmMul3By3x4(tv, mm, tt);
+ icmMulBy2x2(&tv[1], m2, &tv[1]);
+
+ x = tv[1]/rrdl;
+ y = tv[2]/rrdh;
+ z = (tv[0] - 50.0)/rrdc;
+
+ /* Compute normalized delta normalized tangent surface */
+ dd = x * x + y * y + z * z;
+
+ /* If we're within the direction filtering radius, */
+ /* and not of the opposite hue */
+ if (dd <= 1.0 && tv[0] > 0.0) {
+ double w;
+
+ dd = sqrt(dd); /* Convert to radius <= 1.0 */
+
+ /* Add this point into the list */
+ if (smp[ix].nnd >= smp[ix]._nnd) {
+ neighb *nd;
+ int _nnd;
+ _nnd = 5 + smp[ix]._nnd * 2;
+ if ((nd = (neighb *)realloc(smp[ix].nd, _nnd * sizeof(neighb))) == NULL) {
+ VB(("realloc of neighbs at vector %d failed\n",ix));
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ return NULL;
}
- smp[ix].nd[smp[ix].nnd].n = &smp[i];
+ smp[ix].nd = nd;
+ smp[ix]._nnd = _nnd;
+ }
+ smp[ix].nd[smp[ix].nnd].n = &smp[i];
- /* Box filter */
-// w = 1.0;
+ /* Box filter */
+// w = 1.0;
- /* Triangle filter */
-// w = 1.0 - dd;
+ /* Triangle filter */
+// w = 1.0 - dd;
-// /* Cubic spline filter (default) */
- w = 1.0 - dd;
- w = w * w * (3.0 - 2.0 * w);
+// /* Cubic spline filter */
+// w = 1.0 - dd;
+// w = w * w * (3.0 - 2.0 * w);
- /* Gaussian filter */
-// w = exp(-9.0 * dd/2.0);
+ /* Gaussian filter (default) */
+ w = exp(-9.0 * dd/2.0);
- /* Sphere filter */
-// w = sqrt(1.0 - dd * dd);
+ /* Sphere filter */
+// w = sqrt(1.0 - dd * dd);
- /* Sinc^2 filter */
-// w = 3.1415926 * dd;
-// if (w < 1e-9)
-// w = 1e-9;
-// w = sin(w)/w;
-// w = w * w;
+ /* Sinc^2 filter */
+// w = 3.1415926 * dd;
+// if (w < 1e-9)
+// w = 1e-9;
+// w = sin(w)/w;
+// w = w * w;
- /* Save weighting */
- smp[ix].nd[smp[ix].nnd].w = w; /* Will be normalized to sum to 1.0 */
+ smp[ix].nd[smp[ix].nnd].w = w; /* Will be normalized to sum to 1.0 */
-// /* Sphere filter for depth */
-// w = sqrt(1.0 - dd * dd);
+// /* Sphere filter for depth */
+// w = sqrt(1.0 - dd * dd);
- /* Cubic spline filter for depth (default) */
-// w = 1.0 - dd;
-// w = w * w * (3.0 - 2.0 * w);
+ /* Cubic spline filter for depth */
+// w = 1.0 - dd;
+// w = w * w * (3.0 - 2.0 * w);
-// /* Gaussian filter for depth */
-// w = exp(-9.0 * dd/2.0);
+ /* Gaussian filter for depth (default) */
+ w = exp(-9.0 * dd/2.0);
- /* Save weighting */
- smp[ix].nd[smp[ix].nnd].rw = w; /* Won't be normalized */
+ smp[ix].nd[smp[ix].nnd].rw = w; /* Won't be normalized */
//printf("~1 adding %d at %f %f %f, rad %f L %f, w %f dir.\n",i, smp[i].sv[0], smp[i].sv[1], smp[i].sv[2],sqrt(dd),tv[0],smp[ix].nd[smp[ix].nnd].w);
- smp[ix].nnd++;
- }
+ smp[ix].nnd++;
}
- /* Increase radius in case we haven't found enough neighbors */
- rrdl /= 1.5;
- rrdh /= 1.5;
}
-
-//if (smp[ix].nnd < 8) printf("~1 point %d has %d neighbors\n",ix,smp[ix].nnd);
-
if (smp[ix].nnd < minnd)
minnd = smp[ix].nnd;
avgnd += (double)smp[ix].nnd;
-//printf("~1 total of %d dir neigbours after try %d\n",smp[ix].nnd, sit);
+//printf("~1 total of %d dir neigbours\n\n",smp[ix].nnd);
+
}
avgnd /= (double)nmpts;
@@ -2311,44 +2233,16 @@ datao map_oh
for (j = 0; j < smp[i].nnd; j++) {
smp[i].nd[j].w /= tw;
}
- }
- }
-
-#ifdef SHOW_NEIGB
- {
- vrml *wrl = NULL;
- double yellow[3] = { 1.0, 1.0, 0.0 };
- double red[3] = { 1.0, 0.0, 0.0 };
- double green[3] = { 0.0, 1.0, 0.0 };
- double magenta[3] = { 1.0, 0.0, 1.0 };
- double pp[3];
- for (i = 0; i < nmpts; i++) {
-
- if ((wrl = new_vrml("neigb", 1, vrml_lab)) == NULL)
- error("New %s failed for '%s%s'",vrml_format(),"neigb",vrml_ext());
- for (j = 0; j < smp[i].nnd; j++) {
- if (smp[i].nd[j].n == &smp[i])
- continue;
- wrl->add_col_vertex(wrl, 0, smp[i].sv, yellow);
- wrl->add_col_vertex(wrl, 0, smp[i].nd[j].n->sv, yellow);
- }
- wrl->make_lines(wrl, 0, 2);
-
- wrl->add_marker(wrl, smp[i].sv, red, 0.5);
-
- wrl->del(wrl);
- printf("Waiting for input after writing 'neigb%s' for point %d:\n",vrml_ext(),i);
- getchar();
}
}
-#endif /* SHOW_NEIGB */
#ifdef SHOW_NEIGB_WEIGHTS
{
vrml *wrl = NULL;
double yellow[3] = { 1.0, 1.0, 0.0 };
double red[3] = { 1.0, 0.0, 0.0 };
+ double green[3] = { 0.0, 1.0, 0.0 };
double pp[3];
for (i = 0; i < nmpts; i++) {
@@ -2364,7 +2258,7 @@ datao map_oh
}
for (j = 0; j < smp[i].nnd; j++) {
wrl->add_col_vertex(wrl, 0, smp[i].sgam->cent, smp[i].nd[j].n == &smp[i] ? red : yellow);
- icmNormalize33(pp, smp[i].nd[j].n->sv, smp[i].sgam->cent, smp[i].nd[j].w * 50.0/maxw);
+ icmNormalize33(pp, smp[i].nd[j].n->_sv, smp[i].sgam->cent, smp[i].nd[j].w * 50.0/maxw);
wrl->add_col_vertex(wrl, 0, pp, smp[i].nd[j].n == &smp[i] ? red : yellow);
}
wrl->make_lines(wrl, 0, 2);
@@ -2421,8 +2315,6 @@ datao map_oh
smp[i].sv[1] = smp[i].drv[1];
smp[i].sv[2] = smp[i].drv[2];
}
- opts.wngam = smp[i].dgam; /* Nearest to dgam */
- opts.wn = smp[i].sv; /* minimize optfunc1 sv -> dgam */
/* Convert our start value from 3D to 2D for speed. */
icmMul3By3x4(iv, smp[i].m2d, smp[i].dv);
@@ -2458,10 +2350,10 @@ datao map_oh
nv[1] = iv[1] = iv[2];
powell(NULL, 2, nv, s, 0.01, 1000, optfunc1, (void *)(&opts), NULL, NULL);
#endif
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
@@ -2499,12 +2391,14 @@ datao map_oh
smp[i].aodv[2] = smp[i].drv[2];
}
}
+ if (verb) {
+ printf("."); fflush(stdout);
+ }
}
- VA(("Locating weighted mapping vectors without smoothing\n"));
-
+ VA(("Locating weighted mapping vectors without smoothing:\n"));
/* Second pass to locate the optimized overall weighted point nrdv[], */
- /* which is a balance of absolute error, radial error, depth room weighting */
+ /* not counting relative error. */
{
double s[2] = { 20.0, 20.0 }; /* 2D search area */
double iv[3]; /* Initial start value */
@@ -2561,10 +2455,10 @@ datao map_oh
nv[1] = iv[1] = iv[2];
powell(NULL, 2, nv, s, 0.01, 1000, optfunc2, (void *)(&opts), NULL, NULL);
#endif
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
@@ -2579,90 +2473,37 @@ datao map_oh
/* Remap it to the destinaton gamut surface */
smp[i].dgam->radial(smp[i].dgam, tp, tp);
- icmCpy3(smp[i].dv, tp); /* Default current solution */
icmCpy3(smp[i].nrdv, tp); /* Non smoothed result */
icmCpy3(smp[i].anv, tp); /* Starting point for smoothing */
+ icmCpy3(smp[i].dv, tp); /* Default current solution */
smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
//printf("~1 %d: dv %f %f %f\n", i, smp[i].dv[0], smp[i].dv[1], smp[i].dv[2]);
}
- }
-
- /* Make sure the input and output ranges encompas the points */
- for (i = 0; i < nmpts; i++) {
- for (j = 0; j < 3; j++) {
- if (smp[i]._sv[j] < map_il[j])
- map_il[j] = smp[i]._sv[j];;
- if (smp[i]._sv[j] > map_ih[j])
- map_ih[j] = smp[i]._sv[j];
-
- if (smp[i].sv[j] < map_il[j])
- map_il[j] = smp[i].sv[j];;
- if (smp[i].sv[j] > map_ih[j])
- map_ih[j] = smp[i].sv[j];
-
- if (smp[i].dv[j] < map_ol[j])
- map_ol[j] = smp[i].dv[j];;
- if (smp[i].dv[j] > map_oh[j])
- map_oh[j] = smp[i].dv[j];
- }
- }
-
-#ifdef NEVER
- if (verb) {
- printf("Input bounding box:\n");
- printf(" %f -> %f, %f -> %f, %f -> %f\n",
- map_il[0], map_ih[0], map_il[1], map_ih[1], map_il[2], map_ih[2]);
- }
-#endif
-
- /* Expand the bounding box by gexp so that our surface grid points */
- /* establish the extrapolation behaviour. Ensure that boundary */
- /* lands on the new grid though. */
- {
- double scale;
-
- dmapres = (int)(((mapres-1) - (mapres-1)/gexp)/2.0 + 0.5);
- if (dmapres < 1)
- dmapres = 1;
-
- scale = (double)(mapres-1-dmapres)/(double)(mapres-1 - 2 * dmapres);
-
- for (j = 0; j < 3; j++) {
- double low, high;
- high = map_ih[j];
- low = map_il[j];
- map_ih[j] = (scale * (high - low)) + low;
- map_il[j] = (scale * (low - high)) + high;
- }
-#ifdef NEVER
if (verb) {
- printf("After scaling up by %f, input bounding box:\n",scale);
- printf(" %f -> %f, %f -> %f, %f -> %f\n",
- map_il[0], map_ih[0], map_il[1], map_ih[1], map_il[2], map_ih[2]);
+ printf("."); fflush(stdout);
}
-#endif
-
- /* Values for grid surface points */
- hmapres = (mapres+1)/2;
- hdmapres = (dmapres+1)/2;
}
-#if RSPLPASSES > 0 || VECADJPASSES > 0
-
- VA(("Computing fine tuning correction direction:\n"));
-
- /* We need inward pointing correction vectors to be able */
- /* to do clipping and fine tuning. We create a shrunken */
- /* version of the dst_gamut and a mapping based on the */
- /* weighted minimum absolute error metric, and then */
- /* create a rspl to represent that mapping. */
+#ifdef DIAG_POINTS
+ /* Show just the closest vectors etc. */
+ for (i = 0; i < nmpts; i++) { /* Move all the points */
+// icmCpy3(smp[i].dv, smp[i].drv); /* Radial */
+ icmCpy3(smp[i].dv, smp[i].aodv); /* Nearest */
+// icmCpy3(smp[i].dv, smp[i].nrdv); /* No smoothed weighted */
+// icmCpy3(smp[i].dv, smp[i].dv); /* pre-filter smooothed */
+ smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
+ }
+#else
+ /* The smoothed direction and raw depth is a single pass, */
+ /* but we use multiple passes to determine the extra depth that */
+ /* needs to be added so that the smoothed result lies within */
+ /* the destination gamut. */
- /* This sort of clipping direction helps preserve the */
- /* mapping shape (hence smoothness), while minimizing the */
- /* loss of saturation and change in dest. mapping location. */
+#if VECADJPASSES > 0 || RSPLPASSES > 0
+ /* We will need inward pointing correction vectors */
{
- gamut *shgam; /* Shrunken dst_gam */
+ gamut *shgam; /* Shrunken di_gam */
double cusps[6][3];
double wp[3], bp[3], kp[3];
double p[3], p2[3], rad;
@@ -2682,13 +2523,14 @@ datao map_oh
double avgdev[MXDO];
/* Create a gamut that is a shrunk version of the destination */
- if ((shgam = new_gamut(dst_gam->getsres(dst_gam), dst_gam->getisjab(dst_gam),
- dst_gam->getisrast(dst_gam))) == NULL) {
+
+ if ((shgam = new_gamut(di_gam->getsres(di_gam), di_gam->getisjab(di_gam),
+ di_gam->getisrast(di_gam))) == NULL) {
fprintf(stderr, "new_gamut failed\n");
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
@@ -2700,14 +2542,14 @@ datao map_oh
for (i = 0;;) {
double len;
- if ((i = dst_gam->getrawvert(dst_gam, p, i)) < 0)
+ if ((i = di_gam->getrawvert(di_gam, p, i)) < 0)
break;
doshrink(&opts, p, p, SHRINK);
shgam->expand(shgam, p);
}
/* Translate cusps */
- if (dst_gam->getcusps(dst_gam, cusps) == 0) {
+ if (di_gam->getcusps(di_gam, cusps) == 0) {
shgam->setcusps(shgam, 0, NULL);
for (i = 0; i < 6; i++) {
doshrink(&opts, p, cusps[i], SHRINK);
@@ -2716,7 +2558,7 @@ datao map_oh
shgam->setcusps(shgam, 2, NULL);
}
/* Translate white and black points */
- if (dst_gam->getwb(dst_gam, wp, bp, kp, NULL, NULL, NULL) == 0) {
+ if (di_gam->getwb(di_gam, wp, bp, kp, NULL, NULL, NULL) == 0) {
doshrink(&opts, wp, wp, SHRINK);
doshrink(&opts, bp, bp, SHRINK);
doshrink(&opts, kp, kp, SHRINK);
@@ -2726,10 +2568,10 @@ datao map_oh
if ((gpnts = (cow *)malloc(nmpts * sizeof(cow))) == NULL) {
fprintf(stderr,"gamut map: Malloc of near smooth points failed\n");
shgam->del(shgam);
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
@@ -2737,7 +2579,7 @@ datao map_oh
/* Now locate the closest points on the shrunken gamut */
/* and set them up for creating a rspl */
- opts.wngam = shgam;
+ opts.shgam = shgam;
for (i = 0; i < nmpts; i++) { /* Move all the points */
gtri *ctri = NULL;
double tmp[3];
@@ -2749,10 +2591,9 @@ datao map_oh
opts.pass = 0; /* Itteration pass */
opts.ix = i; /* Point to optimise */
opts.p = &smp[i];
- opts.wn = smp[i].dv; /* minimize optfunc1a dv -> shgam */
/* Convert our start value from 3D to 2D for speed. */
- icmMul3By3x4(iv, smp[i].m2d, smp[i].nrdv);
+ icmMul3By3x4(iv, smp[i].m2d, smp[i].dv);
nv[0] = iv[0] = iv[1];
nv[1] = iv[1] = iv[2];
@@ -2778,16 +2619,16 @@ datao map_oh
#ifdef DEBUG_POWELL_FAILS
/* Optimise the point with debug on */
opts.debug = 1;
- icmMul3By3x4(iv, smp[i].m2d, smp[i].nrdv);
+ icmMul3By3x4(iv, smp[i].m2d, smp[i].dv);
nv[0] = iv[0] = iv[1];
nv[1] = iv[1] = iv[2];
powell(NULL, 2, nv, s, 0.01, 1000, optfunc1a, (void *)(&opts), NULL, NULL);
#endif
shgam->del(shgam); /* Done with this */
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
@@ -2803,11 +2644,12 @@ datao map_oh
shgam->radial(shgam, tp, tp);
/* Compute mapping vector from dst to shdst */
- icmSub3(smp[i].temp, tp, smp[i].nrdv);
+ icmSub3(smp[i].temp, tp, smp[i].dv);
+
/* In case shrunk vector is very short, add a small part */
/* of the nearest normal. */
- smp[i].dgam->nearest_tri(smp[i].dgam, NULL, smp[i].nrdv, &ctri);
+ smp[i].dgam->nearest_tri(smp[i].dgam, NULL, smp[i].dv, &ctri);
icmScale3(tmp, ctri->pe, 0.1); /* Scale to small inwards */
icmAdd3(smp[i].temp, smp[i].temp, tmp);
@@ -2815,12 +2657,13 @@ datao map_oh
icmNormalize3(smp[i].temp, smp[i].temp, 1.0);
/* Place it in rspl setup array */
- icmCpy3(gpnts[i].p, smp[i].nrdv);
+ icmCpy3(gpnts[i].p, smp[i].dv);
icmCpy3(gpnts[i].v, smp[i].temp);
gpnts[i].w = 1.0;
}
for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+// gres[j] = (mapres+1)/2; /* Half resolution */
gres[j] = mapres; /* Full resolution */
avgdev[j] = GAMMAP_RSPLAVGDEV;
}
@@ -2829,6 +2672,7 @@ datao map_oh
evectmap->fit_rspl_w(evectmap, GAMMAP_RSPLFLAGS, gpnts, nmpts,
map_il, map_ih, gres, map_ol, map_oh, 1.0, avgdev, NULL);
+// ~~999
#ifdef PLOT_EVECTS /* Create VRML of error correction vectors */
{
vrml *wrl = NULL;
@@ -2846,7 +2690,7 @@ datao map_oh
printf("###### gamut/nearsmth.c: writing diagnostic evects%s\n",vrml_ext());
if ((wrl = new_vrml("evects", doaxes, vrml_lab)) == NULL)
error("new_vrml failed for '%s%s'","evects",vrml_ext());
- wrl->make_gamut_surface_2(wrl, dst_gam, 0.6, 0, cc);
+ wrl->make_gamut_surface_2(wrl, di_gam, 0.6, 0, cc);
cc[0] = -1.0;
wrl->make_gamut_surface(wrl, shgam, 0.2, cc);
@@ -2854,16 +2698,16 @@ datao map_oh
wrl->start_line_set(wrl, 0);
for (i = 0; i < nmpts; i++) {
- wrl->add_col_vertex(wrl, 0, smp[i].nrdv, red);
+ wrl->add_col_vertex(wrl, 0, smp[i].dv, red);
#ifdef NEVER /* Plot created vectors */
icmScale3(tmp, smp[i].temp, 4.0);
- icmSub3(tmp, smp[i].nrdv, tmp);
+ icmSub3(tmp, smp[i].dv, tmp);
#else
/* Plot interpolated vectors */
- icmCpy3(cp.p, smp[i].nrdv);
+ icmCpy3(cp.p, smp[i].dv);
evectmap->interp(evectmap, &cp);
icmScale3(tmp, cp.v, 4.0);
- icmSub3(tmp, smp[i].nrdv, tmp);
+ icmSub3(tmp, smp[i].dv, tmp);
#endif
wrl->add_col_vertex(wrl, 0, tmp, green);
}
@@ -2874,265 +2718,267 @@ datao map_oh
shgam->del(shgam); /* Done with this */
free(gpnts);
}
+#endif /* VECADJPASSES > 0 || RSPLPASSES > 0 */
-#endif /* RSPLPASSES > 0 */
+#ifdef VECSMOOTHING
+ VA(("Smoothing guide vectors:\n"));
+
+ /* Compute the neighbourhood smoothed anv[] from dv[] */
+ for (i = 0; i < nmpts; i++) {
+ double anv[3]; /* new anv[] */
+ double tmp[3];
+
+ /* Compute filtered value */
+ anv[0] = anv[1] = anv[2] = 0.0;
+ for (j = 0; j < smp[i].nnd; j++) {
+ nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
+ double nw = smp[i].nd[j].w; /* Weight */
+ double tmp[3];
+
+ icmSub3(tmp, smp[i].sv, np->sv); /* Vector from neighbour src to src */
+ icmAdd3(tmp, tmp, np->dv); /* Neigbour dst + vector */
+
+ icmScale3(tmp, tmp, nw); /* weight for filter */
+ icmAdd3(anv, anv, tmp); /* sum filtered value */
+ }
+
+ /* Blend to un-smoothed value on neutral axis */
+ icmBlend3(anv, smp[i].dv, anv, smp[i].naxbf);
+
+ icmCpy3(smp[i].dv, anv);
+ icmCpy3(smp[i].anv, anv);
+ smp[i].rext = 0.0; /* No correction */
+ }
#if VECADJPASSES > 0
/* Fine tune vectors to compensate for side effects of vector smoothing */
- /* Lookup correction vectors */
- VA(("Smoothing guide vectors:\n"));
- {
- int pncliped = nmpts;
- double delta;
+ VA(("Fine tuning out of gamut guide vectors:\n"));
+
+ /* Loopkup correction vectors */
+ VA(("Computing fine tuning direction:\n"));
+ for (i = 0; i < nmpts; i++) {
+ co cp;
+ double nd, id, tmp[3];
+
+ icmCpy3(cp.p, smp[i].dv);
+ evectmap->interp(evectmap, &cp);
+ icmNormalize3(smp[i].evect, cp.v, 1.0);
+
+ /* ~~99 ?? should we deal with white & black direction here ?? */
+
+ /* Use closest as a default */
+ smp[i].dgam->nearest(smp[i].dgam, smp[i].tdst, smp[i].dv);
+ nd = icmNorm33(smp[i].tdst, smp[i].dv); /* Dist to nearest */
- /* Compute the source to destination neighborhood scale factors */
+ /* Compute intersection with dest gamut as tdst */
+ if (!vintersect2(smp[i].dgam, NULL, tmp, smp[i].evect, smp[i].dv)) {
+ /* Got an intersection */
+ id = icmNorm33(tmp, smp[i].dv); /* Dist to intersection */
+ if (id <= (nd + 5.0)) /* And it seems sane */
+ icmCpy3(smp[i].tdst, tmp);
+ }
+
+ smp[i].rext = 0.0;
+ }
+
+ VA(("Fine tuning guide vectors:\n"));
+ for (it = 0; it < VECADJPASSES; it++) {
+ double avgog = 0.0, maxog = 0.0, nog = 0.0;
+ double avgig = 0.0, maxig = 0.0, nig = 0.0;
+
+ /* Filter the level of out/in gamut, and apply correction vector */
for (i = 0; i < nmpts; i++) {
- double tmp[3];
- double sav[3], dav[3]; /* Average center locations */
- double sdev[3], ddev[3]; /* Average devation in each direction from center */
- double scev, dcev; /* Average spherical deviation */
+ double cvec[3], clen;
+ double minext = 1e80;
+ double maxext = -1e80; /* Max weighted depth extension */
+ double dext, gain;
- for (j = 0; j < 3; j++)
- sav[j] = dav[j] = sdev[j] = ddev[j] = 0.0;
- scev = dcev = 0.0;
+ minext = -20.0;
- /* Compute center average values */
- for (j = 0; j < smp[i].nnd; j++) {
- nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
- double nw = smp[i].nd[j].w; /* Weight */
-
- icmScale3(tmp, np->sv, nw);
- icmAdd3(sav, sav, tmp);
- icmScale3(tmp, np->dv, nw);
- icmAdd3(dav, dav, tmp);
- }
-
- /* Compute average deviation in each direction */
+ /* Compute filtered value */
for (j = 0; j < smp[i].nnd; j++) {
nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
- double nw = smp[i].nd[j].w; /* Weight */
- double tt;
-
- icmSub3(tmp, sav, np->sv);
- icmAbs3(tmp, tmp);
- icmScale3(tmp, tmp, nw);
- icmAdd3(sdev, sdev, tmp);
-
- tt = icmNorm33(sav, np->sv);
- tt *= nw;
- scev += tt;
-
- icmSub3(tmp, dav, np->dv);
- icmAbs3(tmp, tmp);
- icmScale3(tmp, tmp, nw);
- icmAdd3(ddev, ddev, tmp);
-
- tt = icmNorm33(dav, np->dv);
- tt *= nw;
- dcev += tt;
- }
-
-//printf("~1 %d: sdev %f %f %f, scev %f\n",i,sdev[0],sdev[1],sdev[2],scev);
-//printf("~1 %d: ddev %f %f %f, dcev %f\n",i,ddev[0],ddev[1],ddev[2],dcev);
+ double nw = smp[i].nd[j].rw; /* Weight */
+ double tmpl;
- /* Try and protect against silliness */
- if (scev < 1e-3 || dcev < 1e-3)
- scev = dcev = 1e-3;
+ icmSub3(cvec, np->tdst, np->anv); /* Vector needed to target for neighbour */
+ clen = icmDot3(smp[i].evect, cvec); /* Error in this direction */
- for (j = 0; j < 3; j++) {
- if (sdev[j] < 1e-3 || ddev[j] < 1e-3) {
- sdev[j] = scev;
- ddev[j] = dcev;
- }
+ tmpl = nw * (clen - minext); /* Track maximum weighted extra depth */
+ if (tmpl < 0.0)
+ tmpl = 0.0;
+ if (tmpl > maxext)
+ maxext = tmpl;
}
+ maxext += minext;
- /* Compute scale factors */
- icmDiv3(smp[i].nscale, ddev, sdev); /* Scale = ddev/sdev */
-
-#ifdef NEVER
-if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
- || smp[i].nscale[1] > 1.5 || smp[i].nscale[1] < 0.01
- || smp[i].nscale[2] > 1.5 || smp[i].nscale[2] < 0.01) {
- printf("~1 %d: scale factors %f %f %f\n",i,smp[i].nscale[0], smp[i].nscale[1], smp[i].nscale[2]);
- printf("~1 %d: from sdev %f %f %f\n",i,sdev[0], sdev[1], sdev[2]);
- printf("~1 %d: from ddev %f %f %f\n",i,ddev[0], ddev[1], ddev[2]);
-}
-#endif /* NEVER */
+ if (it == 0)
+ gain = 1.2;
+ else
+ gain = 0.8;
- }
+ /* Accumulate correction with damping */
+ smp[i].rext += gain * maxext;
- /* Itterate smoothing until we're happy */
- for (it = 0; it < VECADJPASSES; it++) {
- int ncliped = 0;
- double maxclipby = 0.0;
- double avgclipby = 0.0;
-
- /* Compute the neighbourhood smoothed anv[] from dv[] */
- for (i = 0; i < nmpts; i++) {
- double sav[3], dav[3]; /* Average locations */
- double tmp[3], c1[3], c2[3];
- double rdsm;
-
- /* Compute average values */
- sav[0] = sav[1] = sav[2] = 0.0;
- dav[0] = dav[1] = dav[2] = 0.0;
- for (j = 0; j < smp[i].nnd; j++) {
- nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
- double nw = smp[i].nd[j].w; /* Weight */
-
- icmScale3(tmp, np->sv, nw); /* weight for filter */
- icmAdd3(sav, sav, tmp); /* sum filtered value */
-
- /* weight for filter */
- tmp[0] = nw * np->dv[0]; /* Don't itterate J */
- tmp[1] = nw * np->anv[1];
- tmp[2] = nw * np->anv[2];
- icmAdd3(dav, dav, tmp); /* sum filtered value */
- }
-
- /* Compute filtered value with source to dest scaling */
- icmSub3(tmp, smp[i].sv, sav); /* Vector from average to src */
- icmMul3(tmp, tmp, smp[i].nscale); /* Scale */
- icmAdd3(tmp, tmp, dav); /* average dst + vector */
+ /* Error for just this point */
+ icmSub3(cvec, smp[i].tdst, smp[i].anv);
+ clen = icmDot3(smp[i].evect, cvec);
- rdsm = 1.0 - sqrt(smp[i].wt.r.dsm); /* To degree of blending with unchanged */
+ /* Blend to individual correction on neutral axis */
+ dext = smp[i].naxbf * smp[i].rext + (1.0 - smp[i].naxbf) * clen;
- icmBlend3(tmp, tmp, smp[i].dv, rdsm); /* Less than full imprint */
-
-#if VECADJPASSES > 1
- /* Clip to gamut */
- if (dc_gam->nradial(dc_gam, c1, tmp) > (1.0 + 1e-6)) {
- co cp;
- double cvec[3];
-
- /* Lookup "shrunk gamut" cliping direction */
- icmCpy3(cp.p, tmp);
- evectmap->interp(evectmap, &cp);
- icmNormalize3(cvec, cp.v, 1.0);
-
- if (!vintersect2(dc_gam, NULL, c2, cvec, tmp)) { /* Got an intersection */
- double id;
-
-//printf("~1 clipped %f %f %f -> %f %f %f\n", tmp[0], tmp[1], tmp[2], c2[0], c2[1], c2[2]);
- id = icmNorm33(c2, tmp); /* Dist to intersection */
- icmCpy3(tmp, c2);
-
- ncliped++;
- if(id > maxclipby)
- maxclipby = id;
- avgclipby += id;
- } else {
-//printf("~1 rclipped %f %f %f -> %f %f %f\n", tmp[0], tmp[1], tmp[2], c1[0], c1[1], c1[2]);
- icmCpy3(tmp, c1); /* Use radial clip */
- }
- }
-#endif
-
- /* Blend to un-smoothed value on neutral axis */
- icmBlend3(tmp, smp[i].dv, tmp, smp[i].naxbf);
-
- /* Updated value for next itteration */
- icmCpy3(smp[i].anv, tmp);
- }
+ /* Apply integrated correction */
+ icmScale3(cvec, smp[i].evect, dext);
+ icmAdd3(smp[i].anv, smp[i].dv, cvec);
- if (ncliped > 0)
- avgclipby /= (double)ncliped;
+ if (clen > 0.0) { /* Compression */
+ if (clen > maxog)
+ maxog = clen;
+ avgog += clen;
+ nog++;
- delta = (pncliped - ncliped)/(double)nmpts;
-
- if (verb) {
- printf("It %d: No clip %d/%d delta %f max by %f, avg by %f\n",it,ncliped, nmpts+1, delta, maxclipby, avgclipby);
+ } else { /* Expansion */
+ if (-clen > maxig)
+ maxig = -clen;
+ avgig += -clen;
+ nig++;
}
- pncliped = ncliped;
- }
-
- /* Copy final results */
- for (i = 0; i < nmpts; i++) {
- icmCpy3(smp[i].dv, smp[i].anv);
- smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
}
+ if (verb)
+ printf("No og %4.0f max %f avg %f, No ig %4.0f max %f avg %f\n",
+ nog,maxog,nog > 1 ? avgog/nog : 0.0, nig,maxig,nig > 1 ? avgig/nig : 0.0);
}
-#endif /* VECADJPASSES > 0 */
-
-#ifdef DIAG_POINTS
- /* Show just the closest vectors etc. */
- for (i = 0; i < nmpts; i++) { /* Move all the points */
-// icmCpy3(smp[i].dv, smp[i].drv); /* Radial */
- icmCpy3(smp[i].dv, smp[i].aodv); /* Nearest */
-// icmCpy3(smp[i].dv, smp[i].nrdv); /* No smoothed weighted */
- smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent); /* Vector smoothed */
+ /* Copy final results */
+ for (i = 0; i < nmpts; i++) {
+ icmCpy3(smp[i].dv, smp[i].anv);
+ smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
}
-#else
- /* The smoothed direction and raw depth is a single pass, */
- /* but we use multiple passes to determine the extra depth that */
- /* needs to be added so that the smoothed result lies within */
- /* the destination gamut. */
-#if RSPLPASSES > 0
+ if (verb) {
+ double avgog = 0.0, maxog = 0.0, nog = 0.0;
+ double avgig = 0.0, maxig = 0.0, nig = 0.0;
- VA(("Fine tuning vectors to allow for rspl smoothing:\n"));
+ /* Check the result */
+ for (i = 0; i < nmpts; i++) {
+ double cvec[3], clen;
+
+ /* Error for just this point, for stats */
+ icmSub3(cvec, smp[i].tdst, smp[i].anv);
+ clen = icmDot3(smp[i].evect, cvec);
+
+ if (clen > 0.0) { /* Compression */
+ if (clen > maxog)
+ maxog = clen;
+ avgog += clen;
+ nog++;
+
+ } else { /* Expansion */
+ if (-clen > maxig)
+ maxig = -clen;
+ avgig += -clen;
+ nig++;
+ }
+ }
+ printf("No og %4.0f max %f avg %f, No ig %4.0f max %f avg %f\n",
+ nog,maxog,nog > 1 ? avgog/nog : 0.0, nig,maxig,nig > 1 ? avgig/nig : 0.0);
+ }
+#endif /* VECADJUST */
+#endif /* VECADJPASSES > 0 */
+#if RSPLPASSES > 0
/* We need to adjust the vectors with extra depth to compensate for */
/* for the effect of rspl smoothing. */
{
cow *gpnts = NULL; /* Mapping points to create 3D -> 3D mapping */
rspl *map = NULL; /* Test map */
+ datai il, ih;
+ datao ol, oh;
int gres[MXDI];
double avgdev[MXDO];
double icgain, ixgain; /* Initial compression, expansion gain */
double fcgain, fxgain; /* Final compression, expansion gain */
+ VA(("Fine tuning vectors to allow for rspl smoothing:\n"));
+
+ for (j = 0; j < 3; j++) { /* Copy ranges */
+ il[j] = map_il[j];
+ ih[j] = map_ih[j];
+ ol[j] = map_ol[j];
+ oh[j] = map_oh[j];
+ }
+
+ /* Adjust the input ranges for guide vectors */
+ for (i = 0; i < nmpts; i++) {
+ for (j = 0; j < 3; j++) {
+ if (smp[i]._sv[j] < il[j])
+ il[j] = smp[i]._sv[j];
+ if (smp[i]._sv[j] > ih[j])
+ ih[j] = smp[i]._sv[j];
+ }
+ }
+
+ /* Now expand the bounding box by aprox 5% margin, but scale grid res */
+ /* to match, so that the natural or given boundary still lies on the grid. */
+ /* (This duplicates code in gammap applied after near_smooth() returns) */
+ /* (We are assuming that our changes to the giude vectprs won't expand the ranges) */
+ {
+ int xmapres;
+ double scale;
+
+ xmapres = (int) ((mapres-1) * 0.05 + 0.5);
+ if (xmapres < 1)
+ xmapres = 1;
+
+ scale = (double)(mapres-1 + xmapres)/(double)(mapres-1);
+
+ for (j = 0; j < 3; j++) {
+ double low, high;
+ high = ih[j];
+ low = il[j];
+ ih[j] = (scale * (high - low)) + low;
+ il[j] = (scale * (low - high)) + high;
+ }
+
+ mapres += 2 * xmapres;
+ }
+
if ((gpnts = (cow *)malloc(nmpts * sizeof(cow))) == NULL) {
fprintf(stderr,"gamut map: Malloc of near smooth points failed\n");
if (evectmap != NULL)
evectmap->del(evectmap);
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
free_nearsmth(smp, nmpts);
*npp = 0;
return NULL;
}
- /* Lookup correction vectors */
- VA(("Computing fine tuning target for vectors:\n"));
+ /* Loopkup correction vectors */
+ VA(("Computing fine tuning direction for vectors:\n"));
for (i = 0; i < nmpts; i++) {
+ co cp;
double nd, id, tmp[3];
- /* If the sv and dv are within dc_gam, then this point doesn't need */
- /* to be fine tuned to make it land on the gamut surface - this point */
- /* either doesn't need gamut mapping, or is being expanded, in which */
- /* case we prioritize smoothness over exactly hitting the expansion */
- /* target */
- if (dc_gam->nradial(dc_gam, NULL, smp[i].sv) <= (1.0 + 1e-6)
- && dc_gam->nradial(dc_gam, NULL, smp[i].dv) <= (1.0 + 1e-6)) {
- icmCpy3(smp[i].tdst, smp[i].dv); /* Target is where we are */
- smp[i].nott = 1;
-
- } else {
- co cp;
- double evect[3];
-
- /* Lookup fine tuning vector direction for current location */
- icmCpy3(cp.p, smp[i].dv);
- evectmap->interp(evectmap, &cp);
- icmNormalize3(evect, cp.v, 1.0);
-
- /* Use closest as a default */
- smp[i].dgam->nearest(smp[i].dgam, smp[i].tdst, smp[i].dv);
- nd = icmNorm33(smp[i].tdst, smp[i].dv); /* Dist to nearest */
-
- /* Compute intersection with dest gamut as tdst */
- if (!vintersect2(smp[i].dgam, NULL, tmp, evect, smp[i].dv)) {
- /* Got an intersection */
- id = icmNorm33(tmp, smp[i].dv); /* Dist to intersection */
- if (id <= (nd + 5.0)) /* And it seems sane */
- icmCpy3(smp[i].tdst, tmp);
- }
- smp[i].nott = 0;
+ icmCpy3(cp.p, smp[i].dv);
+ evectmap->interp(evectmap, &cp);
+ icmNormalize3(smp[i].evect, cp.v, 1.0);
+
+ /* ~~99 ?? should we deal with white & black direction here ?? */
+
+ /* Use closest as a default */
+ smp[i].dgam->nearest(smp[i].dgam, smp[i].tdst, smp[i].dv);
+ nd = icmNorm33(smp[i].tdst, smp[i].dv); /* Dist to nearest */
+
+ /* Compute intersection with dest gamut as tdst */
+ if (!vintersect2(smp[i].dgam, NULL, tmp, smp[i].evect, smp[i].dv)) {
+ /* Got an intersection */
+ id = icmNorm33(tmp, smp[i].dv); /* Dist to intersection */
+ if (id <= (nd + 5.0)) /* And it seems sane */
+ icmCpy3(smp[i].tdst, tmp);
}
smp[i].coff[0] = smp[i].coff[1] = smp[i].coff[2] = 0.0;
@@ -3150,8 +2996,6 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
double avgrext = 0.0;
double ovlen;
- VA(("it %d: Creating rspl\n",it));
-
/* Setup the rspl guide points for creating rspl */
for (i = 0; i < nmpts; i++) {
icmCpy3(gpnts[i].p, smp[i]._sv); /* The orgininal src point */
@@ -3160,14 +3004,13 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
}
for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+// gres[j] = (mapres+1)/2; /* Half resolution for speed */
gres[j] = mapres; /* Full resolution */
avgdev[j] = GAMMAP_RSPLAVGDEV;
}
map = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
map->fit_rspl_w(map, GAMMAP_RSPLFLAGS, gpnts, nmpts,
- map_il, map_ih, gres, map_ol, map_oh, mapsmooth, avgdev, NULL);
-
- VA(("it %d: Evaluate mapping\n",it));
+ il, ih, gres, ol, oh, mapsmooth, avgdev, NULL);
/* See what the source actually maps to via rspl, and how far from */
/* the target point they are. */
@@ -3179,20 +3022,12 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
icmCpy3(cp.p, smp[i]._sv);
map->interp(map, &cp);
icmCpy3(smp[i].temp, cp.v);
-
- /* Lookup fine tuning vector direction for that value. */
- /* (evect[] is then used in the local correction loop below) */
- icmCpy3(cp.p, smp[i].temp);
- evectmap->interp(evectmap, &cp);
- icmNormalize3(smp[i].evect, cp.v, 1.0);
-
+
/* Compute the correction needed and it's signed length */
icmSub3(cvec, smp[i].tdst, smp[i].temp);
smp[i].clen = icmDot3(smp[i].evect, cvec);
}
- VA(("it %d: Compute correction vectors\n",it));
-
/* Compute local correction */
for (i = 0; i < nmpts; i++) {
double minext = 1e80;
@@ -3202,8 +3037,6 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
double tt;
double cgain, xgain; /* This itters compression, expansion gain */
double gain; /* Gain used */
- co cp;
- double evect[3];
/* See what the worst case is in the local area, and */
/* aim to lower the whole local area by enough to */
@@ -3258,7 +3091,6 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
/* Keep stats of this point */
clen = smp[i].clen;
-
if (clen > 0.0) {
if (clen > maxog)
maxog = clen;
@@ -3283,32 +3115,20 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
gpnts[i].w = 1.0;
}
- if ((it+1) < RSPLPASSES || !surfpnts)
- map->del(map); /* Not the last pass, or not doing grid surface points */
- else
- lastmap = map; /* Let grid surface creation use this. */
-
- VA(("it %d: Compute correction rspl\n",it));
-
- /* Create rspl of corrections */
for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+// gres[j] = (mapres+1)/2; /* Half resolution */
gres[j] = mapres; /* Full resolution */
avgdev[j] = GAMMAP_RSPLAVGDEV;
}
map = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
map->fit_rspl_w(map, GAMMAP_RSPLFLAGS, gpnts, nmpts,
- map_il, map_ih, gres, map_ol, map_oh, 1.0, avgdev, NULL);
-
- VA(("it %d: Apply corrections\n",it));
+ il, ih, gres, ol, oh, 2.0, avgdev, NULL);
/* Lookup the smoothed extension vector for each point and apply it */
for (i = 0; i < nmpts; i++) {
double tt;
co cp;
- if (smp[i].nott) /* Don't alter points within the gamut */
- continue;
-
icmCpy3(cp.p, smp[i].dv);
map->interp(map, &cp);
#ifdef RSPLUSEPOW
@@ -3323,7 +3143,7 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
/* Apply accumulated offset */
icmAdd3(smp[i].anv, smp[i].dv, cp.v);
}
- map->del(map); /* Not the last pass, or not doing grid surface points */
+ map->del(map);
if (verb)
printf("No og %4.0f max %f avg %f, No ig %4.0f max %f avg %f, avg rext %f\n",
@@ -3354,15 +3174,18 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
}
#endif /* RSPLPASSES > 0 */
-#endif /* !DIAG_POINTS */
+#endif /* NEVER (show debug values) */
VA(("Smoothing passes done, doing final houskeeping\n"));
+ if (verb)
+ printf("\n");
+
#if defined(SAVE_VRMLS) && defined(PLOT_MAPPING_INFLUENCE)
- create_influence_plot(smp, nmpts, mapres);
+ create_influence_plot(smp, nmpts);
#endif
- VA(("Restoring non cusp-rotated source points:\n"));
+ VB(("Final guide points:\n"));
/* Restore the actual non cusp rotated source point */
for (i = 0; i < nmpts; i++) {
@@ -3413,7 +3236,7 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
/* Compute actual depth of ray into destination gamut */
/* to determine if this is expansion or contraction. */
- if (dst_gam->vector_isect(dst_gam, smp[i].sv, smp[i].dv,
+ if (di_gam->vector_isect(di_gam, smp[i].sv, smp[i].dv,
minv, maxv, &mint, &maxt, &mintri, &maxtri) != 0) {
double wp[3], bp[3]; /* Gamut white and black points */
double p1, napoint[3] = { 50.0, 0.0, 0.0 }; /* Neutral axis point */
@@ -3426,7 +3249,7 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
/* the guide ray. We use this as a destination direction */
/* if the sub surface ray gets very long, and to compute */
/* a sanity check on the available depth. */
- if (dc_gam->getwb(dc_gam, NULL, NULL, NULL, wp, dst_kbp ? NULL : bp, dst_kbp ? bp : NULL) == 0) {
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, wp, dst_kbp ? NULL : bp, dst_kbp ? bp : NULL) == 0) {
if (icmLineLineClosest(napoint, NULL, &p1, NULL, bp, wp,
smp[i].sv, smp[i].dv) == 0) {
double nalev[3];
@@ -3472,7 +3295,7 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
}
#ifdef VERB
else {
- printf("dc_gam->getwb failed\n");
+ printf("d_gam->getwb failed\n");
}
#endif
@@ -3621,345 +3444,54 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
#ifdef SUBVEC_SMOOTHING
VB(("Smoothing sub-surface guide points:\n"));
- {
- double maxmv = 0.0, avgmv = 0.0, acount = 0.0;
- /* Smooth the sub-surface mapping points */
- for (i = 0; i < nmpts; i++) {
- double sav[3], dav[3]; /* Average locations */
- double scr, dcr; /* Cylindrical radius */
- double scf; /* Scale factor */
- double tmp[3], de;
-
- if (smp[i].vflag == 0)
- continue; /* Sub value not valid */
-
- /* Compute average values */
- sav[0] = sav[1] = sav[2] = 0.0;
- dav[0] = dav[1] = dav[2] = 0.0;
- for (j = 0; j < smp[i].nnd; j++) {
- nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
- double nw = smp[i].nd[j].w; /* Weight */
+ /* Smooth the sub-surface mapping points */
+ /* dv2[] is duplicated in temp[], so use temp[] as the values to be filtered */
+ for (i = 0; i < nmpts; i++) {
+ double tmp[3];
+ double fdv2[3]; /* Filtered dv2[] */
+ double tw; /* Total weight */
+ int rc;
+
+ if (smp[i].vflag == 0)
+ continue;
+
+ /* Compute filtered value */
+ tw = fdv2[0] = fdv2[1] = fdv2[2] = 0.0;
+ for (j = 0; j < smp[i].nnd; j++) {
+ nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
+ double nw = smp[i].nd[j].w; /* Weight */
+ double tmp[3];
- icmScale3(tmp, np->sv2, nw); /* weight for filter */
- icmAdd3(sav, sav, tmp); /* sum filtered value */
+ if (np->vflag) {
+ icmSub3(tmp, smp[i].sv2, np->sv2); /* Vector from neighbour src to src */
+ icmAdd3(tmp, tmp, np->dv2); /* Neigbour dst + vector */
- icmScale3(tmp, np->dv2, nw); /* weight for filter */
- icmAdd3(dav, dav, tmp); /* sum filtered value */
+ icmScale3(tmp, tmp, nw); /* weight for filter */
+ icmAdd3(fdv2, fdv2, tmp); /* sum filtered value */
+ tw += nw;
}
-
- /* We want to transfer the relative location (i.e. detail) from */
- /* the source to destination, but we need to scale the features */
- /* appropriately for the mapping. */
- scr = sqrt(sav[1] * sav[1] + sav[2] * sav[2]);
- dcr = sqrt(dav[1] * dav[1] + dav[2] * dav[2]);
- scf = dcr/scr;
-
- /* Compute filtered value */
- icmSub3(tmp, smp[i].sv2, sav); /* Vector from average to src */
- tmp[1] *= scf; /* Scale */
- tmp[2] *= scf; /* Scale */
- icmAdd3(tmp, tmp, dav); /* average dst + vector */
-
- de = icmNorm33(smp[i].dv2, tmp);
- icmCpy3(smp[i].dv2, tmp);
-
- if (de > maxmv)
- maxmv = de;
- avgmv += de;
- acount++;
-
- VB(("Smthd Src %d = %f %f %f\n",i,smp[i].sv2[0],smp2[i].sv[1],smp2[i].sv2[2]));
- VB(("Smthd Dst %d = %f %f %f\n",i,smp[i].dv2[0],smp2[i].dv[1],smp2[i].dv2[2]));
}
- if (acount > 0)
- avgmv /= acount;
-
- if (verb)
- printf("Sub-surface smoothing changed by max %f, average %f\n",maxmv, avgmv);
+ if (tw > 0.0) {
+//printf("~1 %d: moved %f %f %f -> %f %f %f de %f\n", i, smp[i].dv2[0], smp[i].dv2[1], smp[i].dv2[2], fdv2[0], fdv2[1], fdv2[2], icmNorm33(smp[i].dv2,fdv2));
+ icmScale3(smp[i].dv2, fdv2, 1.0/tw);
+ }
}
#endif /* SUBVEC_SMOOTHING */
VB(("near_smooth is done\n"));
-#ifdef PLOT_SMOOTHING_CHANGE
- /* Plot change in destination point of un-smoothed to smoothed */
- {
- vrml *wrl = NULL;
- int doaxes = 0;
-
-#ifdef PLOT_AXES
- doaxes = 1;
-#endif
- wrl = new_vrml("dst_smvec", doaxes, vrml_lab);
-
- /* Start of guide vector plot */
- wrl->start_line_set(wrl, 0);
-
- for (i = 0; i < nmpts; i++) {
- double red[3] = { 1.0, 0.0, 0.0 };
- double green[3] = { 0.0, 1.0, 0.0 };
-
- wrl->add_col_vertex(wrl, 0, smp[i].nrdv, red);
- wrl->add_col_vertex(wrl, 0, smp[i].dv, green);
- }
- wrl->make_lines(wrl, 0, 2); /* Change vectors */
-
-#ifndef NEVER
- /* Plot un-smoothed src to dst mappings */
- wrl->start_line_set(wrl, 0);
-
- for (i = 0; i < nmpts; i++) {
- double lblue[3] = { 0.4, 0.4, 0.8 };
- double magenta[3] = { 0.8, 0.4, 0.8 };
-
- wrl->add_col_vertex(wrl, 0, smp[i].sv, lblue);
- wrl->add_col_vertex(wrl, 0, smp[i].nrdv, magenta);
- }
- wrl->make_lines(wrl, 0, 2); /* Change vectors */
-#endif
-
-#ifdef NEVER
- /* Plot index numbers */
- for (i = 0; i < nmpts; i++) {
- double cream[3] = { 0.7, 0.7, 0.5 };
- char buf[100];
- sprintf(buf, "%d", i);
- wrl->add_text(wrl, buf, smp[i].dv, cream, 0.5);
- }
-#endif /* NEVER */
-
- /* Write transparent destination space gamut surface */
- dc_gam->write_to_vrml(dc_gam, wrl, 0.5, 0);
-
- /* Write file */
- wrl->del(wrl);
- }
-#endif /* PLOT_SMOOTHING_CHANGE */
-
- /* If grid surface points are requested */
- if (surfpnts) {
- DCOUNT(gc, 3, 3, 0, 0, hmapres);
- double cent[3];
-
- VB(("Adding grid surface points:\n"));
-
- /* If rspl smoothing didn't leave us a map */
- if (lastmap == NULL) {
-
- cow *gpnts = NULL; /* Mapping points to create 3D -> 3D mapping */
- int gres[MXDI];
- double avgdev[MXDO];
-
- VB(("Creating rspl map for grid surface points\n",it));
-
- if ((gpnts = (cow *)malloc(nmpts * sizeof(cow))) == NULL) {
- fprintf(stderr,"gamut map: Malloc of near smooth points failed\n");
- if (evectmap != NULL)
- evectmap->del(evectmap);
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
- free_nearsmth(smp, nmpts);
- *npp = 0;
- return NULL;
- }
-
- /* Setup the rspl guide points for creating rspl */
- for (i = 0; i < nmpts; i++) {
- icmCpy3(gpnts[i].p, smp[i].sv);
- icmCpy3(gpnts[i].v, smp[i].dv);
- gpnts[i].w = 1.0;
- }
-
- for (j = 0; j < 3; j++) { /* Set resolution for all axes */
- gres[j] = mapres; /* Full resolution */
- avgdev[j] = GAMMAP_RSPLAVGDEV;
- }
- lastmap = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
- lastmap->fit_rspl_w(lastmap, GAMMAP_RSPLFLAGS, gpnts, nmpts,
- map_il, map_ih, gres, map_ol, map_oh, mapsmooth, avgdev, NULL);
- free(gpnts);
- }
-
- sc_gam->getcent(dc_gam, cent);
-
- DC_INIT(gc);
- for (;;) {
- /* If point is in the outer two layers of grid */
- if ( gc[0] == 0 || gc[0] == hdmapres
- || gc[0] == (hmapres-1) || gc[0] == (hmapres-1-hdmapres)
- || gc[1] == 0 || gc[1] == hdmapres
- || gc[1] == (hmapres-1) || gc[1] == (hmapres-1-hdmapres)
- || gc[2] == 0 || gc[2] == hdmapres
- || gc[2] == (hmapres-1) || gc[2] == (hmapres-1-hdmapres))
-
- /* Only points around gamut, not on top or underneath */
-/*
- if ( gc[1] == 0 || gc[1] == hdmapres
- || gc[1] == (hmapres-1) || gc[1] == (hmapres-1-hdmapres)
- || gc[2] == 0 || gc[2] == hdmapres
- || gc[2] == (hmapres-1) || gc[2] == (hmapres-1-hdmapres))
-*/
- {
- double grid2gamut, gamut2cent, ww;
- co cp;
-
- if (nmpts >= mxnmpts) {
- warning("nearsmth ran out of space for points");
- break;
- }
- smp[nmpts].uflag = 1;
-
- /* Source location */
- for (j = 0; j < 3; j++)
- smp[nmpts].sv[j] = map_il[j] + gc[j]/(hmapres-1.0) * (map_ih[j] - map_il[j]);
-
- /* If this point is within source gamut, skip it */
- if (sc_gam->nradial(sc_gam, NULL, smp[nmpts].sv) <= (1.0 + 1e-6)) {
-//printf("~1 point %d %d %d = %f %f %f is inside source gamut\n", gc[0], gc[1], gc[2], smp[nmpts].sv[0], smp[nmpts].sv[1], smp[nmpts].sv[2]);
- goto next_point;
- }
-#ifdef NEVER
- /* Clip the point to the closest location on the source */
- /* colorspace gamut. */
- sc_gam->nearest(sc_gam, cp.p, smp[nmpts].sv);
-#else
- /* Map grid point to weighted nearest on source space gamut */
- {
- double ta[3] = { 50.0, 0.0, 0.0 };
- double tc[3] = { 0.0, 0.0, 0.0 };
- double s[2] = { 20.0, 20.0 }; /* 2D search area */
- double nv[2]; /* 2D New value */
- double tp[3]; /* Resultint value */
- double ne; /* New error */
- int notrials = NO_TRIALS;
- double bnv[3]; /* Best 3d value */
- double brv; /* Best return value */
- int trial;
- double mv;
-
- /* Determine the parameter weighting at this location */
- opts.pass = 0; /* Itteration pass */
- opts.ix = nmpts;
- opts.p = &smp[nmpts];
- opts.wngam = sc_gam; /* Optimise to source colorspace gamut */
- opts.wn = smp[nmpts].sv; /* minimize optfunc1a sv -> sc_gam */
-
- /* Compute weights at this point */
- interp_xweights(sc_gam, &smp[nmpts].wt, smp[nmpts].sv, opts.xwh, &opts, 0);
-
- /* Initial starting point */
- sc_gam->nearest(sc_gam, bnv, smp[nmpts].sv);
-
- /* Do several trials from different starting points to avoid */
- /* any local minima, particularly with nearest mapping. */
- brv = 1e38;
- for (trial = 0; trial < notrials; trial++) {
- double rv; /* Temporary */
-
- /* Setup the 3D -> 2D tangent conversion and inverse for our start point */
- icmVecRotMat(smp[nmpts].m2d, bnv, sc_gam->cent, ta, tc);
- icmVecRotMat(smp[nmpts].m3d, ta, tc, bnv, sc_gam->cent);
-
- /* Convert our start value from 3D to 2D for speed. */
- icmMul3By3x4(tp, smp[nmpts].m2d, bnv);
- nv[0] = tp[1];
- nv[1] = tp[2];
-
- if (trial >= 2) {
- /* Use random offset to avoid local minima */
- nv[0] += d_rand(-20.0, 20.0);
- nv[1] += d_rand(-20.0, 20.0);
- }
-
- /* Optimise the point */
- if (powell(&rv, 2, nv, s, 0.01, 1000, optfunc1a, (void *)(&opts), NULL, NULL) == 0
- && rv < brv) {
- brv = rv;
-//printf("~1 point %d, trial %d, new best %f\n",i,trial,rv);
-
- /* Convert best result 2D -> 3D */
- tp[2] = nv[1];
- tp[1] = nv[0];
- tp[0] = 50.0;
- icmMul3By3x4(tp, smp[nmpts].m3d, tp);
-
- /* Remap it to the source gamut surface */
- sc_gam->radial(sc_gam, bnv, tp);
- }
-//else printf("~1 powell failed with rv = %f\n",rv);
- }
- if (brv == 1e38) { /* We failed to get a result */
- fprintf(stderr, "multiple powells failed to get a result (4)\n");
- sc_gam->nearest(sc_gam, cp.p, smp[nmpts].sv);
-
- } else {
- icmCpy3(cp.p, bnv);
- }
- }
-#endif /* NEVER */
-
-//printf("~1 grid %f %f %f -> src %f %f %f\n", smp[nmpts].sv[0], smp[nmpts].sv[1], smp[nmpts].sv[2], cp.p[0], cp.p[1], cp.p[2]);
-
- /* Then lookup the gamut mapped value */
- lastmap->interp(lastmap, &cp);
-
-//printf("~1 src %f %f %f -> dst %f %f %f\n", cp.p[0], cp.p[1], cp.p[2], cp.v[0], cp.v[1], cp.v[2]);
-
- for (j = 0; j < 3; j++)
- smp[nmpts].dv[j] = cp.v[j];
-
- /* Compute the distance of the grid surface point to the to the */
- /* source colorspace gamut, as well as the distance from there */
- /* to the gamut center point. */
- for (grid2gamut = gamut2cent = 0.0, j = 0; j < 3; j++) {
- double tt;
- tt = smp[nmpts].dv[j] - cp.p[j];
- grid2gamut += tt * tt;
- tt = cp.p[j] - cent[j];
- gamut2cent += tt * tt;
- }
- grid2gamut = sqrt(grid2gamut);
- gamut2cent = sqrt(gamut2cent);
- if (gamut2cent < 0.1)
- gamut2cent = 0.1;
-
- /* Make the weighting inversely related to distance, */
- /* to reduce influence on in gamut mapping shape, */
- /* while retaining some influence at the edge of the */
- /* grid. */
- ww = grid2gamut / gamut2cent;
- if (ww > 1.0)
- ww = 1.0;
-
- /* A low weight seems to be enough ? */
- /* The lower the better in terms of geting best hull mapping fidelity */
- smp[nmpts++].w1 = 0.1 * ww;
- }
- next_point:;
- DC_INC(gc);
- if (DC_DONE(gc))
- break;
- }
- *npp = nmpts; /* Update returned number of points */
-
- lastmap->del(lastmap);
- }
-
if (evectmap != NULL)
evectmap->del(evectmap);
#ifndef PLOT_DIGAM
- if (src_gam != sc_gam)
- src_gam->del(src_gam);
- if (dst_gam != src_gam && dst_gam != dc_gam)
- dst_gam->del(dst_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
for (i = 0; i < nmpts; i++) {
smp[i].sgam = NULL;
smp[i].dgam = NULL;
- smp[i].dcgam = NULL;
}
#else /* !PLOT_DIGAM */
warning("!!!!! PLOT_DIGAM defined !!!!!");
@@ -3972,7 +3504,6 @@ if (smp[i].nscale[0] > 1.5 || smp[i].nscale[0] < 0.01
void free_nearsmth(nearsmth *smp, int nmpts) {
int i;
- /* Free contents that have been used */
for (i = 0; i < nmpts; i++) {
if (smp[i].nd != NULL)
free(smp[i].nd);
@@ -3987,7 +3518,7 @@ void free_nearsmth(nearsmth *smp, int nmpts) {
/* Create a plot indicating how the source mapping has been guided by the */
/* various weighting forces. */
-static void create_influence_plot(nearsmth *smp, int nmpts, int mapres) {
+static void create_influence_plot(nearsmth *smp, int nmpts) {
int i, j, k;
gamut *gam;
int src = 0; /* 1 = src, 0 = dst gamuts */
@@ -4061,7 +3592,7 @@ static void create_influence_plot(nearsmth *smp, int nmpts, int mapres) {
/* Create the diagnostic color rspl */
for (j = 0; j < 3; j++) { /* Set resolution for all axes */
- gres[j] = mapres;
+ gres[j] = smp->mapres;
avgdev[j] = 0.001;
}
swdiag = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
diff --git a/gamut/nearsmth.h b/gamut/nearsmth.h
index 82afab3..f826357 100644
--- a/gamut/nearsmth.h
+++ b/gamut/nearsmth.h
@@ -126,14 +126,10 @@ typedef struct {
struct {
double rdl; /* Direction smoothing radius L* dir. (delta E radius at src point)*/
double rdh; /* Direction smoothing radius H* (delta E radius at src point)*/
-
- double dsm; /* Degree of smoothing (non-linear response) */
} r;
- /* Depth room weighting. */
- /* Weighing to give to minimizing depth ratio by mapping to/from adequate dest/src depth. */
- /* The idea is to compromize luminance and/or hue to allow room for */
- /* preserving saturation distinction under heavy compression. */
+ /* depth weighting */
+ /* Weighing to give to minimizing depth ratio by mapping to/from adequate dest/src depth */
struct {
double co; /* Overall compression weighting */
double xo; /* Overall expansion weighting */
@@ -170,7 +166,6 @@ typedef struct {
struct _nearsmth {
/* Public: */
- int uflag; /* Use flag, 0 = normal, 1 = grid surface point */
int gflag; /* Gamut direction flag. 0 = not determinable, 1 = comp., 2 = exp. */
int vflag; /* Vector direction flag. 0 = not determinable, 1 = comp., 2 = exp. */
/* sv2, dv2, sd3 etc. are valid if vflag != 0 */
@@ -183,13 +178,12 @@ struct _nearsmth {
double dv[3]; /* Output destination value */
double dr; /* Output destination value radius from center */
double div[3]; /* gam[cx]pf moderated dv[] value */
- double w1; /* guide point weight */
/* Gamut sub-surface mapping guide point (knee shape controlled by gamcknf & gamxknf) */
double sv2[3]; /* Sub-surface source value */
double dv2[3]; /* Sub-surface knee'd adjusted destination value */
double div2[3]; /* gam[cx]pf moderated dv2[] value */
- double w2; /* Sub-surface weight (set in nearsmth) */
+ double w2; /* Sub-surface weight (fixed in nearsmth) */
double sd3[3]; /* Deep sub-surface source & destination value */
double w3; /* Deep sub-surface weight */
@@ -207,43 +201,39 @@ struct _nearsmth {
double _sr; /* Original source radius */
double naxbf; /* Blend factor that goes to 0.0 at white & black points. */
double aodv[3]; /* Absolute error optimized destination value */
- double nrdv[3]; /* No relative smoothed destination value */
+ double nrdv[3]; /* No relative weight optimized destination value */
double anv[3]; /* Average neighborhood target point (relative target) */
double tdst[3]; /* Target destination on gamut */
- int nott; /* NZ if not a point that needs to land on gamut */
double evect[3]; /* Accumulated extension vector direction */
double clen; /* Current correction length needed */
double coff[3]; /* Correction offset */
double rext;
double temp[3]; /* General temporary */
- gamut *sgam; /* Source gamut src_gam = intersection of src and img gamut gamut */
- gamut *dgam; /* Intersected destination gamut dst_gam */
- gamut *dcgam; /* Destination Colorspace gamut dc_gam */
+ gamut *sgam; /* Source gamut sci_gam = intersection of src and img gamut gamut */
+ gamut *dgam; /* Destination gamut di_gam */
int nnd, _nnd; /* No & size of direction neighbour list */
neighb *nd; /* Allocated list of neighbours */
- double nscale[3]; /* Neighborhood scale change from sv to dv */
double dcratio; /* Depth compression ratio */
double dxratio; /* Depth expansion ratio */
+ int mapres; /* Target grid res for 3D RSPL */
+
int debug;
- double dbgv[3]; /* Error components va, vr, vd on last itteration */
+ double dbgv[4]; /* Error components va, vr, vl, vd on last itteration */
}; typedef struct _nearsmth nearsmth;
/* Return the upper bound on the number of points that will be generated */
int near_smooth_np(
- gamut **pp_gam, /* Return gamut that was used for points */
gamut *sc_gam, /* Source colorspace gamut */
gamut *s_gam, /* Source image gamut (== sc_gam if none) */
gamut *d_gam, /* Destination colorspace gamut */
- double xvra, /* Extra vertex ratio */
- int gmult, /* Guide point multiplier, typically 4 */
- int surfgres /* surface grid point resolution, 0 for none */
+ double xvra /* Extra vertex ratio */
);
/* Return a list of points. Call free_nearsmth() after use */
@@ -263,13 +253,11 @@ nearsmth *near_smooth(
int usecomp, /* Flag indicating whether smoothed compressed value will be used */
int useexp, /* Flag indicating whether smoothed expanded value will be used */
double xvra, /* Extra vertex ratio */
- int mapres, /* Target grid res for 3D RSPL, (allowing for gexp) */
+ int mapres, /* Target grid res for 3D RSPL */
double mapsmooth, /* Target smoothing for 3D RSPL */
- double gexp, /* Total grid expansion ratio, none = 1.0 */
- int surfgres, /* Surface grid point resolution, 0 for none */
- datai map_il, /* Return input range */
+ datai map_il, /* Preliminary rspl input range */
datai map_ih,
- datao map_ol, /* Return output range */
+ datao map_ol, /* Preliminary rspl output range */
datao map_oh
);
@@ -279,21 +267,13 @@ void free_nearsmth(nearsmth *smp, int npp);
/* Expand the compact form of weights into the explicit form. */
int expand_weights(gammapweights out[14], gammapweights *in);
-/* Blend two expanded groups of individual weights into one */
+/* Blend a two expanded groups of individual weights into one */
void near_xwblend(
gammapweights *dst,
gammapweights *src1, double wgt1,
gammapweights *src2, double wgt2
);
-/* Blend three expanded groups of individual weights into one */
-void near_xwblend3(
-gammapweights *dst,
-gammapweights *src1, double wgt1,
-gammapweights *src2, double wgt2,
-gammapweights *src3, double wgt3
-);
-
/* Tweak weights acording to extra cmy cusp flags or rel override */
void tweak_weights(gammapweights out[14], int dst_cmymap, int rel_oride);
diff --git a/gamut/smthtest.c b/gamut/smthtest.c
index b794ed0..c9214d3 100644
--- a/gamut/smthtest.c
+++ b/gamut/smthtest.c
@@ -47,44 +47,37 @@ gammapweights weights[] = {
{ /* Cusp alignment control */
{
0.1, /* Cusp luminance alignment weighting 0 = none, 1 = full */
- 0.0, /* Cusp chroma alignment weighting 0 = none, 1 = full */
- 0.3 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ 0.1, /* Cusp chroma alignment weighting 0 = none, 1 = full */
+ 0.2 /* Cusp hue alignment weighting 0 = none, 1 = full */
},
- 2.0, /* Alignment twist power, 0 = linear, 1 = curve, 2+ late curve */
1.00 /* Chroma expansion 1 = none */
},
- { /* Radial weighting (currently broken - need to fix) */
+ { /* Radial weighting */
0.0, /* Radial error overall weight, 0 + */
0.5, /* Radial hue dominance vs l+c, 0 - 1 */
0.5 /* Radial l dominance vs, c, 0 - 1 */
},
{ /* Weighting of absolute error of destination from source */
1.0, /* Absolute error overall weight */
- 0.8, /* Hue dominance vs l+c, 0 - 1 */
+ 0.5, /* Hue dominance vs l+c, 0 - 1 */
- 0.8, /* White l dominance vs, c, 0 - 1 */
- 0.5, /* Grey l dominance vs, c, 0 - 1 */
- 0.93, /* Black l dominance vs, c, 0 - 1 */
+ 0.9, /* Light l dominance vs, c, 0 - 1 */
+ 0.9, /* Medium l dominance vs, c, 0 - 1 */
+ 0.9, /* Dark l dominance vs, c, 0 - 1 */
- 0.4, /* White l blend start radius, 0 - 1, at white = 0 */
- 0.7, /* Black l blend power, linear = 1.0, enhance < 1.0 */
-
- 1.5, /* L error extra power with size, none = 1.0 */
- 10.0 /* L error extra xover threshold in DE */
+ 0.5, /* l/c dominance breakpoint, 0 - 1 */
+ 0.0, /* l dominance exageration, 0+ */
+ 0.0 /* c dominance exageration, 0+ */
},
{ /* Relative vector smoothing */
- 20.0, 30.0, /* Relative Smoothing radius L* H* */
- 0.9 /* Degree of smoothing */
+ 30.0, 20.0 /* Relative Smoothing radius L* H* */
},
{ /* Weighting of excessive compression error, which is */
/* the src->dst vector length over the available dst depth. */
/* The depth is half the distance to the intersection of the */
/* vector to the other side of the gamut. (doesn't get triggered much ?) */
- 5.0, /* Compression depth weight */
- 5.0 /* Expansion depth weight */
- },
- {
- 0.0 /* Fine tuning expansion weight, 0 - 1 */
+ 100.0, /* Compression depth weight */
+ 100.0 /* Expansion depth weight */
}
}
};
@@ -217,7 +210,7 @@ main(int argc, char *argv[]) {
/* Create the near point mapping */
nsm = near_smooth(verb, &nnsm, gin, gin, gout, 0, 0, NULL, xweights,
- 0.1, 0.1, 1, 1, 2.0, 19, 2.0, 1.20, 5, il, ih, ol, oh);
+ 0.1, 0.1, 1, 1, 2.0, 17, 10.0, il, ih, ol, oh);
if (nsm == NULL)
error("Creating smoothed near points failed");
diff --git a/h/aconfig.h b/h/aconfig.h
index 50275ea..4b24c82 100644
--- a/h/aconfig.h
+++ b/h/aconfig.h
@@ -9,31 +9,8 @@
/* minor number = 8 bits */
/* major number = 8 bits */
-#define ARGYLL_VERSION 0x01083
-#define ARGYLL_VERSION_STR "1.8.3"
-
-#if defined(NT)
-# if defined(_WIN64)
-# define ARGYLL_BUILD_STR "MSWin 64 bit"
-# else
-# define ARGYLL_BUILD_STR "MSWin 32 bit"
-# endif
-#endif
-#if defined(UNIX)
-# if defined(__APPLE__)
-# if defined(__LP64__)
-# define ARGYLL_BUILD_STR "OS X 64 bit"
-# else
-# define ARGYLL_BUILD_STR "OS X 32 bit"
-# endif
-# else
-# if defined(__LP64__)
-# define ARGYLL_BUILD_STR "Linux 64 bit"
-# else
-# define ARGYLL_BUILD_STR "Linux 32 bit"
-# endif
-# endif
-#endif
+#define ARGYLL_VERSION 0x01082
+#define ARGYLL_VERSION_STR "1.8.2"
/* Maximum file path length */
#define MAXNAMEL 1024
diff --git a/icc/icc.c b/icc/icc.c
index d5b72ce..92611c3 100644
--- a/icc/icc.c
+++ b/icc/icc.c
@@ -13401,13 +13401,6 @@ void icmMul3(double out[3], double in1[3], double in2[3]) {
out[2] = in1[2] * in2[2];
}
-/* Take absolute of a 3 vector */
-void icmAbs3(double out[3], double in[3]) {
- out[0] = fabs(in[0]);
- out[1] = fabs(in[1]);
- out[2] = fabs(in[2]);
-}
-
/* - - - - - - - - - - - - - - - - - - - - - - - - */
/* Set a 3x3 matrix to unity */
@@ -13844,11 +13837,6 @@ void icmRotMat(double m[3][3], double s[3], double t[3]) {
/* If the two input vectors are close to being parallel, */
/* then h will be close to zero. */
if (fabs(h) < 1e-12) {
-
- /* Make sure scale is the correct sign */
- if (s[0] * t[0] + s[1] * t[1] + s[2] * t[2] < 0.0)
- tl = -tl;
-
m[0][0] = tl/sl;
m[0][1] = 0.0;
m[0][2] = 0.0;
@@ -13872,19 +13860,6 @@ void icmRotMat(double m[3][3], double s[3], double t[3]) {
m[2][1] = tl/sl * (h * v[1] * v[2] + v[0]);
m[2][2] = tl/sl * (e + h * v[2] * v[2]);
}
-
-#ifdef NEVER /* Check result */
- {
- double tt[3];
-
- icmMulBy3x3(tt, m, s);
-
- if (icmLabDEsq(t, tt) > 1e-4) {
- printf("icmRotMat error t, is %f %f %f\n",tt[0],tt[1],tt[2]);
- printf(" should be %f %f %f\n",t[0],t[1],t[2]);
- }
- }
-#endif /* NEVER */
}
/* - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -13933,9 +13908,9 @@ void icmMul3By3x4(double out[3], double mat[3][4], double in[3]) {
/* "Real-Time Rendering". */
/* s0 -> s1 is source vector, t0 -> t1 is target vector. */
/* Usage of icmRotMat: */
-/* t[0] = mat[0][0] * s[0] + mat[0][1] * s[1] + mat[0][2] * s[2] + mat[0][3]; */
-/* t[1] = mat[1][0] * s[0] + mat[1][1] * s[1] + mat[1][2] * s[2] + mat[1][3]; */
-/* t[2] = mat[2][0] * s[0] + mat[2][1] * s[1] + mat[2][2] * s[2] + mat[2][3]; */
+/* t[0] == mat[0][0] * s[0] + mat[0][1] * s[1] + mat[0][2] * s[2] + mat[0][3]; */
+/* t[1] == mat[1][0] * s[0] + mat[1][1] * s[1] + mat[1][2] * s[2] + mat[1][3]; */
+/* t[2] == mat[2][0] * s[0] + mat[2][1] * s[1] + mat[2][2] * s[2] + mat[2][3]; */
/* i.e. use icmMul3By3x4 */
void icmVecRotMat(double m[3][4], double s1[3], double s0[3], double t1[3], double t0[3]) {
int i, j;
@@ -13964,26 +13939,6 @@ void icmVecRotMat(double m[3][4], double s1[3], double s0[3], double t1[3], doub
m[j][i] = 0.0;
}
}
-
-#ifdef NEVER /* Check result */
- {
- double tt0[3], tt1[3];
-
- icmMul3By3x4(tt0, m, s0);
-
- if (icmLabDEsq(t0, tt0) > 1e-4) {
- printf("icmVecRotMat error t0, is %f %f %f\n",tt0[0],tt0[1],tt0[2]);
- printf(" should be %f %f %f\n",t0[0],t0[1],t0[2]);
- }
-
- icmMul3By3x4(tt1, m, s1);
-
- if (icmLabDEsq(t1, tt1) > 1e-4) {
- printf("icmVecRotMat error t1, is %f %f %f\n",tt1[0],tt1[1],tt1[2]);
- printf(" should be %f %f %f\n",t1[0],t1[1],t1[2]);
- }
- }
-#endif /* NEVER */
}
/* - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -15359,8 +15314,6 @@ int icmClipXYZ(double out[3], double in[3]) {
/* --------------------------------------------------------------- */
/* Some video specific functions */
-/* Should add ST.2048 log functions */
-
/* Convert Lut table index/value to YPbPr */
/* (Same as Lut_Lut2YPbPr() ) */
void icmLut2YPbPr(double *out, double *in) {
diff --git a/icc/icc.h b/icc/icc.h
index 36ec73a..4eba0ec 100644
--- a/icc/icc.h
+++ b/icc/icc.h
@@ -1754,9 +1754,6 @@ void icmMul3(double out[3], double in1[3], double in2[3]);
#define ICMMUL3(o, i, j) ((o)[0] = (i)[0] * (j)[0], (o)[1] = (i)[1] * (j)[1], (o)[2] = (i)[2] * (j)[2])
-/* Take absolute of a 3 vector */
-void icmAbs3(double out[3], double in[3]);
-
/* Compute the dot product of two 3 vectors */
double icmDot3(double in1[3], double in2[3]);
diff --git a/link/collink.c b/link/collink.c
index 597cd1d..7d04838 100644
--- a/link/collink.c
+++ b/link/collink.c
@@ -130,7 +130,7 @@
External cLUTs that are implemented using integer logic
(ie, in HW, such as the eeColor) may choose to cope
- with this problem in a different way, i.e. by
+ with this probem in a different way, i.e. by
scaling against a value above the largest valid
device encoding. For instance, cLUTs of resolution
65 would be normalised to 65 rather than the usual 64,
@@ -246,7 +246,7 @@ void usage(char *diag, ...) {
fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
fprintf(stderr," l:imagewhite Image white in cd.m^2 if surround = auto (default 250)\n");
fprintf(stderr," f:flare Flare light %% of image luminance (default 0)\n");
- fprintf(stderr," g:glare Flare light %% of ambient (default %d)\n",XICC_DEFAULT_GLARE);
+ fprintf(stderr," g:glare Flare light %% of ambient (default 1)\n");
fprintf(stderr," g:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
fprintf(stderr," g:x:y Flare color as x, y\n");
fprintf(stderr," -t tlimit set source total ink limit, 0 - 400%% (estimate by default)\n");
@@ -309,12 +309,10 @@ struct _profinfo {
icmLuAlgType alg; /* Type of lookup algorithm */
icColorSpaceSignature csp; /* Colorspace */
int chan; /* Channels */
- int nocurve; /* NZ to not use ICC device curve and tvenc in per channel curve */
+ int nocurve; /* NZ to not use device curve in per channel curve */
int lcurve; /* 1 to apply a Y like to L* curve for XYZ Matrix profiles */
/* 2 to apply a Y to L* curve for XYZ space */
- /* lcurve is applied irrespective of nocurve, and is */
- /* incompatible with tvenc ? */
- int tvenc; /* 0 = Full range RGB, */
+ int tvenc; /* 0 = full range RGB, 1 = RGB Video Level encoding, */
/* 1 = RGB Video Level encoding, */
/* 3 = Rec601 YCbCr encoding, */
/* 4 = Rec709 1150/60/2:1 YCbCr encoding */
@@ -328,8 +326,8 @@ struct _profinfo {
int bt1886; /* 1 to apply input gamma curve using effective gamma */
/* 2 to apply input gamma curve using technical gamma */
double outoprop; /* Proportion of black output offset, 0.0 .. 1.0. 0.0 == BT.1886 */
- double egamma; /* effective gamma to aim for */
- double tgamma; /* technical gamma to aim for */
+ double egamma; /* effective gamma to ain for */
+ double tgamma; /* technical gamma to ain for */
bt1886_info bt; /* BT.1886 adjustment info */
double rgb_bk[3]; /* Linear light input RGB black to bend to */
double wp[3]; /* Lab/Jab white point for profile used by wphack & xyzscale */
@@ -350,7 +348,6 @@ struct _clink {
int dst_cmymap; /* masks C = 1, M = 2, Y = 4 to force 100% cusp map */
int tdlut; /* nz = 3DLut output, 1 = eeColor format, 2 = MadVR format */
/* 3 = .cube format */
- double coscale[3]; /* eeColor cLUT output de-scale/"second" 1D lut scale */
icColorSpaceSignature pcsor; /* PCS to use between in & out profiles */
@@ -371,8 +368,8 @@ struct _clink {
xicc *abs_xicc;
icxLuBase *abs_luo; /* NULL if none */
- int addcal; /* 1 = apply cal to 3dLut and set linear MadVR cal1 */
- /* 2 = set MadVR cal1 to cal */
+ int addcal; /* 1 = apply cal to 3dLut and set linear cal1 */
+ /* 2 = set cal1 to cal */
xcal *cal; /* Calibration to apply, NULL if none */
/* (We current assume that xyzscale can't be used with gmi) */
@@ -631,8 +628,10 @@ static void xvYCC_fwd_matrix(double *out, double *in) {
}
/* ======================================================= */
-/* cLUT Input value tweaks to make Video encoded black land on */
-/* 65 res grid nodes, which should help 33 and 17 res cLUTs too*/
+/* cLUT Input value tweaks to make Video emcoded black land on */
+/* 65 res grid nodes. This should help 33 and 17 res cLUTs too*/
+
+/* This also makes the cLUT nodes line up with the eeColor cLUT nodes. */
static void VidRGB_to_cLUT65(double out[3], double in[3]) {
int i;
@@ -745,7 +744,7 @@ void devi_devip(void *cntx, double *out, double *in) {
for (i = 0; i < p->in.chan; i++)
out[i] = in[i];
- if (!p->in.nocurve) { /* Using ICC profile per channel curves & tvenc */
+ if (!p->in.nocurve) { /* Using profile per channel curves */
/* Video decode */
if (p->in.tvenc == 1) { /* Video 16-235 range */
@@ -754,7 +753,7 @@ void devi_devip(void *cntx, double *out, double *in) {
icmVidRGB_2_RGB(out, out);
} else if (p->in.tvenc >= 3) { /* YCbCr */
- error("Can't use input curves with YCbCr or other input encoding");
+ error("Can't use input curves with YCbCr input encoding");
}
#ifdef DEBUG
@@ -801,11 +800,25 @@ void devi_devip(void *cntx, double *out, double *in) {
#endif
}
- /* For video encoding, adjust index value very slightly, */
+ /* eeColor cLUT is fake 65^3 - only 64^3 is usable. This affects */
+ /* full range and xvYCC RGB, so map inputs to cLUT to only use 64^3 */
+ if (p->tdlut == 1) {
+ if (p->in.tvenc == 0) { /* Full range */
+ for (i = 0; i < p->in.chan; i++)
+ out[i] = out[i] * (p->clutres-2.0)/(p->clutres-1.0);
+
+ /* This isn't actually usable, because the eeColor does its own YCbCr conversion */
+ } else if (p->in.tvenc == 8 || p->in.tvenc == 9) { /* xvYCC */
+ out[0] = out[0];
+ out[1] = (out[1] * (p->clutres-3.0) + 1.0)/(p->clutres-1.0); /* Keep symetrical */
+ out[2] = (out[2] * (p->clutres-3.0) + 1.0)/(p->clutres-1.0);
+ }
+ }
+
+ /* For video encoding, adjust index value vert slightly, */
/* to align black with grid node. (We assume that the 3DLut HW */
/* is doing this when there are no input & output curves for 2DLuts) */
if (p->in.tvenc != 0
- && p->tdlut != 1 /* Not eeColor - it doesn't have an input curve */
&& (p->clutres == 65
|| p->clutres == 33
|| p->clutres == 17)) {
@@ -867,10 +880,24 @@ void devip_devop(void *cntx, double *out, double *in) {
for (i = 0; i < p->in.chan; i++)
win[i] = oin[i] = in[i];
+ /* eeColor cLUT is fake 65^3 - only 64^3 is usable. This affects */
+ /* full range and xvYCC RGB, so un-map inputs to cLUT to only use 64^3 */
+ if (p->tdlut == 1) {
+ if (p->in.tvenc == 0) {
+ for (i = 0; i < p->in.chan; i++)
+ win[i] = win[i] * (p->clutres-1.0)/(p->clutres-2.0);
+
+ /* This isn't actually usable, because the eeColor does its own YCbCr conversion */
+ } else if (p->in.tvenc == 8 || p->in.tvenc == 9) { /* xvYCC */
+ win[0] = win[0];
+ win[1] = (win[1] * (p->clutres-1.0) - 1.0)/(p->clutres-3.0);
+ win[2] = (win[2] * (p->clutres-1.0) - 1.0)/(p->clutres-3.0);
+ }
+ }
+
/* For video encoding, adjust index value to align black with */
/* grid node */
if (p->in.tvenc != 0
- && p->tdlut != 1 /* Not eeColor - it doesn't have an input curve */
&& (p->clutres == 65
|| p->clutres == 33
|| p->clutres == 17)) {
@@ -893,7 +920,7 @@ void devip_devop(void *cntx, double *out, double *in) {
#endif
}
- if (p->in.nocurve) { /* Not using profile per channel tvenc curves */
+ if (p->in.nocurve) { /* Not using profile per channel curves */
/* Video encoding decode and input clipping */
scale = 1.0;
if (p->in.tvenc == 1) { /* Video 16-235 range */
@@ -1039,7 +1066,7 @@ void devip_devop(void *cntx, double *out, double *in) {
}
}
- if (p->in.lcurve) { /* Apply L* to Y to undo input curve */
+ if (p->in.lcurve) { /* Apply L* to Y */
l2y_curve(win, win, p->in.lcurve == 2);
#ifdef DEBUG
DEBUGCND printf("win[] set to L* value %s\n",icmPdv(p->in.chan, win));
@@ -1379,9 +1406,6 @@ void devip_devop(void *cntx, double *out, double *in) {
} else if (rgbbktrig) {
out[0] = out[1] = out[2] = 0.0;
}
-#ifdef DEBUG
- DEBUGCND printf("DevOut' after hack trigger %s\n\n",icmPdv(p->out.chan, out));
-#endif
} else { /* Various hacks haven't triggered */
switch(p->out.alg) {
@@ -1455,20 +1479,27 @@ void devip_devop(void *cntx, double *out, double *in) {
}
if (rv >= 2)
error("icc lookup failed: %d, %s",p->in.c->errc,p->in.c->err);
-#ifdef DEBUG
- DEBUGCND printf("DevOut' after PCS->Dev %s\n\n",icmPdv(p->out.chan, out));
-#endif
}
if (p->cal != NULL && p->addcal == 1 && p->out.nocurve) {
+#ifdef DEBUG
+ DEBUGCND printf("DevOut' before cal curve %s\n\n",icmPdv(p->out.chan, out));
+#endif
p->cal->interp(p->cal, out, out);
+ }
+
+ if (p->out.lcurve) { /* Apply Y to L* */
#ifdef DEBUG
- DEBUGCND printf("DevOut' after cal curve %s\n\n",icmPdv(p->out.chan, out));
+ DEBUGCND printf("DevOut' before y2l_curve %s\n\n",icmPdv(p->out.chan, out));
#endif
+ y2l_curve(out, out, p->out.lcurve == 2);
}
/* Video encode */
- if (p->out.nocurve && p->out.tvenc != 0) {
+ if (p->out.nocurve && p->out.tvenc) {
+#ifdef DEBUG
+ DEBUGCND printf("DevOut' before TVenc %s\n",icmPdv(p->out.chan, out));
+#endif
for (i = 0; i < p->out.chan; i++) {
if (out[i] < 0.0)
out[i] = 0.0;
@@ -1509,7 +1540,7 @@ void devip_devop(void *cntx, double *out, double *in) {
#endif
}
- if (clip && p->out.nocurve && p->out.tvenc != 0) {
+ if (clip && p->out.nocurve && p->out.tvenc) {
/* For RGB encoding, unscale +ve clip to preserve hue */
if (p->out.tvenc == 1) { /* RGB Video 16-235 range */
@@ -1557,34 +1588,6 @@ void devip_devop(void *cntx, double *out, double *in) {
}
}
}
-#ifdef DEBUG
- DEBUGCND printf("DevOut' after TVenc un-clip %s\n",icmPdv(p->out.chan, out));
-#endif
- }
-
- /* For eeColor and Full range RGB, make sure that the cLUT output maps to 1.0 */
- /* The output curve will correct this, irrespective of out.nocurve */
- if (p->tdlut == 1) { /* eeColor encoded input */
- /* ~~ it's not clear if this re-scaling would help with other */
- /* encodings like xvYCC ? */
- if (p->out.tvenc == 0) { /* Full range RGB */
- for (i = 0; i < 3; i++) {
- out[i] /= p->coscale[i];
- if (out[i] > 1.0)
- out[i] = 1.0;
- }
-#ifdef DEBUG
- DEBUGCND printf("DevOut' after eeColor de-scale %s\n\n",icmPdv(p->out.chan, out));
-#endif
- }
- }
-
- /* lcurve is incompatible with coscale and tvenc ?? */
- if (p->out.lcurve) { /* Apply Y to L* to make output perceptual */
-#ifdef DEBUG
- DEBUGCND printf("DevOut' before y2l_curve %s\n\n",icmPdv(p->out.chan, out));
-#endif
- y2l_curve(out, out, p->out.lcurve == 2);
}
#ifdef DEBUG
@@ -1627,20 +1630,7 @@ void devop_devo(void *cntx, double *out, double *in) {
#endif
}
- /* For eeColor and Full range RGB, unmap the cLUT output maps from 1.0 */
- if (p->tdlut == 1) { /* eeColor encoded input */
- /* ~~ it's not clear if this re-scaling would help with other */
- /* encodings like xvYCC ? */
- if (p->out.tvenc == 0) { /* Full range RGB */
- for (i = 0; i < 3; i++)
- out[i] *= p->coscale[i];
-#ifdef DEBUG
- DEBUGCND printf("DevOut after eeColor re-scale %s\n\n",icmPdv(p->out.chan, out));
-#endif
- }
- }
-
- if (!p->out.nocurve) { /* Using ICC per channel output curves and tvenc */
+ if (!p->out.nocurve) { /* Using per channel output curves */
/* Apply output curve */
switch(p->out.alg) {
@@ -1690,9 +1680,10 @@ void devop_devo(void *cntx, double *out, double *in) {
}
#ifdef DEBUG
if (p->out.tvenc != 0) {
- DEBUGCND printf("After Video encode %s\n",icmPdv(p->out.chan, out));
+ DEBUGCND printf("After Video encode %s\n",icmPdv(p->out.chan, out));
}
#endif
+
}
#ifdef DEBUG
DEBUGCND printf("DevOut'->DevOut ret %s\n",icmPdv(p->out.chan, out));
@@ -1835,8 +1826,8 @@ main(int argc, char *argv[]) {
int intentset = 0; /* The user specified an intent */
int vcset = 0; /* Viewing conditions were set by user */
int modeset = 0; /* The gamut mapping mode was set by the user */
- int addcal = 0; /* 1 = Incorporate cal. curves in 3dLUT and set linear MadVR cal1 */
- /* 2 = Set 3dLut MadVR cal1 to calibration curves */
+ int addcal = 0; /* 1 = Incorporate cal. curves in 3dLUT and set linear cal1 */
+ /* 2 = Set 3dLut cal1 to calibration curves */
int rv = 0;
icxViewCond ivc, ovc; /* Viewing Condition Overrides for in and out profiles */
int ivc_e = -1, ovc_e = -1; /* Enumerated viewing condition */
@@ -3558,23 +3549,23 @@ main(int argc, char *argv[]) {
printf("Creating Gamut Mapping\n");
/* Gamut mapping will extend given grid res to encompas */
- /* source gamut by a margin. This allows for grid expansion beyond src gamut of 1.20 */
+ /* source gamut by a margin. */
if (li.quality == 3) { /* Ultra High */
sgres = 7.0;
dgres = 7.0;
- mapres = 49;
+ mapres = 41;
} else if (li.quality == 2) { /* High */
sgres = 8.0;
dgres = 8.0;
- mapres = 39;
+ mapres = 33;
} else if (li.quality == 1) { /* Medium */
sgres = 10.0;
dgres = 10.0;
- mapres = 29;
+ mapres = 25;
} else { /* Low quality */
sgres = 12.0;
dgres = 12.0;
- mapres = 19;
+ mapres = 17;
}
/* Creat the source colorspace gamut surface */
@@ -3771,7 +3762,7 @@ main(int argc, char *argv[]) {
if (li.verb) {
printf("Gamma curve target out black rel XYZ = %f %f %f, Lab %f %f %f\n",
- bp[0],bp[1],bp[2], li.in.bt.outL, li.in.bt.tab[0], li.in.bt.tab[1]);
+ bp[0],bp[1],bp[2], li.in.bt.outL, li.in.bt.tab[1], li.in.bt.tab[2]);
printf("Proportion of black output offset = %f%s\n", li.in.outoprop,
li.in.outoprop == 0.0 ? " (BT.1886)" : "");
printf("Gamma Y input offset = %f\n", li.in.bt.ingo);
@@ -4335,33 +4326,6 @@ main(int argc, char *argv[]) {
}
}
- /* The eeColor hard wires 1.0 input to 1.0 output in its cLUT, */
- /* so de-scale the cLUT to match this, and re-scale in the */
- /* output 1D lut */
-
- li.coscale[0] = li.coscale[1] = li.coscale[2] = 1.0; /* Default - do nothing */
- if (li.tdlut == 1) { /* eeColor encoded input */
- double inout[3] = { 1.0, 1.0, 1.0 };
-
- /* ~~ it's not clear if this re-scaling would help with other */
- /* encodings like xvYCC ? */
- if (li.out.tvenc == 0) { /* Full range RGB */
- int verb = li.verb;
- li.verb = 0;
- devip_devop((void *)&li, inout, inout);
- li.verb = verb;
- if (inout[0] < 0.1
- || inout[1] < 0.1
- || inout[2] < 0.1) {
- error("Link output for white is unexpected! (%f %f %f)\n",inout[0],inout[1],inout[2]);
- }
- icmCpy3(li.coscale, inout);
- if (li.verb)
- printf("De-scaling/scaling eeColor output by %f %f %f\n",
- li.coscale[0], li.coscale[1], li.coscale[2]);
- }
- }
-
/* Link Lut = AToB0 */
if ((wo = (icmLut *)wr_icc->add_tag(
@@ -4458,6 +4422,7 @@ main(int argc, char *argv[]) {
if (li.map != NULL)
li.map->dbg = 0;
+
}
#endif /* NEVER */
@@ -4786,8 +4751,7 @@ main(int argc, char *argv[]) {
/* ===================================================================== */
-/* Tweak for eeColor input and output value encodings, to compensate */
-/* for assumption that it maps the FP range 1.0 to 64 * 2^(bits -6). */
+/* Tweak for eeColor input and output value encodings */
static void VidRGB_to_eeColor(double out[3], double in[3]) {
int i;
@@ -4802,9 +4766,7 @@ static void eeColor_to_VidRGB(double out[3], double in[3]) {
}
-/* Write a eeColor 1DLut "first/gamma" LUT files. */
-/* eeColor applies these after the cLUT and before its 3x3 matrix. */
-/* This can't help us, so create a unity lookup/ */
+/* Write a eeColor 1DLut input LUT files */
/* Return nz on error */
int write_eeColor1DinputLuts(clink *li, char *tdlut_name) {
char fname[MAXNAMEL+1+20], *xl;
@@ -4831,7 +4793,23 @@ int write_eeColor1DinputLuts(clink *li, char *tdlut_name) {
for (i = 0; i < 1024; i++) {
for (k = 0; k < 3; k++)
in[k] = i/(1024-1.0);
- icmCpy3(out,in);
+
+ /* Full range -> 64/65 scaled */
+ /* or Video -> cLUT65 index */
+ devi_devip((void *)li, out, in);
+
+ if (li->in.tvenc == 1) { /* Video 16-235 range */
+ cLUT65_to_VidRGB(out, out);
+
+ /* eeColor doesn't actually do YCrCb explicitly, but put this here for completeness */
+ } else if (li->in.tvenc == 3 /* Rec601 YCbCr */
+ || li->in.tvenc == 4 /* Rec709 1150/60/2:1 YCbCr */
+ || li->in.tvenc == 5 /* Rec709 1250/50/2:1 YCbCr */
+ || li->in.tvenc == 6 /* Rec2020 Non-constant Luminance YCbCr encoding */
+ || li->in.tvenc == 7) { /* Rec2020 Constant Luminance YCbCr encoding */
+ cLUT65_to_YCrCb(out, out);
+ }
+
fp->gprintf(fp,"%.6f\n",out[j]);
}
@@ -4872,14 +4850,13 @@ int write_eeColor3DLut(icc *icc, clink *li, char *fname) {
double oin[3], in[3], out[3];
/* Our assumption is that the eeColor maps the FP range 1.0
- to 64 * 2^(bits -6). This is slightly too much for
+ to 64 * 2^(bits -6). This is sligghtly too much for
full range (PC), but exactly lines the black point
- up on the 4th grid node for any video encoding bit depth,
+ up on the 4th grid node for any video encodig bit depth,
and results in input values being the same as output
- values for the null transform.
- (We haven't confirmed this assumtion by experiment.)
+ values for the null transform
*/
- /* There are two sets of cLUT RGB values. One is (suposedly)
+ /* There are two sets of RGB values. One is (suposedly)
the "calibrated white point" and one "the native white point",
but experiments don't give any indications that the first
three entries are capable of affecting the result in any way
@@ -4887,7 +4864,7 @@ int write_eeColor3DLut(icc *icc, clink *li, char *fname) {
*/
/* The eeColor wires the 65'th node to 1.0, and we can skip */
- /* creating it. We de-scale in clut() and re-scale in devop_devo() to compensate. */
+ /* creating it */
if (gc[0] == 64 || gc[1] == 64 || gc[2] == 64)
goto next;
@@ -4917,7 +4894,7 @@ int write_eeColor3DLut(icc *icc, clink *li, char *fname) {
|| li->in.tvenc == 4 /* Rec709 1150/60/2:1 YCbCr */
|| li->in.tvenc == 5 /* Rec709 1250/50/2:1 YCbCr */
|| li->in.tvenc == 6 /* Rec2020 Non-constant Luminance YCbCr encoding */
- || li->in.tvenc == 7) { /* Rec2020 Constant Luminance YCbCr encoding */
+ || li->in.tvenc == 7) { /* Rec2020 Constant Luminance YCbCr encoding */
YCrCb_to_cLUT65(in, in);
}
}
@@ -4946,7 +4923,7 @@ int write_eeColor3DLut(icc *icc, clink *li, char *fname) {
return 0;
}
-/* Write a eeColor 1DLut "second/linearization" LUT files. */
+/* Write a eeColor 1DLut output LUT files */
/* Return nz on error */
int write_eeColor1DoutputLuts(clink *li, char *tdlut_name) {
char fname[MAXNAMEL+1+20], *xl;
@@ -4973,7 +4950,7 @@ int write_eeColor1DoutputLuts(clink *li, char *tdlut_name) {
for (i = 0; i < 8192; i++) {
for (k = 0; k < 3; k++)
in[k] = i/(8192-1.0);
- devop_devo((void *)li, out, in); /* Apply possible output re-scaling */
+ devop_devo((void *)li, out, in);
fp->gprintf(fp,"%.6f\n",out[j]);
}
@@ -5145,7 +5122,7 @@ int write_MadVR_3DLut(clink *li, icc *icc, char *fname) {
}
}
- /* Append a MadVR cal1 table to the 3dlut. */
+ /* Append a cal1 table to the 3dlut. */
/* This can be used to ensure that the Graphics Card VideoLuts */
/* are correctly setup to match what the 3dLut is expecting. */
diff --git a/link/monoplot.c b/link/monoplot.c
index 2af1aac..adcc532 100644
--- a/link/monoplot.c
+++ b/link/monoplot.c
@@ -26,13 +26,14 @@
#include <math.h>
#include "copyright.h"
#include "aconfig.h"
-#include "numsup.h"
#include "icc.h"
#include "plot.h"
#include "ui.h"
#define PRES 100
+void error(char *fmt, ...), warning(char *fmt, ...);
+
/* ---------------------------------------- */
void usage(void) {
@@ -202,3 +203,30 @@ main(
return 0;
}
+/* ------------------------------------------------ */
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"monoplot: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"monoplot: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/log.txt b/log.txt
index e94a676..3c6d45f 100644
--- a/log.txt
+++ b/log.txt
@@ -2,59 +2,6 @@
Argyll CMS change log
=====================
-Version 1.8.3
--------------
-
-* Added SpyderCheckr24 scaning .cht and .cie files.
-
-* Fixed USB problem with i1pro (Rev B & D ?), where
- communications would occasionally break down on
- fast systems.
-
-* Added another fixed display intergration time to i1pro
- non-adaptive emission mode to cope with higher brightness displays.
-
-* Added workaround for i1d3 Rev. B status code 0x83 on very low light measurement.
-
-* Fixed minor bug in i1d3.c that truncated serial number string.
- (Thanks to Mikael Sterner).
-
-* Fixed bug in Klein K10 driver - adaptive measurement
- wasn't properly using all the extra measurements.
-
-* Improved Klein K10 driver to be more robust when lights off
- command returns bogus error codes, or causes a cascade of
- bogus measurement errors.
-
-* Added workaround for OS X 10.9+ "App Nap" problem.
-
-* Added maximum sensor frequency check for Spyder & i1d3 drivers, so that
- erronious readings due to excessive brightness can't be missed.
-
-* Changed chartread so that it doesn't warn of a possible wrong
- strip being read, nor allows bi-directional strip reading,
- if "printtarg -r" was used. A warning will be issued if
- "printtarg -r" was used, and "chartread -B" wasn't used.
-
-* Fixed collink for eeColor Full range RGB to use
- output curve ("second" 1D curves) to compensate for
- cLUT being wired for 1.0 output from 1.0 input.
-
-* Added "lp" gamut mapping intent :- Luminance Preserving Perceptual,
- for Photographers concerned with maintaining tonal variations.
-
-* Fixed bugs in image specific gamut mapping that were degrading
- the accuracy of the result.
-
-* Re-wrote gamut smoothing code, and re-tuned it to behave similarly
- to the V1.8.2 release.
-
-* Changed default viewing condition glare to 5%, to smooth out
- shadow tone curve.
-
-* Reduced the level of Helmholtz-Kohlrausch effect in CIECAM02
- implementation in the light of visual experiments.
-
Version 1.8.2
-------------
diff --git a/makepackagebin.sh b/makepackagebin.sh
index 2b846ba..1b8db28 100644
--- a/makepackagebin.sh
+++ b/makepackagebin.sh
@@ -1,8 +1,6 @@
#!/bin/sh
echo "Script to invoke Jam and then package the binary release."
-# Must use this rather than "jam -q" to ensure builtin libraries are used.
-
# Typical environment variables:
# (NOTE some systems don't export these ENV vars. by default !!!)
#
@@ -53,7 +51,7 @@ rm -f bin/*.exe bin/*.dll
rm -f ref/*.sp ref/*.cht ref/*.ti2
# Make sure it's built and installed
-if ! jam -q -fJambase -j${NUMBER_OF_PROCESSORS:-2} -sBUILTIN_TIFF=true -sBUILTIN_JPEG=true -sBUILTIN_PNG=true -sBUILTIN_Z=true -sBUILTIN_SSL=true install ; then
+if ! jam -q -fJambase -j${NUMBER_OF_PROCESSORS:-2} -sBUILTIN_TIFF=true -sBUILTIN_JPEG=true install ; then
echo "Build failed!"
exit 1
fi
@@ -163,7 +161,6 @@ if [ X$USETAR = "Xtrue" ] ; then
tar -czvf $PACKAGE $TOPDIR
# tar -xzf to extract
# tar -tzf to list
- # Should we use "COPYFILE_DISABLE=1 tar .." on OS X ??
else
zip -9 -r $PACKAGE $TOPDIR
# unzip to extract
diff --git a/namedc/namedc.c b/namedc/namedc.c
index 2fc7796..6dcfce8 100644
--- a/namedc/namedc.c
+++ b/namedc/namedc.c
@@ -796,8 +796,8 @@ static int read_cxf(namedc *p, const char *filename, int options) {
}
if (!found_io) {
- p->ill = icxIT_D50;
- p->obs = icxOT_CIE_1931_2;
+ p->ill = icIlluminantD50;
+ p->obs = icStdObs1931TwoDegrees;
a1logd(p->log, 2, "read_cxf: failed to locate ColorSpecification - assuming D50 2 degree observer\n");
}
diff --git a/numlib/Jamfile b/numlib/Jamfile
index 1053612..87c3c78 100644
--- a/numlib/Jamfile
+++ b/numlib/Jamfile
@@ -17,8 +17,6 @@ Headers = numlib.h libui.h ;
#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
-HDRS = ../h ;
-
# Numeric library
Library libnum.lib : numsup.c dnsq.c powell.c dhsx.c ludecomp.c svd.c zbrent.c rand.c sobol.c aatree.c ;
@@ -35,5 +33,3 @@ if $(OS) = MACOSX {
# UI setup library
Library libui.lib : ui.c ;
-
-
diff --git a/numlib/numsup.c b/numlib/numsup.c
index c08ed99..43f6e73 100644
--- a/numlib/numsup.c
+++ b/numlib/numsup.c
@@ -17,7 +17,6 @@
#include <string.h>
#include <limits.h>
#include <time.h>
-#include <ctype.h>
#if defined (NT)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -25,14 +24,8 @@
#ifdef UNIX
#include <unistd.h>
#include <sys/param.h>
-#include <sys/utsname.h>
#include <pthread.h>
#endif
-#ifndef SALONEINSTLIB
-#include "aconfig.h"
-#else
-#include "sa_config.h"
-#endif
#define NUMSUP_C
#include "numsup.h"
@@ -227,138 +220,22 @@ void check_if_not_interactive() {
/* It's values can be overridden to redirect these messages. */
/******************************************************************/
-static void va_loge(a1log *p, char *fmt, ...);
-
#ifdef NT
-
-/* Get a string describing the MWin operating system */
-
-typedef struct {
- DWORD dwOSVersionInfoSize;
- DWORD dwMajorVersion;
- DWORD dwMinorVersion;
- DWORD dwBuildNumber;
- DWORD dwPlatformId;
- WCHAR szCSDVersion[128];
- WORD wServicePackMajor;
- WORD wServicePackMinor;
- WORD wSuiteMask;
- BYTE wProductType;
- BYTE wReserved;
-} osversioninfoexw;
-
-#define VER_NT_DOMAIN_CONTROLLER 0x0000002
-#define VER_NT_SERVER 0x0000003
-#define VER_NT_WORKSTATION 0x0000001
-
-static char *get_sys_info() {
- static char sysinfo[100] = { "Unknown" };
- LONG (WINAPI *pfnRtlGetVersion)(osversioninfoexw*);
-
- *(FARPROC *)&pfnRtlGetVersion
- = GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion");
- if (pfnRtlGetVersion != NULL) {
- osversioninfoexw ver = { 0 };
- ver.dwOSVersionInfoSize = sizeof(ver);
-
- if (pfnRtlGetVersion(&ver) == 0) {
- if (ver.dwMajorVersion > 6 || (ver.dwMajorVersion == 6 && ver.dwMinorVersion > 3)) {
- if (ver.wProductType == VER_NT_WORKSTATION)
- sprintf(sysinfo,"Windows V%d.%d SP %d",
- ver.dwMajorVersion,ver.dwMinorVersion,
- ver.wServicePackMajor);
- else
- sprintf(sysinfo,"Windows Server 2016 V%d.%d SP %d",
- ver.dwMajorVersion,ver.dwMinorVersion,
- ver.wServicePackMajor);
-
- } else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 3) {
- if (ver.wProductType == VER_NT_WORKSTATION)
- sprintf(sysinfo,"Windows V8.1 SP %d",
- ver.wServicePackMajor);
- else
- sprintf(sysinfo,"Windows Server 2012 R2 SP %d",
- ver.wServicePackMajor);
-
- } else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 2) {
- if (ver.wProductType == VER_NT_WORKSTATION)
- sprintf(sysinfo,"Windows V8 SP %d",
- ver.wServicePackMajor);
- else
- sprintf(sysinfo,"Windows Server SP %d",
- ver.wServicePackMajor);
-
- } else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 1) {
- if (ver.wProductType == VER_NT_WORKSTATION)
- sprintf(sysinfo,"Windows V7 SP %d",
- ver.wServicePackMajor);
- else
- sprintf(sysinfo,"Windows Server 2008 R2 SP %d",
- ver.wServicePackMajor);
-
- } else if (ver.dwMajorVersion == 6 && ver.dwMinorVersion == 0) {
- if (ver.wProductType == VER_NT_WORKSTATION)
- sprintf(sysinfo,"Windows Vista SP %d",
- ver.wServicePackMajor);
- else
- sprintf(sysinfo,"Windows Server 2008 SP %d",
- ver.wServicePackMajor);
-
- } else if (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 2) {
- // Actually could be Server 2003, Home Server, Server 2003 R2
- sprintf(sysinfo,"Windows XP Pro64 SP %d",
- ver.wServicePackMajor);
-
- } else if (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 1) {
- sprintf(sysinfo,"Windows XP SP %d",
- ver.wServicePackMajor);
-
- } else if (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 0) {
- sprintf(sysinfo,"Windows XP SP %d",
- ver.wServicePackMajor);
-
- } else {
- sprintf(sysinfo,"Windows Maj %d Min %d SP %d",
- ver.dwMajorVersion,ver.dwMinorVersion,
- ver.wServicePackMajor);
- }
- }
- }
- return sysinfo;
-}
-
-
# define A1LOG_LOCK(log) \
if (g_log_init == 0) { \
InitializeCriticalSection(&log->lock); \
- EnterCriticalSection(&log->lock); \
g_log_init = 1; \
- va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
- } else { \
- EnterCriticalSection(&log->lock); \
- }
+ } \
+ EnterCriticalSection(&log->lock)
# define A1LOG_UNLOCK(log) LeaveCriticalSection(&log->lock)
#endif
#ifdef UNIX
-
-static char *get_sys_info() {
- static char sysinfo[200] = { "Unknown" };
- struct utsname ver;
-
- if (uname(&ver) == 0)
- sprintf(sysinfo,"%s %s %s %s",ver.sysname, ver.version, ver.release, ver.machine);
- return sysinfo;
-}
-
# define A1LOG_LOCK(log) \
if (g_log_init == 0) { \
pthread_mutex_init(&log->lock, NULL); \
- pthread_mutex_lock(&log->lock); \
g_log_init = 1; \
- va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
- } else { \
- pthread_mutex_lock(&log->lock); \
- }
+ } \
+ pthread_mutex_lock(&log->lock)
# define A1LOG_UNLOCK(log) pthread_mutex_unlock(&log->lock)
#endif
@@ -380,14 +257,6 @@ static void a1_default_de_log(void *cntx, a1log *p, char *fmt, va_list args) {
#define a1_default_e_log a1_default_de_log
-/* Call log->loge() with variags */
-static void va_loge(a1log *p, char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- p->loge(p->cntx, p, fmt, args);
- va_end(args);
-}
-
/* Global log */
a1log default_log = {
1, /* Refcount of 1 because this is not allocated or free'd */
@@ -729,177 +598,6 @@ size_t nsize
}
/******************************************************************/
-/* OS X App Nap fixes */
-/******************************************************************/
-
-#if defined(__APPLE__)
-
-#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
-# include <objc/runtime.h>
-# include <objc/message.h>
-#else
-# include <objc/objc-runtime.h>
-#endif
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
-# include <objc/objc-auto.h>
-#endif
-
-/*
- OS X 10.9+ App Nap problems bug:
-
- <http://stackoverflow.com/questions/22784886/what-can-make-nanosleep-drift-with-exactly-10-sec-on-mac-os-x-10-9>
-
- NSProcessInfo variables:
-
- <https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Classes/NSProcessInfo_Class/#//apple_ref/c/tdef/NSActivityOptions>
-
- typedef enum : uint64_t { NSActivityIdleDisplaySleepDisabled = (1ULL << 40),
- NSActivityIdleSystemSleepDisabled = (1ULL << 20),
- NSActivitySuddenTerminationDisabled = (1ULL << 14),
- NSActivityAutomaticTerminationDisabled = (1ULL << 15),
- NSActivityUserInitiated = (0x00FFFFFFULL | NSActivityIdleSystemSleepDisabled ),
- NSActivityUserInitiatedAllowingIdleSystemSleep =
- (NSActivityUserInitiated & ~NSActivityIdleSystemSleepDisabled ),
- NSActivityBackground = 0x000000FFULL,
- NSActivityLatencyCritical = 0xFF00000000ULL,
- } NSActivityOptions;
-
- See <http://stackoverflow.com/questions/19847293/disable-app-nap-in-macos-10-9-mavericks-application>:
-
- @property (strong) id activity;
-
- if ([[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions:reason:)]) {
- self.activity = [[NSProcessInfo processInfo] beginActivityWithOptions:0x00FFFFFF reason:@"receiving OSC messages"];
-}
-
- <http://stackoverflow.com/questions/19671197/disabling-app-nap-with-beginactivitywithoptions>
-
- NSProcessInfo = interface(NSObject)['{B96935F6-3809-4A49-AD4F-CBBAB0F2C961}']
- function beginActivityWithOptions(options: NSActivityOptions; reason: NSString): NSObject; cdecl;
-
- <http://stackoverflow.com/questions/22164571/weird-behaviour-of-dispatch-after>
-
-*/
-
-static int osx_userinitiated_cnt = 0;
-static id osx_userinitiated_activity = nil;
-
-/* Tell App Nap that this is user initiated */
-void osx_userinitiated_start() {
- Class pic; /* Process info class */
- SEL pis; /* Process info selector */
- SEL bawo; /* Begin Activity With Options selector */
- id pi; /* Process info */
- id str;
-
- if (osx_userinitiated_cnt++ != 0)
- return;
-
- a1logd(g_log, 7, "OS X - User Initiated Activity start\n");
-
- /* We have to be conservative to avoid triggering an exception when run on older OS X */
- if ((pic = (Class)objc_getClass("NSProcessInfo")) == nil) {
- return;
- }
-
- if (class_getClassMethod(pic, (pis = sel_getUid("processInfo"))) == NULL) {
- return;
- }
-
- if (class_getInstanceMethod(pic, (bawo = sel_getUid("beginActivityWithOptions:reason:"))) == NULL) {
- a1logd(g_log, 7, "OS X - beginActivityWithOptions not supported\n");
- return;
- }
-
- /* Get the process instance */
- if ((pi = objc_msgSend((id)pic, pis)) == nil) {
- return;
- }
-
- /* Create a reason string */
- str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc"));
- str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), "ArgyllCMS");
-
- /* Start activity that tells App Nap to mind its own business. */
- /* NSActivityUserInitiatedAllowingIdleSystemSleep */
- osx_userinitiated_activity = objc_msgSend(pi, bawo, 0x00FFFFFFULL, str);
-}
-
-/* Done with user initiated */
-void osx_userinitiated_end() {
- if (osx_userinitiated_cnt > 0) {
- osx_userinitiated_cnt--;
- if (osx_userinitiated_cnt == 0 && osx_userinitiated_activity != nil) {
- a1logd(g_log, 7, "OS X - User Initiated Activity end");
- objc_msgSend(
- objc_msgSend(objc_getClass("NSProcessInfo"), sel_getUid("processInfo")),
- sel_getUid("endActivity:"), osx_userinitiated_activity);
- osx_userinitiated_activity = nil;
- }
- }
-}
-
-static int osx_latencycritical_cnt = 0;
-static id osx_latencycritical_activity = nil;
-
-/* Tell App Nap that this is latency critical */
-void osx_latencycritical_start() {
- Class pic; /* Process info class */
- SEL pis; /* Process info selector */
- SEL bawo; /* Begin Activity With Options selector */
- id pi; /* Process info */
- id str;
-
- if (osx_latencycritical_cnt++ != 0)
- return;
-
- a1logd(g_log, 7, "OS X - Latency Critical Activity start\n");
-
- /* We have to be conservative to avoid triggering an exception when run on older OS X */
- if ((pic = (Class)objc_getClass("NSProcessInfo")) == nil) {
- return;
- }
-
- if (class_getClassMethod(pic, (pis = sel_getUid("processInfo"))) == NULL) {
- return;
- }
-
- if (class_getInstanceMethod(pic, (bawo = sel_getUid("beginActivityWithOptions:reason:"))) == NULL) {
- a1logd(g_log, 7, "OS X - beginActivityWithOptions not supported\n");
- return;
- }
-
- /* Get the process instance */
- if ((pi = objc_msgSend((id)pic, pis)) == nil) {
- return;
- }
-
- /* Create a reason string */
- str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc"));
- str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), "Measuring Color");
-
- /* Start activity that tells App Nap to mind its own business. */
- /* NSActivityUserInitiatedAllowingIdleSystemSleep | NSActivityLatencyCritical */
- osx_latencycritical_activity = objc_msgSend(pi, bawo, 0x00FFFFFFULL | 0xFF00000000ULL, str);
-}
-
-/* Done with latency critical */
-void osx_latencycritical_end() {
- if (osx_latencycritical_cnt > 0) {
- osx_latencycritical_cnt--;
- if (osx_latencycritical_cnt == 0 && osx_latencycritical_activity != nil) {
- a1logd(g_log, 7, "OS X - Latency Critical Activity end");
- objc_msgSend(
- objc_msgSend(objc_getClass("NSProcessInfo"), sel_getUid("processInfo")),
- sel_getUid("endActivity:"), osx_latencycritical_activity);
- osx_latencycritical_activity = nil;
- }
- }
-}
-
-#endif /* __APPLE__ */
-
-/******************************************************************/
/* Numerical Recipes Vector/Matrix Support functions */
/******************************************************************/
/* Note the z suffix versions return zero'd vectors/matricies */
diff --git a/numlib/numsup.h b/numlib/numsup.h
index 366763d..a284809 100644
--- a/numlib/numsup.h
+++ b/numlib/numsup.h
@@ -350,24 +350,6 @@ size_t nsize
/* =========================================================== */
-#if defined(__APPLE__)
-
-/* Tell App Nap that this is user initiated */
-void osx_userinitiated_start();
-
-/* Done with user initiated */
-void osx_userinitiated_end();
-
-/* Tell App Nap that this is latency critical */
-void osx_latencycritical_start();
-
-/* Done with latency critical */
-void osx_latencycritical_end();
-
-#endif /* __APPLE__ */
-
-/* =========================================================== */
-
/* Numerical recipes vector/matrix support functions */
/* Note that the index arguments are the inclusive low and high values */
@@ -522,7 +504,6 @@ void write_INR64_le(ORD8 *p, INR64 d);
#ifndef isNan
#define isNan(x) ((x) != (x))
#define isFinite(x) ((x) == 0.0 || (x) * 1.0000001 != (x))
-#define isNFinite(x) ((x) != 0.0 && (x) * 1.0000001 == (x))
#endif
diff --git a/numlib/ui.c b/numlib/ui.c
index a3cdbe8..31fd3b6 100644
--- a/numlib/ui.c
+++ b/numlib/ui.c
@@ -12,8 +12,7 @@
* see the License.txt file for licencing details.
*
* Typically we need to set things up and then call the
- * "normal" main, called "uimain" in ArgyllCMS utils,
- * created by ui.h #defining main to uimain.
+ * "normal" main, called "uimain" in ArgyllCMS utils.
*/
#ifdef UNIX
@@ -49,14 +48,6 @@
# include <Foundation/Foundation.h>
# include <AppKit/AppKit.h>
-/* (Duplicate declaration from numsup.h) */
-
-/* Tell App Nap that this is user initiated */
-void osx_userinitiated_start();
-
-/* Done with user initiated */
-void osx_userinitiated_end();
-
/* This is a mechanism to force libui to link */
int ui_initialized = 0;
@@ -66,9 +57,6 @@ static char **g_argv;
pthread_t ui_thid = 0; /* Thread ID of main thread running io run loop */
pthread_t ui_main_thid = 0; /* Thread ID of thread running application main() */
-extern int uimain(int argc, char *argv[]);
-
-/* Thread that calls the real application main() */
static void *callMain(void *p) {
int rv;
@@ -76,13 +64,8 @@ static void *callMain(void *p) {
NSAutoreleasePool *tpool = [NSAutoreleasePool new];
- /* Turn App Nap off */
- osx_userinitiated_start();
-
rv = uimain(g_argc, g_argv);
- osx_userinitiated_end();
-
[tpool release];
exit(rv);
@@ -221,8 +204,6 @@ int ui_initialized = 0;
//# pragma comment( linker, "/subsystem:windows /ENTRY:mainCRTStartup" )
//# pragma comment( linker, "/subsystem:windows /ENTRY:WinMainCRTStartup" )
-extern int uimain(int argc, char *argv[]);
-
APIENTRY WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
diff --git a/plot/plot.c b/plot/plot.c
index e3cd5bf..948cb64 100644
--- a/plot/plot.c
+++ b/plot/plot.c
@@ -1529,12 +1529,7 @@ static int do_plot_imp(
nanosleep(&ts, NULL);
}
} else if (dowait < 0) {
- struct timespec ts;
- int msec = -dowait * 1000;
-
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- nanosleep(&ts, NULL);
+ Sleep(-dowait * 1000);
}
if (tpool != nil)
diff --git a/plot/vrml.c b/plot/vrml.c
index 0121c53..5b3f9a1 100644
--- a/plot/vrml.c
+++ b/plot/vrml.c
@@ -877,7 +877,7 @@ double cc[3] /* Surface color, cc == NULL or cc[0] < 0.0 */
fprintf(s->fp," ></Material>\n");
/* Hack to workaround bugs in x3dom trasparency */
if (s->fmt == fmt_x3dom && trans > 0.0)
- fprintf(s->fp," <DepthMode readOnly='true'></depthMode>\n");
+ fprintf(s->fp," <DepthMode readOnly='true'></depthMode>\n", trans);
fprintf(s->fp," </Appearance>\n");
fprintf(s->fp," </Shape>\n");
}
diff --git a/profile/colprof.c b/profile/colprof.c
index 7309dc4..ced168b 100644
--- a/profile/colprof.c
+++ b/profile/colprof.c
@@ -956,7 +956,7 @@ int main(int argc, char *argv[]) {
if (illum == icxIT_none)
illum = icxIT_D50;
- if (observ == icxOT_none)
+ if (observ = icxOT_none)
observ = icxOT_CIE_1931_2;
/* See if CIE is actually available - some sources of .TI3 don't provide it */
diff --git a/profile/colverify.c b/profile/colverify.c
index 1ab3f64..40165a0 100644
--- a/profile/colverify.c
+++ b/profile/colverify.c
@@ -707,7 +707,7 @@ int main(int argc, char *argv[])
}
/* Set default */
- if (l_observ == icxOT_none)
+ if (l_observ = icxOT_none)
l_observ = icxOT_CIE_1931_2;
if ((sp2cie = new_xsp2cie(l_illum, l_illum == icxIT_none ? NULL : &cust_illum,
diff --git a/profile/profcheck.c b/profile/profcheck.c
index e3f1bec..8c2fc60 100644
--- a/profile/profcheck.c
+++ b/profile/profcheck.c
@@ -446,7 +446,7 @@ int main(int argc, char *argv[])
if (illum == icxIT_none)
illum = icxIT_D50;
- if (observ == icxOT_none)
+ if (observ = icxOT_none)
observ = icxOT_CIE_1931_2;
/* See if CIE is actually available - some sources of .TI3 don't provide it */
diff --git a/profile/profout.c b/profile/profout.c
index 4ad62aa..1a6f4ae 100644
--- a/profile/profout.c
+++ b/profile/profout.c
@@ -2276,22 +2276,22 @@ make_output_icc(
printf("Creating Gamut Mapping\n");
/* Gamut mapping will extend given grid res to encompas */
- /* source gamut by a margin of 1.20. */
- if (oquality == 3) { /* Ultra High */
- gres = 7.0;
- mapres = 49;
+ /* source gamut by a margin. */
+ if (oquality == 3) { /* Ultra High */
+ gres = 8.0;
+ mapres = 41;
} else if (oquality == 2) { /* High */
gres = 8.0;
- mapres = 39;
+ mapres = 33;
} else if (oquality == 1) { /* Medium */
gres = 10.0;
- mapres = 29;
+ mapres = 25;
} else if (oquality == 0) { /* Low quality */
gres = 12.0;
- mapres = 19;
+ mapres = 17;
} else { /* Extremely low */
gres = 14.0;
- mapres = 11;
+ mapres = 9;
}
/* We could lift this restriction by allowing for separate */
diff --git a/ref/ColorCheckerPassport.cht b/ref/ColorCheckerPassport.cht
index 5378c2f..758cad7 100644
--- a/ref/ColorCheckerPassport.cht
+++ b/ref/ColorCheckerPassport.cht
@@ -69,54 +69,54 @@ YLIST 38
105.7 1.0 1.0
112.4 1.0 1.0
-EXPECTED XYZ 50
- SAT1 31.444334 19.286094 6.888559
- SAT2 56.064662 44.030373 6.427599
- SAT3 67.324242 67.447159 7.468562
- SAT4 15.570651 29.465796 11.20434
- SAT5 21.619963 29.778971 41.25516
- SAT6 17.456572 19.372800 46.61877
- SAT7 24.114288 18.910816 30.96444
- SAT8 30.360635 18.858573 16.93814
- WBP1 55.603171 57.729295 46.42132
- WBP2 57.049606 60.324512 49.89966
- WBP3 53.811668 58.177050 49.42470
- WBP4 52.378305 57.343255 49.64556
- WBP5 52.469763 58.680177 51.97625
- WBL1 59.661034 59.332741 48.55177
- WBL2 59.041480 59.368909 48.29234
- WBL3 55.920447 58.052670 47.03935
- WBL4 55.083575 58.526581 51.10275
- WBL5 53.892264 58.200472 53.59833
- NEU1 3.151107 3.263644 2.737095
- NEU2 3.610326 3.768524 3.225077
- NEU3 4.585675 4.814770 4.063276
- NEU4 5.242110 5.523981 4.582603
- NEU5 44.365128 46.364955 37.75652
- NEU6 55.836099 58.281967 47.53593
- NEU7 70.627230 73.603361 59.69403
- NEU8 88.638466 92.368156 71.51666
- A1 11.411919 10.072672 5.112897
- A2 38.118655 34.074205 18.53409
- A3 16.687521 18.224488 25.41503
- A4 11.119565 13.272712 5.165291
- A5 23.995041 23.022599 32.25695
- A6 29.864887 41.242607 33.61720
- B1 40.774497 30.980646 4.853984
- B2 12.786912 11.654674 29.31582
- B3 29.900282 19.631992 10.31426
- B4 8.854344 6.750602 10.88177
- B5 35.445183 44.094908 8.863355
- B6 49.113465 43.647237 6.214123
- C1 6.659992 5.799339 20.11315
- C2 15.407588 23.700772 7.772715
- C3 21.254733 12.710445 3.970060
- C4 58.616280 59.203678 6.871706
- C5 31.444170 20.458848 23.34756
- C6 13.290512 19.046913 29.20373
- D1 87.016740 90.636247 69.99650
- D2 57.632418 59.860806 48.52846
- D3 35.434916 36.927843 30.23039
- D4 18.558911 19.319142 15.73822
- D5 8.770657 9.165214 7.636996
- D6 3.216922 3.320339 2.732945
+EXPECTED XYZ
+SAT1 31.444334 19.286094 6.888559
+SAT2 56.064662 44.030373 6.427599
+SAT3 67.324242 67.447159 7.468562
+SAT4 15.570651 29.465796 11.20434
+SAT5 21.619963 29.778971 41.25516
+SAT6 17.456572 19.372800 46.61877
+SAT7 24.114288 18.910816 30.96444
+SAT8 30.360635 18.858573 16.93814
+WBP1 55.603171 57.729295 46.42132
+WBP2 57.049606 60.324512 49.89966
+WBP3 53.811668 58.177050 49.42470
+WBP4 52.378305 57.343255 49.64556
+WBP5 52.469763 58.680177 51.97625
+WBL1 59.661034 59.332741 48.55177
+WBL2 59.041480 59.368909 48.29234
+WBL3 55.920447 58.052670 47.03935
+WBL4 55.083575 58.526581 51.10275
+WBL5 53.892264 58.200472 53.59833
+NEU1 3.151107 3.263644 2.737095
+NEU2 3.610326 3.768524 3.225077
+NEU3 4.585675 4.814770 4.063276
+NEU4 5.242110 5.523981 4.582603
+NEU5 44.365128 46.364955 37.75652
+NEU6 55.836099 58.281967 47.53593
+NEU7 70.627230 73.603361 59.69403
+NEU8 88.638466 92.368156 71.51666
+A1 11.411919 10.072672 5.112897
+A2 38.118655 34.074205 18.53409
+A3 16.687521 18.224488 25.41503
+A4 11.119565 13.272712 5.165291
+A5 23.995041 23.022599 32.25695
+A6 29.864887 41.242607 33.61720
+B1 40.774497 30.980646 4.853984
+B2 12.786912 11.654674 29.31582
+B3 29.900282 19.631992 10.31426
+B4 8.854344 6.750602 10.88177
+B5 35.445183 44.094908 8.863355
+B6 49.113465 43.647237 6.214123
+C1 6.659992 5.799339 20.11315
+C2 15.407588 23.700772 7.772715
+C3 21.254733 12.710445 3.970060
+C4 58.616280 59.203678 6.871706
+C5 31.444170 20.458848 23.34756
+C6 13.290512 19.046913 29.20373
+D1 87.016740 90.636247 69.99650
+D2 57.632418 59.860806 48.52846
+D3 35.434916 36.927843 30.23039
+D4 18.558911 19.319142 15.73822
+D5 8.770657 9.165214 7.636996
+D6 3.216922 3.320339 2.732945
diff --git a/ref/SpyderChecker24.cht b/ref/SpyderChecker24.cht
deleted file mode 100644
index a67bbf6..0000000
--- a/ref/SpyderChecker24.cht
+++ /dev/null
@@ -1,59 +0,0 @@
-BOXES 25
- F _ _ 11 11 405.5 11 405.5 609.5 11 609.5
- D ALL ALL _ _ 415 619 0 0 0 0
- X A D 1 6 88.5 88.5 11 11 102 102
-
-
-BOX_SHRINK 8.0
-
-REF_ROTATION 0.0
-
-XLIST 8
- 11.0 1.0 1.0
- 99.5 1.0 1.0
- 113.0 1.0 1.0
- 201.5 1.0 1.0
- 215.0 1.0 1.0
- 303.5 1.0 1.0
- 317.0 1.0 1.0
- 405.5 1.0 1.0
-
-YLIST 12
- 11.0 1.0 1.0
- 99.5 1.0 1.0
- 113.0 1.0 1.0
- 201.5 1.0 1.0
- 215.0 1.0 1.0
- 303.5 1.0 1.0
- 317.0 1.0 1.0
- 405.5 1.0 1.0
- 419.0 1.0 1.0
- 507.5 1.0 1.0
- 521.0 1.0 1.0
- 609.5 1.0 1.0
-
-EXPECTED XYZ 24
- A1 85.00 89.31 96.33
- A2 54.09 56.94 61.35
- A3 32.55 34.33 36.79
- A4 17.72 18.68 20.09
- A5 7.89 8.30 8.87
- A6 2.65 2.78 3.12
- B1 12.84 18.14 36.39
- B2 28.20 18.34 29.84
- B3 57.08 61.01 8.56
- B4 19.63 11.29 4.87
- B5 13.70 22.39 9.24
- B6 7.32 5.35 26.41
- C1 35.76 28.16 5.45
- C2 12.71 11.07 36.60
- C3 27.74 18.51 13.48
- C4 9.34 6.93 16.38
- C5 33.22 43.77 10.98
- C6 46.49 42.42 7.53
- D1 30.35 42.13 42.95
- D2 24.45 23.05 44.34
- D3 9.73 12.51 6.59
- D4 17.28 18.47 34.69
- D5 36.71 34.18 24.66
- D6 10.43 9.32 6.27
diff --git a/ref/SpyderChecker24.cie b/ref/SpyderChecker24.cie
deleted file mode 100644
index 49bdf61..0000000
--- a/ref/SpyderChecker24.cie
+++ /dev/null
@@ -1,38 +0,0 @@
-IT8.7/2
-ORIGINATOR "Jose Pereira"
-DESCRIPTOR "Datacolor SpyderCheckr (D65)"
-CREATED "dec, 19. 2011"
-MANUFACTURER "DataColor"
-
-NUMBER_OF_FIELDS 7
-BEGIN_DATA_FORMAT
-SAMPLE_ID XYZ_X XYZ_Y XYZ_Z
-END_DATA_FORMAT
-
-NUMBER_OF_SETS 24
-BEGIN_DATA
-A1 85.00 89.31 96.33
-A2 54.09 56.94 61.35
-A3 32.55 34.33 36.79
-A4 17.72 18.68 20.09
-A5 7.89 8.30 8.87
-A6 2.65 2.78 3.12
-B1 12.84 18.14 36.39
-B2 28.20 18.34 29.84
-B3 57.08 61.01 8.56
-B4 19.63 11.29 4.87
-B5 13.70 22.39 9.24
-B6 7.32 5.35 26.41
-C1 35.76 28.16 5.45
-C2 12.71 11.07 36.60
-C3 27.74 18.51 13.48
-C4 9.34 6.93 16.38
-C5 33.22 43.77 10.98
-C6 46.49 42.42 7.53
-D1 30.35 42.13 42.95
-D2 24.45 23.05 44.34
-D3 9.73 12.51 6.59
-D4 17.28 18.47 34.69
-D5 36.71 34.18 24.66
-D6 10.43 9.32 6.27
-END_DATA
diff --git a/ref/afiles b/ref/afiles
index bd8a2f1..360448a 100644
--- a/ref/afiles
+++ b/ref/afiles
@@ -28,8 +28,6 @@ ColorCheckerPassport.cht
ColorCheckerPassport.cie
SpyderChecker.cht
SpyderChecker.cie
-SpyderChecker24.cht
-SpyderChecker24.cie
ECI2002.ti2
ECI2002R.ti2
FograStrip2.ti1
diff --git a/ref/linear.cal b/ref/linear.cal
index 9c88605..b686edc 100644
--- a/ref/linear.cal
+++ b/ref/linear.cal
@@ -2,7 +2,7 @@ CAL
DESCRIPTOR "Argyll Device Calibration Curves"
ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
+CREATED "Thu Jun 04 09:27:53 2015"
DEVICE_CLASS "DISPLAY"
COLOR_REP "RGB"
diff --git a/ref/strange.cal b/ref/strange.cal
index 5f2e94d..6757f3b 100644
--- a/ref/strange.cal
+++ b/ref/strange.cal
@@ -2,7 +2,7 @@ CAL
DESCRIPTOR "Argyll Device Calibration Curves"
ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
+CREATED "Thu Jun 04 09:27:53 2015"
DEVICE_CLASS "DISPLAY"
COLOR_REP "RGB"
diff --git a/rspl/gam.c b/rspl/gam.c
index 0765e05..e46780f 100644
--- a/rspl/gam.c
+++ b/rspl/gam.c
@@ -18,52 +18,6 @@
* Latest simplex/linear equation version.
*/
-/*
-
- This probably needs re-writing, since (I think) it doesn't take gamut
- self intersection into account. Outline would be:
-
- Have a spactial cache structure that contains list of potentialy
- intersecting triangles for any point. Create this incrementally.
- Each triangle can be replaced by a list of fragment triangles
- sharing the same plane.
-
- i.e.
-
- triangle planes
- triangles
- edges
- vertexes
-
- Initialization:
-
- Locate extreme vertex
- Locate triangle that uses that vertex that is most elevated
- in that direction as initial surface.
- Intersect that triangle with all other triangles nearby, and
- retain the fragment that has that vertex.
- List of open edges is initial triangle edges.
- Track outward and inward faces of all triangles in open surface.
-
- Basic loop:
-
- While edge list is non-empty {
- Locate adjacent triangle that is not part of surface that
- is most accutely angled to outside face.
-
- Intersect that triangle with all other triangles using cache structure,
- hanging on to all resulting fragments that are part of that edge.
-
- Add those fragments to the open surface.
-
- }
-
- Each intersection adds new nodes, and splits a triangle into
- about 8 smaller triangles. Trick is to avoid slivers and
- numerical issues with triangles.
-*/
-
-
/* TTBD:
Add ouutput curve lookup callback support.
diff --git a/scanin/Jamfile b/scanin/Jamfile
index 2cb05fb..7a1ab7a 100644
--- a/scanin/Jamfile
+++ b/scanin/Jamfile
@@ -13,8 +13,7 @@ Samples = it8.cht ColorChecker.cht ColorChecker.cie ColorCheckerDC.cht ColorChec
ColorCheckerPassport.cht ColorCheckerPassport.cie
QPcard_201.cht QPcard_201.cie QPcard_202.cht QPcard_202.cie CMP_DT_003.cht
CMP_Digital_Target-4.cht CMP_Digital_Target-4.ti2 CMP_Digital_Target-4.cie
- LaserSoftDCPro.cht SpyderChecker.cht SpyderChecker.cie
- SpyderChecker24.cht SpyderChecker24.cie ;
+ LaserSoftDCPro.cht SpyderChecker.cht SpyderChecker.cie ;
#Install
InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
diff --git a/scanin/SpyderChecker24.cht b/scanin/SpyderChecker24.cht
deleted file mode 100644
index a67bbf6..0000000
--- a/scanin/SpyderChecker24.cht
+++ /dev/null
@@ -1,59 +0,0 @@
-BOXES 25
- F _ _ 11 11 405.5 11 405.5 609.5 11 609.5
- D ALL ALL _ _ 415 619 0 0 0 0
- X A D 1 6 88.5 88.5 11 11 102 102
-
-
-BOX_SHRINK 8.0
-
-REF_ROTATION 0.0
-
-XLIST 8
- 11.0 1.0 1.0
- 99.5 1.0 1.0
- 113.0 1.0 1.0
- 201.5 1.0 1.0
- 215.0 1.0 1.0
- 303.5 1.0 1.0
- 317.0 1.0 1.0
- 405.5 1.0 1.0
-
-YLIST 12
- 11.0 1.0 1.0
- 99.5 1.0 1.0
- 113.0 1.0 1.0
- 201.5 1.0 1.0
- 215.0 1.0 1.0
- 303.5 1.0 1.0
- 317.0 1.0 1.0
- 405.5 1.0 1.0
- 419.0 1.0 1.0
- 507.5 1.0 1.0
- 521.0 1.0 1.0
- 609.5 1.0 1.0
-
-EXPECTED XYZ 24
- A1 85.00 89.31 96.33
- A2 54.09 56.94 61.35
- A3 32.55 34.33 36.79
- A4 17.72 18.68 20.09
- A5 7.89 8.30 8.87
- A6 2.65 2.78 3.12
- B1 12.84 18.14 36.39
- B2 28.20 18.34 29.84
- B3 57.08 61.01 8.56
- B4 19.63 11.29 4.87
- B5 13.70 22.39 9.24
- B6 7.32 5.35 26.41
- C1 35.76 28.16 5.45
- C2 12.71 11.07 36.60
- C3 27.74 18.51 13.48
- C4 9.34 6.93 16.38
- C5 33.22 43.77 10.98
- C6 46.49 42.42 7.53
- D1 30.35 42.13 42.95
- D2 24.45 23.05 44.34
- D3 9.73 12.51 6.59
- D4 17.28 18.47 34.69
- D5 36.71 34.18 24.66
- D6 10.43 9.32 6.27
diff --git a/scanin/SpyderChecker24.cie b/scanin/SpyderChecker24.cie
deleted file mode 100644
index 49bdf61..0000000
--- a/scanin/SpyderChecker24.cie
+++ /dev/null
@@ -1,38 +0,0 @@
-IT8.7/2
-ORIGINATOR "Jose Pereira"
-DESCRIPTOR "Datacolor SpyderCheckr (D65)"
-CREATED "dec, 19. 2011"
-MANUFACTURER "DataColor"
-
-NUMBER_OF_FIELDS 7
-BEGIN_DATA_FORMAT
-SAMPLE_ID XYZ_X XYZ_Y XYZ_Z
-END_DATA_FORMAT
-
-NUMBER_OF_SETS 24
-BEGIN_DATA
-A1 85.00 89.31 96.33
-A2 54.09 56.94 61.35
-A3 32.55 34.33 36.79
-A4 17.72 18.68 20.09
-A5 7.89 8.30 8.87
-A6 2.65 2.78 3.12
-B1 12.84 18.14 36.39
-B2 28.20 18.34 29.84
-B3 57.08 61.01 8.56
-B4 19.63 11.29 4.87
-B5 13.70 22.39 9.24
-B6 7.32 5.35 26.41
-C1 35.76 28.16 5.45
-C2 12.71 11.07 36.60
-C3 27.74 18.51 13.48
-C4 9.34 6.93 16.38
-C5 33.22 43.77 10.98
-C6 46.49 42.42 7.53
-D1 30.35 42.13 42.95
-D2 24.45 23.05 44.34
-D3 9.73 12.51 6.59
-D4 17.28 18.47 34.69
-D5 36.71 34.18 24.66
-D6 10.43 9.32 6.27
-END_DATA
diff --git a/scanin/afiles b/scanin/afiles
index 90097e6..399961c 100644
--- a/scanin/afiles
+++ b/scanin/afiles
@@ -28,5 +28,3 @@ CMP_Digital_Target-4.cie
LaserSoftDCPro.cht
SpyderChecker.cht
SpyderChecker.cie
-SpyderChecker24.cht
-SpyderChecker24.cie
diff --git a/spectro/aglob.c b/spectro/aglob.c
index dbf9157..2ba37d5 100644
--- a/spectro/aglob.c
+++ b/spectro/aglob.c
@@ -42,7 +42,6 @@
# include <pthread.h>
#endif
-#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
diff --git a/spectro/ccxxmake.c b/spectro/ccxxmake.c
index 418affc..4202c67 100644
--- a/spectro/ccxxmake.c
+++ b/spectro/ccxxmake.c
@@ -27,9 +27,6 @@
/*
TTBD:
- Would be nice to have a way of not changing the target
- instruments absolute calibration.
-
Would be nice to have a veryify option that produces
a fit report of a matrix vs. the input files.
@@ -37,7 +34,7 @@
(See post from umberto.guidali@tiscali.it)
Would be nice to be able to use an i1D3 to correct other instruments,
- or an i1D3 created .ti3 as the reference. (can do this with .ti3 files).
+ or an i1D3 created .ti3 as the reference.
Would be nice to have an option of providing two ICC profiles,
instead of using .ti3 files (?? How well would it work though ?)
diff --git a/spectro/chartread.c b/spectro/chartread.c
index 9cf6c22..0fc7646 100644
--- a/spectro/chartread.c
+++ b/spectro/chartread.c
@@ -198,7 +198,6 @@ alphix *paix, /* Pass (row) index generators */
alphix *saix, /* Step (patch) index generators */
int ixord, /* Index order, 0 = pass then step */
int rstart, /* Random start/chart id */
-int rand, /* Random order used - can do auto strip ID & Bi-Dir */
int hex, /* Hexagon test patches */
icompath *ipath, /* Instrument path to open */
flow_control fc, /* flow control */
@@ -1390,7 +1389,7 @@ a1log *log /* verb, debug & error log */
int xbdir; /* Expected pass overall pass direction */
double xwerror = 0.0; /* Expected pass worst error in best strip */
- if (rand && disbidi == 0 && (cap2 & inst2_bidi_scan))
+ if (disbidi == 0 && (cap2 & inst2_bidi_scan))
dirrg = 2; /* Enable bi-directional strip recognition */
/* DTP51 has a nasty habit of misaligning test squares by +/- 1 */
@@ -1464,7 +1463,7 @@ a1log *log /* verb, debug & error log */
}
}
}
- if (emit_warnings != 0 && rand && boroi != oroi) { /* Looks like the wrong strip */
+ if (emit_warnings != 0 && boroi != oroi) { /* Looks like the wrong strip */
char *mm = NULL;
mm = paix->aix(paix, boroi);
#ifdef DEBUG
@@ -2111,7 +2110,6 @@ int main(int argc, char *argv[]) {
alphix *paix, *saix; /* Pass and Step index generators */
int ixord = 0; /* Index order, 0 = pass then step */
int rstart = 0; /* Random start/chart id */
- int rand = 0; /* Random patch order, - can use auto strip ID and Bi-Di */
int hex = 0; /* Hexagon pattern layout */
time_t clk = time(0);
struct tm *tsp = localtime(&clk);
@@ -2474,13 +2472,10 @@ int main(int argc, char *argv[]) {
ixord = 1;
}
- if ((ti = icg->find_kword(icg, 0, "RANDOM_START")) >= 0) {
+ if ((ti = icg->find_kword(icg, 0, "RANDOM_START")) >= 0)
rstart = atoi(icg->t[0].kdata[ti]);
- rand = 1;
- } else if ((ti = icg->find_kword(icg, 0, "CHART_ID")) >= 0) {
+ else if ((ti = icg->find_kword(icg, 0, "CHART_ID")) >= 0)
rstart = atoi(icg->t[0].kdata[ti]);
- rand = 0;
- }
if ((ti = icg->find_kword(icg, 0, "HEXAGON_PATCHES")) >= 0)
hex = 1;
@@ -2508,10 +2503,6 @@ int main(int argc, char *argv[]) {
tlen = atof(icg->t[0].kdata[ti]);
}
- if (itype != instDTP20 && !rand && disbidi == 0) {
- warning("Can't do bi-directional strip recognition without randomize patch locations");
- }
-
if (verb) {
printf("Steps in each Pass = %d\n",stipa);
printf("Passes in each Strip = ");
@@ -2847,7 +2838,7 @@ int main(int argc, char *argv[]) {
/* Read all of the strips in */
if (read_strips(itype, scols, &atype, npat, totpa, stipa, pis, paix,
- saix, ixord, rstart, rand, hex, ipath, fc, plen, glen, tlen,
+ saix, ixord, rstart, hex, ipath, fc, plen, glen, tlen,
trans, emis, displ, dtype, fe, nocal, disbidi, highres, ccxxname, obType,
scan_tol, pbypatch, xtern, spectral, uvmode, accurate_expd,
emit_warnings, g_log) == 0) {
diff --git a/spectro/colorhug.c b/spectro/colorhug.c
index 7397314..1b2a56d 100644
--- a/spectro/colorhug.c
+++ b/spectro/colorhug.c
@@ -825,7 +825,6 @@ colorhug_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
inst_del_disptype_list(p->dtlist, p->ndtlist);
- p->vdel(pp);
free(p);
}
}
diff --git a/spectro/conv.c b/spectro/conv.c
index 94023db..1a8c78b 100644
--- a/spectro/conv.c
+++ b/spectro/conv.c
@@ -68,7 +68,6 @@
//#include <stdbool.h>
#include <sys/sysctl.h>
#include <sys/param.h>
-#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
@@ -264,14 +263,12 @@ static int beep_msec;
/* Delayed beep handler */
static int delayed_beep(void *pp) {
msec_sleep(beep_delay);
- a1logd(g_log,8, "msec_beep activate\n");
Beep(beep_freq, beep_msec);
return 0;
}
/* Activate the system beeper */
void msec_beep(int delay, int freq, int msec) {
- a1logd(g_log,8, "msec_beep %d msec\n",msec);
if (delay > 0) {
if (beep_thread != NULL)
beep_thread->del(beep_thread);
@@ -281,7 +278,6 @@ void msec_beep(int delay, int freq, int msec) {
if ((beep_thread = new_athread(delayed_beep, NULL)) == NULL)
a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n");
} else {
- a1logd(g_log,8, "msec_beep activate\n");
Beep(freq, msec);
}
}
@@ -553,8 +549,6 @@ void empty_con_chars(void) {
}
/* Sleep for the given number of msec */
-/* (Note that OS X 10.9+ App Nap can wreck this, unless */
-/* it is turned off.) */
void msec_sleep(unsigned int msec) {
#ifdef NEVER
if (msec > 1000) {
@@ -785,7 +779,6 @@ static int beep_msec;
/* Delayed beep handler */
static int delayed_beep(void *pp) {
msec_sleep(beep_delay);
- a1logd(g_log,8, "msec_beep activate\n");
#ifdef __APPLE__
# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
AudioServicesPlayAlertSound(kUserPreferredAlert);
@@ -801,7 +794,6 @@ static int delayed_beep(void *pp) {
/* Activate the system beeper */
void msec_beep(int delay, int freq, int msec) {
- a1logd(g_log,8, "msec_beep %d msec\n",msec);
if (delay > 0) {
if (beep_thread != NULL)
beep_thread->del(beep_thread);
@@ -811,7 +803,6 @@ void msec_beep(int delay, int freq, int msec) {
if ((beep_thread = new_athread(delayed_beep, NULL)) == NULL)
a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n");
} else {
- a1logd(g_log,8, "msec_beep activate\n");
#ifdef __APPLE__
# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
AudioServicesPlayAlertSound(kUserPreferredAlert);
diff --git a/spectro/dispwin.c b/spectro/dispwin.c
index fffbaee..69536f3 100644
--- a/spectro/dispwin.c
+++ b/spectro/dispwin.c
@@ -3624,9 +3624,6 @@ static void create_my_win(NSRect rect, osx_cntx_t *cx) {
[cx->view setCntx:(void *)cx];
[cx->window setContentView: cx->view];
- /* Moves the window to the front of the screen list within its level, */
- /* and show the window (i.e. make it "key") */
- /* Trigger crash on OS X 10.11 El Capitan ? */
[cx->window makeKeyAndOrderFront: nil];
/* Use a null color transform to ensure device values */
@@ -6454,7 +6451,7 @@ main(int argc, char *argv[]) {
/* Try darkening it */
for (j = 0; j < 3; j++) {
for (i = 0; i < dw->r->nent; i++) {
- dw->r->v[j][i] = pow(dw->or->v[j][i], 1.6);
+ dw->r->v[j][i] = pow(dw->or->v[j][i], 2.0);
}
}
printf("Darkening screen\n");
@@ -6467,7 +6464,7 @@ main(int argc, char *argv[]) {
/* Try lightening it */
for (j = 0; j < 3; j++) {
for (i = 0; i < dw->r->nent; i++) {
- dw->r->v[j][i] = pow(dw->or->v[j][i], 0.625);
+ dw->r->v[j][i] = pow(dw->or->v[j][i], 0.5);
}
}
printf("Lightening screen\n");
diff --git a/spectro/dtp20.c b/spectro/dtp20.c
index 6af2484..a504803 100644
--- a/spectro/dtp20.c
+++ b/spectro/dtp20.c
@@ -217,7 +217,7 @@ double top) { /* Timout in seconds */
}
/* Establish communications with a DTP20 */
-/* Return DTP20_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
dtp20_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
dtp20 *p = (dtp20 *)pp;
@@ -1402,8 +1402,7 @@ dtp20_del(inst *pp) {
dtp20 *p = (dtp20 *)pp;
if (p->icom != NULL)
p->icom->del(p->icom);
- p->vdel(pp);
- free(p);
+ free (p);
}
/* Set the instrument capabilities */
diff --git a/spectro/dtp22.c b/spectro/dtp22.c
index 2cb3634..d332ffc 100644
--- a/spectro/dtp22.c
+++ b/spectro/dtp22.c
@@ -164,7 +164,7 @@ dtp22_command(dtp22 *p, char *in, char *out, int bsize, double to) {
/* Establish communications with a DTP22 */
/* If it's a serial port, use the baud rate given, and timeout in to secs */
-/* Return DTP22_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
dtp22_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
dtp22 *p = (dtp22 *) pp;
@@ -930,7 +930,6 @@ dtp22_del(inst *pp) {
dtp22 *p = (dtp22 *)pp;
if (p->icom != NULL)
p->icom->del(p->icom);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/dtp41.c b/spectro/dtp41.c
index 44ac6c6..5c3361c 100644
--- a/spectro/dtp41.c
+++ b/spectro/dtp41.c
@@ -145,7 +145,7 @@ dtp41_command(dtp41 *p, char *in, char *out, int bsize, double to) {
/* Establish communications with a DTP41 */
/* Use the baud rate given, and timeout in to secs */
-/* Return DTP41_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
dtp41_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
dtp41 *p = (dtp41 *)pp;
@@ -1085,8 +1085,7 @@ dtp41_del(inst *pp) {
dtp41 *p = (dtp41 *)pp;
if (p->icom != NULL)
p->icom->del(p->icom);
- p->vdel(pp);
- free(p);
+ free (p);
}
/* Interogate the device to discover its capabilities */
diff --git a/spectro/dtp51.c b/spectro/dtp51.c
index ab1999d..cfd1265 100644
--- a/spectro/dtp51.c
+++ b/spectro/dtp51.c
@@ -180,7 +180,7 @@ double to) { /* Timout in seconts */
/* Establish communications with a DTP51 */
/* Use the baud rate given, and timeout in to secs */
-/* Return DTP51_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
dtp51_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
dtp51 *p = (dtp51 *)pp;
@@ -787,7 +787,6 @@ dtp51_del(inst *pp) {
dtp51 *p = (dtp51 *)pp;
if (p->icom != NULL)
p->icom->del(p->icom);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/dtp92.c b/spectro/dtp92.c
index 3b6dacd..1ed9bc1 100644
--- a/spectro/dtp92.c
+++ b/spectro/dtp92.c
@@ -169,7 +169,7 @@ dtp92_command(dtp92 *p, char *in, char *out, int bsize, double to) {
/* Establish communications with a DTP92 */
/* If it's a serial port, use the baud rate given, and timeout in to secs */
-/* Return DTP92_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
dtp92 *p = (dtp92 *) pp;
@@ -1023,7 +1023,6 @@ dtp92_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
inst_del_disptype_list(p->dtlist, p->ndtlist);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/ex1.c b/spectro/ex1.c
index b336cbc..93d0a31 100644
--- a/spectro/ex1.c
+++ b/spectro/ex1.c
@@ -147,10 +147,6 @@ static int ex1_set_boxcar(ex1 *p, int nobox);
static int ex1_measure(ex1 *p, double *raw);
-static int ex1_save_calibration(ex1 *p);
-static int ex1_restore_calibration(ex1 *p);
-static int ex1_touch_calibration(ex1 *p);
-
/* ----------------------------------------------------------------- */
/* Establish communications with a ex1 */
@@ -1042,7 +1038,6 @@ ex1_del(inst *pp) {
if (p->conv != NULL)
p->conv->del(p->conv);
- p->vdel(pp);
free(p);
}
}
@@ -1239,7 +1234,7 @@ extern ex1 *new_ex1(icoms *icom, instType itype) {
/* =============================================================================== */
/* Calibration info save/restore */
-static int ex1_save_calibration(ex1 *p) {
+int ex1_save_calibration(ex1 *p) {
int ev = EX1_OK;
int i;
char fname[100]; /* Name */
@@ -1285,7 +1280,7 @@ static int ex1_save_calibration(ex1 *p) {
}
/* Restore the all modes calibration from the local system */
-static int ex1_restore_calibration(ex1 *p) {
+int ex1_restore_calibration(ex1 *p) {
int ev = EX1_OK;
int i, j;
char fname[100]; /* Name */
@@ -1358,7 +1353,7 @@ static int ex1_restore_calibration(ex1 *p) {
return ev;
}
-static int ex1_touch_calibration(ex1 *p) {
+int ex1_touch_calibration(ex1 *p) {
int ev = EX1_OK;
char fname[100]; /* Name */
int rv;
diff --git a/spectro/hcfr.c b/spectro/hcfr.c
index a6c457e..d0a8261 100644
--- a/spectro/hcfr.c
+++ b/spectro/hcfr.c
@@ -637,7 +637,6 @@ hcfr_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
inst_del_disptype_list(p->dtlist, p->ndtlist);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/huey.c b/spectro/huey.c
index b09ed2c..79f8089 100644
--- a/spectro/huey.c
+++ b/spectro/huey.c
@@ -159,7 +159,7 @@ static char *inst_desc(int cc) {
/* The Huey is set up as an HID device, which can ease the need */
/* for providing a kernel driver on MSWindows systems, */
/* but it doesn't seem to actually be used as an HID device. */
-/* We allow for communicating via usbio, or an HID driver. */
+/* We allow for communicating via libusb, or an HID driver. */
static inst_code
huey_command(
huey *p, /* huey object */
@@ -1026,7 +1026,7 @@ static inst_code set_default_disp_type(huey *p);
/* Establish communications with a HUEY */
/* If it's a serial port, use the baud rate given, and timeout in to secs */
-/* Return HUEY_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
huey_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
huey *p = (huey *) pp;
@@ -1400,7 +1400,6 @@ huey_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
inst_del_disptype_list(p->dtlist, p->ndtlist);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/i1d3.c b/spectro/i1d3.c
index df7d3f0..689f328 100644
--- a/spectro/i1d3.c
+++ b/spectro/i1d3.c
@@ -34,10 +34,6 @@
and agreed to support.
*/
-/* TTBD:
-
-*/
-
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -74,8 +70,6 @@
#define I1D3_MEAS_TIMEOUT 40.0 /* Longest reading timeout in seconds */
/* Typically 20.0 is the maximum needed. */
-#define I1D3_SAT_FREQ 100000.0 /* L2F sensor frequency limit */
-
static inst_code i1d3_interp_code(inst *pp, int ec);
static inst_code i1d3_check_unlock(i1d3 *p);
@@ -111,12 +105,6 @@ static int icoms2i1d3_err(int se, int torc) {
/* and byte 1 is the sub code for command 0x00 . The response is byte 0 */
/* error code, byte 1 echoing the major command number. */
/* Major code 00 works when locked ? */
-/* Response codes:
-
- 00 OK
- 83 After pulse count measure in low light. Means ???
-
- */
typedef enum {
i1d3_getinfo = 0x0000, /* Product name + Firmware version + Firmware Date string */
i1d3_status = 0x0001, /* status number ?? */
@@ -186,7 +174,7 @@ static char *inst_desc(i1Disp3CC cc) {
/* The i1d3 is set up as an HID device, which can ease the need */
/* for providing a kernel driver on MSWindows systems, */
/* but it doesn't seem to actually be used as an HID device. */
-/* We allow for communicating via usbio, or an HID driver. */
+/* We allow for communicating via libusb, or an HID driver. */
static inst_code
i1d3_command(
i1d3 *p, /* i1d3 object */
@@ -277,21 +265,6 @@ i1d3_command(
rv = i1d3_interp_code((inst *)p, I1D3_BAD_RD_LENGTH);
}
- /* Hmm. Not sure about this bug workaround. Is this a rev B thing ? */
- /* May get status 0x83 on i1d3_measure2 when there are no transitions ? */
- /* If so, ignore the error. */
- if (rv == inst_ok && cc == i1d3_measure2 && recv[1] == 0x02 && recv[0] == 0x83) {
- int i;
- for (i = 2; i < 14; i++) {
- if (recv[i] != 0)
- break;
- }
- if (i >= 14) { /* returned all zero's */
- if (!nd) a1logd(p->log, 1, "i1d3_command: ignoring status byte = 0x%x\n",recv[0]);
- recv[0] = 0x00; /* Fudge OK status */
- }
- }
-
/* The first byte returned seems to be a command result error code. */
if (rv == inst_ok && recv[0] != 0x00) {
if (!nd) a1logd(p->log, 1, "i1d3_command: status byte != 00 = 0x%x\n",recv[0]);
@@ -783,7 +756,7 @@ static inst_code
i1d3_freq_measure(
i1d3 *p, /* Object */
double *inttime, /* Integration time in seconds. (Return clock rounded) */
- double rgb[3] /* Return the RGB count values */
+ double rgb[3] /* Return the RGB values */
) {
int intclks;
unsigned char todev[64];
@@ -1595,11 +1568,6 @@ i1d3_take_emis_measurement(
}
a1logd(p->log,3,"Got %f %f %f raw, %f %f %f Hz\n",rmeas[0],rmeas[1],rmeas[2],rgb[0],rgb[1],rgb[2]);
-
- for (i = 0; i < 3; i++) {
- if (rgb[i] > I1D3_SAT_FREQ)
- return i1d3_interp_code((inst *)p, I1D3_TOOBRIGHT);
- }
}
/* If some period measurement will be done */
@@ -1895,11 +1863,6 @@ i1d3_take_emis_measurement(
a1logd(p->log,3,"Got %f %f %f raw, %f %f %f Hz after re-measure\n",rmeas[0],rmeas[1],rmeas[2],rgb[0],rgb[1],rgb[2]);
- for (i = 0; i < 3; i++) {
- if (rgb[i] > I1D3_SAT_FREQ)
- return i1d3_interp_code((inst *)p, I1D3_TOOBRIGHT);
- }
-
} else {
/* Use period measurement of the target number of edges */
/* (Note that if the patch isn't constant and drops compared to */
@@ -1944,11 +1907,6 @@ i1d3_take_emis_measurement(
}
a1logd(p->log,3,"Cooked RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
-
- for (i = 0; i < 3; i++) {
- if (rgb[i] > I1D3_SAT_FREQ)
- return i1d3_interp_code((inst *)p, I1D3_TOOBRIGHT);
- }
return inst_ok;
}
@@ -2025,7 +1983,7 @@ static inst_code i1d3_decode_intEE(
p->serial_no[20] = '\000';
strncpy(p->vers_no, (char *)buf + 0x2C, 10);
- p->vers_no[10] = '\000';
+ p->serial_no[10] = '\000';
/* Read the black level offset */
for (i = 0; i < 3; i++) {
@@ -2437,7 +2395,7 @@ i1d3_set_cal(i1d3 *p) {
/* ------------------------------------------------------------------------ */
/* Establish communications with a I1D3 */
-/* Return I1D3_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
i1d3 *p = (i1d3 *) pp;
@@ -3329,9 +3287,6 @@ i1d3_interp_error(inst *pp, int ec) {
case I1D3_INT_THREADFAILED:
return "Starting diffuser position thread failed";
- case I1D3_TOOBRIGHT:
- return "Too bright to read accuractly";
-
case I1D3_NO_COMS:
return "Communications hasn't been established";;
case I1D3_NOT_INITED:
@@ -3400,13 +3355,11 @@ i1d3_interp_code(inst *pp, int ec) {
case I1D3_BAD_EX_CHSUM:
return inst_hardware_fail | ec;
- case I1D3_TOOBRIGHT:
- return inst_misread | ec;
-
/* Unused:
inst_notify
inst_warning
inst_unknown_model
+ inst_misread
inst_nonesaved
inst_nochmatch
inst_needs_cal
@@ -3458,7 +3411,6 @@ i1d3_del(inst *pp) {
if (p->samples != NULL)
free(p->samples);
amutex_del(p->lock);
- p->vdel(pp);
free(p);
}
}
diff --git a/spectro/i1d3.h b/spectro/i1d3.h
index bb239df..47f3858 100644
--- a/spectro/i1d3.h
+++ b/spectro/i1d3.h
@@ -63,7 +63,6 @@
#define I1D3_BAD_RET_STAT 0x13
#define I1D3_BAD_RET_CMD 0x14
#define I1D3_NOT_INITED 0x15
-#define I1D3_TOOBRIGHT 0x16
/* Internal errors */
#define I1D3_BAD_MEM_ADDRESS 0x20
diff --git a/spectro/i1disp.c b/spectro/i1disp.c
index 489c6cd..437e1fa 100644
--- a/spectro/i1disp.c
+++ b/spectro/i1disp.c
@@ -1737,7 +1737,7 @@ i1disp_compute_factors(
/* Establish communications with a I1DISP */
/* If it's a serial port, use the baud rate given, and timeout in to secs */
-/* Return I1DISP_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
i1disp_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
i1disp *p = (i1disp *) pp;
@@ -2240,7 +2240,6 @@ i1disp_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
inst_del_disptype_list(p->dtlist, p->ndtlist);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/i1pro.c b/spectro/i1pro.c
index 816aee5..96335cc 100644
--- a/spectro/i1pro.c
+++ b/spectro/i1pro.c
@@ -79,7 +79,7 @@ static inst_code i1pro_interp_code(i1pro *p, i1pro_code ec);
/* Establish communications with a I1DISP */
/* If it's a serial port, use the baud rate given, and timeout in to secs */
-/* Return I1PRO_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
i1pro *p = (i1pro *) pp;
@@ -806,7 +806,6 @@ i1pro_del(inst *pp) {
del_i1proimp(p);
if (p->icom != NULL)
p->icom->del(p->icom);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/i1pro_imp.c b/spectro/i1pro_imp.c
index 8577f8c..0b6fc69 100644
--- a/spectro/i1pro_imp.c
+++ b/spectro/i1pro_imp.c
@@ -149,8 +149,6 @@
/* Should be good up to 275 cd/m^2 */
#define DISP_INTT3 0.3 /* High brightness display spot mode seconds per reading, */
/* Should be good up to 700 cd/m^2 */
-#define DISP_INTT4 0.1 /* Very high brightness display spot mode seconds per reading, */
- /* Should be good up to 2000 cd/m^2 ? */
#define ADARKINT_MAX 2.0 /* Max cal time for adaptive dark cal */
#define ADARKINT_MAX2 4.0 /* Max cal time for adaptive dark cal Rev E or no high gain */
@@ -400,7 +398,6 @@ void del_i1proimp(i1pro *p) {
free_dvector(s->dark_data, -1, m->nraw-1);
free_dvector(s->dark_data2, -1, m->nraw-1);
free_dvector(s->dark_data3, -1, m->nraw-1);
- free_dvector(s->dark_data4, -1, m->nraw-1);
free_dvector(s->white_data, -1, m->nraw-1);
free_dmatrix(s->idark_data, 0, 3, -1, m->nraw-1);
@@ -961,7 +958,6 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->dark_data = dvectorz(-1, m->nraw-1);
s->dark_data2 = dvectorz(-1, m->nraw-1);
s->dark_data3 = dvectorz(-1, m->nraw-1);
- s->dark_data4 = dvectorz(-1, m->nraw-1);
s->cal_valid = 0; /* Scale cal invalid */
s->cal_factor[0] = dvectorz(0, m->nwav[0]-1);
@@ -976,7 +972,6 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->dark_int_time = DISP_INTT; /* 2.0 */
s->dark_int_time2 = DISP_INTT2; /* 0.8 */
s->dark_int_time3 = DISP_INTT3; /* 0.3 */
- s->dark_int_time4 = DISP_INTT4; /* 0.1 */
s->idark_int_time[0] = s->idark_int_time[2] = m->min_int_time;
if (p->itype == instI1Pro2) {
@@ -1062,14 +1057,12 @@ i1pro_code i1pro_imp_init(i1pro *p) {
s->dark_int_time = s->inttime;
s->dark_int_time2 = DISP_INTT2; /* Alternate disp integration time (ie. 0.8) */
s->dark_int_time3 = DISP_INTT3; /* Alternate disp integration time (ie. 0.3) */
- s->dark_int_time4 = DISP_INTT4; /* Alternate disp integration time (ie. 0.1) */
s->dadaptime = 0.0;
s->wadaptime = 0.10;
s->dcaltime = DISP_INTT; /* ie. determines number of measurements */
s->dcaltime2 = DISP_INTT2 * 2; /* Make it 1.6 seconds (ie, 2 x 0.8 seconds) */
s->dcaltime3 = DISP_INTT3 * 3; /* Make it 0.9 seconds (ie, 3 x 0.3 seconds) */
- s->dcaltime4 = DISP_INTT4 * 3; /* Make it 0.3 seconds (ie, 3 x 0.1 seconds) */
s->wcaltime = 0.0;
s->dreadtime = 0.0;
s->wreadtime = DISP_INTT;
@@ -1627,10 +1620,10 @@ i1pro_code i1pro_imp_calibrate(
|| (s->emiss && !s->adaptive && !s->scan)
|| (s->trans && !s->adaptive))) {
int stm;
- int usesdct234 = 0; /* Is a mode that uses dcaltime2, 3 & 4 */
+ int usesdct23 = 0; /* Is a mode that uses dcaltime2 & 3 */
if (s->emiss && !s->adaptive && !s->scan)
- usesdct234 = 1;
+ usesdct23 = 1;
nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->inttime);
@@ -1644,7 +1637,7 @@ i1pro_code i1pro_imp_calibrate(
a1logd(p->log,2,"Execution time of dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
/* Special display mode alternate integration time black measurement */
- if (usesdct234) {
+ if (usesdct23) {
nummeas = i1pro_comp_nummeas(p, s->dcaltime2, s->dark_int_time2);
a1logd(p->log,2,"Doing 2nd initial black calibration with dcaltime2 %f, dark_int_time2 %f, nummeas %d, gainmode %d\n", s->dcaltime2, s->dark_int_time2, nummeas, s->gainmode);
stm = msec_time();
@@ -1665,17 +1658,6 @@ i1pro_code i1pro_imp_calibrate(
return ev;
}
a1logd(p->log,2,"Execution time of 3rd dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
-
- nummeas = i1pro_comp_nummeas(p, s->dcaltime4, s->dark_int_time4);
- a1logd(p->log,2,"Doing 4th initial black calibration with dcaltime4 %f, dark_int_time4 %f, nummeas %d, gainmode %d\n", s->dcaltime4, s->dark_int_time4, nummeas, s->gainmode);
- nummeas = i1pro_comp_nummeas(p, s->dcaltime4, s->dark_int_time4);
- stm = msec_time();
- if ((ev = i1pro_dark_measure(p, s->dark_data4,
- nummeas, &s->dark_int_time4, s->gainmode)) != I1PRO_OK) {
- m->mmode = mmode; /* Restore actual mode */
- return ev;
- }
- a1logd(p->log,2,"Execution time of 4rd dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
}
s->dark_valid = 1;
s->want_dcalib = 0;
@@ -1704,15 +1686,13 @@ i1pro_code i1pro_imp_calibrate(
ss->dark_gain_mode = s->dark_gain_mode;
for (k = -1; k < m->nraw; k++)
ss->dark_data[k] = s->dark_data[k];
- /* If this is a mode with dark_data2/3/4, tranfer it too */
- if (usesdct234 && ss->emiss && !ss->adaptive && !ss->scan) {
+ /* If this is a mode with dark_data2/3, tranfer it too */
+ if (usesdct23 && ss->emiss && !ss->adaptive && !ss->scan) {
ss->dark_int_time2 = s->dark_int_time2;
- ss->dark_int_time3 = s->dark_int_time3;
- ss->dark_int_time4 = s->dark_int_time4;
+ ss->dark_int_time3 = s->dark_int_time2;
for (k = -1; k < m->nraw; k++) {
ss->dark_data2[k] = s->dark_data2[k];
ss->dark_data3[k] = s->dark_data3[k];
- ss->dark_data4[k] = s->dark_data4[k];
}
}
}
@@ -2296,9 +2276,6 @@ i1pro_code i1pro_imp_calibrate(
} else if (s->dispswap == 2) {
tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
- } else if (s->dispswap == 3) {
- tv = s->inttime; s->inttime = s->dark_int_time4; s->dark_int_time4 = tv;
- tt = s->dark_data; s->dark_data = s->dark_data4; s->dark_data4 = tt;
}
s->dispswap = 0;
@@ -2307,43 +2284,30 @@ i1pro_code i1pro_imp_calibrate(
nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
ev = i1pro_whitemeasure(p, NULL, NULL, data , &scale, nummeas,
&s->inttime, s->gainmode, s->targoscale, 0);
+ /* Switch to the alternate if things are too bright */
+ /* We do this simply by swapping the alternate values in. */
if (ev == I1PRO_RD_SENSORSATURATED || scale < 1.0) {
- a1logd(p->log,2,"Switching to 2nd display integration time %f seconds\n",s->dark_int_time2);
- /* swap in 2nd display integration time */
+ a1logd(p->log,2,"Switching to alternate display integration time %f seconds\n",s->dark_int_time2);
tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
s->dispswap = 1;
/* Do another measurement of the full display white, and if it's close to */
- /* saturation, switch to the 3rd display integration time */
+ /* saturation, switch to the 3rd alternate display integration time */
nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
ev = i1pro_whitemeasure(p, NULL, NULL, data , &scale, nummeas,
&s->inttime, s->gainmode, s->targoscale, 0);
+ /* Switch to the 3rd alternate if things are too bright */
+ /* We do this simply by swapping the alternate values in. */
if (ev == I1PRO_RD_SENSORSATURATED || scale < 1.0) {
- a1logd(p->log,2,"Switching to 3rd display integration time %f seconds\n",s->dark_int_time3);
+ a1logd(p->log,2,"Switching to 3rd alternate display integration time %f seconds\n",s->dark_int_time3);
/* Undo previous swap */
tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
- /* swap in 3rd time */
+ /* swap in 2nd alternate */
tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
s->dispswap = 2;
-
- /* Do another measurement of the full display white, and if it's close to */
- /* saturation, switch to the 4th display integration time */
- nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
- ev = i1pro_whitemeasure(p, NULL, NULL, data , &scale, nummeas,
- &s->inttime, s->gainmode, s->targoscale, 0);
- if (ev == I1PRO_RD_SENSORSATURATED || scale < 1.0) {
- a1logd(p->log,2,"Switching to 4th display integration time %f seconds\n",s->dark_int_time3);
- /* Undo previous swap */
- tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
- tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
- /* swap in 4th time */
- tv = s->inttime; s->inttime = s->dark_int_time4; s->dark_int_time4 = tv;
- tt = s->dark_data; s->dark_data = s->dark_data4; s->dark_data4 = tt;
- s->dispswap = 3;
- }
}
}
free_dvector(data, -1, m->nraw-1);
@@ -2983,16 +2947,16 @@ i1pro_code i1pro_imp_measure(
/* and try again. */
if (s->emiss && !s->scan && !s->adaptive
&& ev == I1PRO_RD_SENSORSATURATED
- && s->dispswap < 3) {
+ && s->dispswap < 2) {
double *tt, tv;
if (s->dispswap == 0) {
- a1logd(p->log,2,"Switching to 2nd display integration time %f seconds\n",s->dark_int_time2);
+ a1logd(p->log,2,"Switching to alternate display integration time %f seconds\n",s->dark_int_time2);
tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
s->dispswap = 1;
} else if (s->dispswap == 1) {
- a1logd(p->log,2,"Switching to 3rd display integration time %f seconds\n",s->dark_int_time3);
+ a1logd(p->log,2,"Switching to 2nd alternate display integration time %f seconds\n",s->dark_int_time3);
/* Undo first swap */
tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
@@ -3000,15 +2964,6 @@ i1pro_code i1pro_imp_measure(
tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
s->dispswap = 2;
- } else if (s->dispswap == 2) {
- a1logd(p->log,2,"Switching to 4th display integration time %f seconds\n",s->dark_int_time4);
- /* Undo 2nd swap */
- tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
- tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
- /* Do 3rd swap */
- tv = s->inttime; s->inttime = s->dark_int_time4; s->dark_int_time4 = tv;
- tt = s->dark_data; s->dark_data = s->dark_data4; s->dark_data4 = tt;
- s->dispswap = 3;
}
/* Recompute number of measurements and realloc measurement buffer */
free(mbuf);
@@ -4190,8 +4145,6 @@ i1pro_code i1pro_save_calibration(i1pro *p) {
write_doubles(&x, fp, s->dark_data2-1, m->nraw+1);
write_doubles(&x, fp, &s->dark_int_time3, 1);
write_doubles(&x, fp, s->dark_data3-1, m->nraw+1);
- write_doubles(&x, fp, &s->dark_int_time4, 1);
- write_doubles(&x, fp, s->dark_data4-1, m->nraw+1);
write_ints(&x, fp, &s->dark_gain_mode, 1);
if (!s->emiss) {
@@ -4335,10 +4288,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
read_doubles(&x, fp, &dd, 1);
for (j = -1; j < m->nraw; j++)
read_doubles(&x, fp, &dd, 1);
- read_doubles(&x, fp, &dd, 1); /* dark_data3 */
- for (j = -1; j < m->nraw; j++)
- read_doubles(&x, fp, &dd, 1);
- read_doubles(&x, fp, &dd, 1); /* dark_data4 */
+ read_doubles(&x, fp, &dd, 1);
for (j = -1; j < m->nraw; j++)
read_doubles(&x, fp, &dd, 1);
read_ints(&x, fp, &di, 1);
@@ -4388,7 +4338,6 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
ts.dark_data = dvectorz(-1, m->nraw-1);
ts.dark_data2 = dvectorz(-1, m->nraw-1);
ts.dark_data3 = dvectorz(-1, m->nraw-1);
- ts.dark_data4 = dvectorz(-1, m->nraw-1);
ts.cal_factor[0] = dvectorz(0, m->nwav[0]-1);
ts.cal_factor[1] = dvectorz(0, m->nwav[1]-1);
ts.white_data = dvectorz(-1, m->nraw-1);
@@ -4435,8 +4384,6 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
read_doubles(&x, fp, ts.dark_data2-1, m->nraw+1);
read_doubles(&x, fp, &ts.dark_int_time3, 1);
read_doubles(&x, fp, ts.dark_data3-1, m->nraw+1);
- read_doubles(&x, fp, &ts.dark_int_time4, 1);
- read_doubles(&x, fp, ts.dark_data4-1, m->nraw+1);
read_ints(&x, fp, &ts.dark_gain_mode, 1);
if (!ts.emiss) {
@@ -4472,7 +4419,6 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
&& (s->adaptive || fabs(s->dark_int_time - ts.dark_int_time) < 0.01)
&& (s->adaptive || fabs(s->dark_int_time2 - ts.dark_int_time2) < 0.01)
&& (s->adaptive || fabs(s->dark_int_time3 - ts.dark_int_time3) < 0.01)
- && (s->adaptive || fabs(s->dark_int_time4 - ts.dark_int_time4) < 0.01)
&& (!s->adaptive || fabs(s->idark_int_time[0] - ts.idark_int_time[0]) < 0.01)
&& (!s->adaptive || fabs(s->idark_int_time[1] - ts.idark_int_time[1]) < 0.01)
&& (!s->adaptive || fabs(s->idark_int_time[2] - ts.idark_int_time[2]) < 0.01)
@@ -4505,9 +4451,6 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
s->dark_int_time3 = ts.dark_int_time3;
for (j = -1; j < m->nraw; j++)
s->dark_data3[j] = ts.dark_data3[j];
- s->dark_int_time4 = ts.dark_int_time4;
- for (j = -1; j < m->nraw; j++)
- s->dark_data4[j] = ts.dark_data4[j];
s->dark_gain_mode = ts.dark_gain_mode;
if (!ts.emiss) {
s->cal_valid = ts.cal_valid;
@@ -4537,7 +4480,7 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
a1logd(p->log,2,"emis = %d : %d, trans = %d : %d, ref = %d : %d\n",s->emiss,ts.emiss,s->trans,ts.trans,s->reflective,ts.reflective);
a1logd(p->log,2,"scan = %d : %d, flash = %d : %d, ambi = %d : %d, adapt = %d : %d\n",s->scan,ts.scan,s->flash,ts.flash,s->ambient,ts.ambient,s->adaptive,ts.adaptive);
a1logd(p->log,2,"inttime = %f : %f\n",s->inttime,ts.inttime);
- a1logd(p->log,2,"darkit1 = %f : %f, 2 = %f : %f, 3 = %f : %f, 4 = %f : %f\n",s->dark_int_time,ts.dark_int_time,s->dark_int_time2,ts.dark_int_time2,s->dark_int_time3,ts.dark_int_time3,s->dark_int_time4,ts.dark_int_time4);
+ a1logd(p->log,2,"darkit1 = %f : %f, 2 = %f : %f, 3 = %f : %f\n",s->dark_int_time,ts.dark_int_time,s->dark_int_time2,ts.dark_int_time2,s->dark_int_time3,ts.dark_int_time3);
a1logd(p->log,2,"idarkit0 = %f : %f, 1 = %f : %f, 2 = %f : %f, 3 = %f : %f\n",s->idark_int_time[0],ts.idark_int_time[0],s->idark_int_time[1],ts.idark_int_time[1],s->idark_int_time[2],ts.idark_int_time[2],s->idark_int_time[3],ts.idark_int_time[3]);
}
}
@@ -4546,7 +4489,6 @@ i1pro_code i1pro_restore_calibration(i1pro *p) {
free_dvector(ts.dark_data, -1, m->nraw-1);
free_dvector(ts.dark_data2, -1, m->nraw-1);
free_dvector(ts.dark_data3, -1, m->nraw-1);
- free_dvector(ts.dark_data4, -1, m->nraw-1);
free_dvector(ts.white_data, -1, m->nraw-1);
free_dmatrix(ts.idark_data, 0, 3, -1, m->nraw-1);
@@ -4607,8 +4549,6 @@ i1pro_establish_high_power(i1pro *p) {
if ((ev = i1pro_getmisc(p, &m->fwrev, NULL, &m->maxpve, NULL, &m->powmode)) != I1PRO_OK)
return ev;
- a1logd(p->log,2,"CPLD rev = %d\n",m->cpldrev);
-
if (m->powmode != 8) { /* In high power mode */
if ((ev = i1pro_reset(p, 0x1f)) != I1PRO_OK)
return ev;
@@ -10784,14 +10724,14 @@ i1pro_readEEProm(
0xC4, 0, 0, pbuf, len, 2.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_readEEProm: read failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_readEEProm: read failed with ICOM err 0x%x\n",se);
return rv;
}
/* Now read the bytes */
se = p->icom->usb_read(p->icom, NULL, 0x82, buf, size, &rwbytes, 5.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_readEEProm: read failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_readEEProm: read failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -10872,7 +10812,7 @@ i1pro_writeEEProm(
0xC3, 0, 0, pbuf, len, 2.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,2,"i1pro_writeEEProm: write failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,2,"i1pro_writeEEProm: write failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -10880,7 +10820,7 @@ i1pro_writeEEProm(
se = p->icom->usb_write(p->icom, NULL, 0x03, buf, size, &rwbytes, 5.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_writeEEProm: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_writeEEProm: failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -10897,7 +10837,7 @@ i1pro_writeEEProm(
se = p->icom->usb_write(p->icom, NULL, 0x03, pbuf, 1, &rwbytes, 5.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_writeEEProm: write failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_writeEEProm: write failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -10949,7 +10889,7 @@ i1pro_getmisc(
0xC9, 0, 0, pbuf, 8, 2.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_getmisc: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_getmisc: failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -10997,7 +10937,7 @@ i1pro_getmeasparams(
0xC2, 0, 0, pbuf, 8, 2.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_getmeasparams: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_getmeasparams: failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -11062,7 +11002,7 @@ i1pro_setmeasparams(
0xC1, 0, 0, pbuf, 8, 2.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_setmeasparams: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_setmeasparams: failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -11378,13 +11318,10 @@ i1pro_setmcmode(
0xCF, 0, 0, pbuf, 1, 2.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_setmcmode: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_setmcmode: failed with ICOM err 0x%x\n",se);
return rv;
}
- /* Hmm. Give the instrument a little time to reconfigure itself. */
- msec_sleep(10);
-
a1logd(p->log,2,"i1pro_setmcmode: done, ICOM err 0x%x (%d msec)\n",
se, msec_time()-stime);
return rv;
@@ -11421,7 +11358,7 @@ i1pro_getmcmode(
0xD1, 0, 0, pbuf, 6, 2.0);
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_getmcmode: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_getmcmode: failed with ICOM err 0x%x\n",se);
return rv;
}
@@ -11466,7 +11403,7 @@ i1pro_code i1pro_waitfor_switch(i1pro *p, double top) {
}
if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
- a1logd(p->log,1,"i1pro_waitfor_switch: failed with ICOM err 0x%x (%d msec)\n",se, msec_time()-stime);
+ a1logd(p->log,1,"i1pro_waitfor_switch: failed with ICOM err 0x%x\n",se);
return rv;
}
diff --git a/spectro/i1pro_imp.h b/spectro/i1pro_imp.h
index 5a2cef2..6bf8de4 100644
--- a/spectro/i1pro_imp.h
+++ b/spectro/i1pro_imp.h
@@ -127,7 +127,6 @@ struct _i1pro_state {
/* Display mode calibration state (emmis && !scan && !adaptive) */
int dispswap; /* 0 = default time, 1 = dark_int_time2, 2 = dark_int_time3 */
- /* 3 = dark_int_time4 */
double done_dintsel; /* A display integration time selection has been done */
time_t diseldate; /* Date/time of last display integration time selection */
double dcaltime2; /* Target dark calibration time - sets number of readings */
@@ -136,9 +135,6 @@ struct _i1pro_state {
double dcaltime3; /* Target dark calibration time - sets number of readings */
double dark_int_time3; /* Integration time used for dark data 3 */
double *dark_data3; /* [-1 nraw] of dark level to subtract for dark_int_time3. */
- double dcaltime4; /* Target dark calibration time - sets number of readings */
- double dark_int_time4; /* Integration time used for dark data 4 */
- double *dark_data4; /* [-1 nraw] of dark level to subtract for dark_int_time4. */
}; typedef struct _i1pro_state i1pro_state;
@@ -204,8 +200,8 @@ struct _i1proimp {
/* Values read from GetMisc() */
int fwrev; /* int - Firmware revision number, from getmisc() */
/* Used for internal switching ?? */
- /* 101 = Rev A, 202 = Rev A update, 302 = Rev B, */
- /* 502, 505, 631 = Rev D, 629 = Rev E (i1pro2) */
+ /* 101 = Rev A, 202 = Rev A update, 302 = Rev B, 502 = Rev D */
+ /* 629 = Rev E (i1pro2) */
int cpldrev; /* int - CPLD revision number in EEProm */
/* Not used internaly ???? */
diff --git a/spectro/inst.c b/spectro/inst.c
index 8976669..949e34f 100644
--- a/spectro/inst.c
+++ b/spectro/inst.c
@@ -581,18 +581,6 @@ static inst_config config_enum(inst *p, int ec) {
}
/* ---------------------------------------------- */
-
-/* Delete things set/done by new_inst() */
-static inst_code virtual_del(inst *p) {
-
-#if defined(__APPLE__)
- osx_latencycritical_end();
-#endif
-
- return inst_ok;
-}
-
-
/* Virtual constructor. */
/* Return NULL for unknown instrument, */
/* or serial instrument if nocoms == 0. */
@@ -714,8 +702,6 @@ void *cntx /* Context for callback */
return NULL;
}
- p->vdel = virtual_del;
-
/* Add default methods if constructor did not supply them */
if (p->init_coms == NULL)
p->init_coms = init_coms;
@@ -799,10 +785,6 @@ void *cntx /* Context for callback */
/* Set the provided user interaction callback */
p->set_uicallback(p, uicallback, cntx);
-#if defined(__APPLE__)
- osx_latencycritical_start();
-#endif
-
return p;
}
diff --git a/spectro/inst.h b/spectro/inst.h
index 736a879..d47f7ea 100644
--- a/spectro/inst.h
+++ b/spectro/inst.h
@@ -643,10 +643,6 @@ typedef enum {
void (*eventcallback)(void *cntx, inst_event_type event); \
void *event_cntx; /* Event callback function */ \
\
- /* Virtual delete. Cleans up things done by new_inst(). */ \
- inst_code (*vdel)( \
- struct _inst *p); \
- \
/* Establish communications at the indicated baud rate. */ \
/* (Serial parameters are ignored for USB instrument) */ \
/* Timout in to seconds, and return non-zero error code */ \
diff --git a/spectro/instappsup.c b/spectro/instappsup.c
index d2ce7ff..0762bbe 100644
--- a/spectro/instappsup.c
+++ b/spectro/instappsup.c
@@ -401,7 +401,7 @@ inst_code inst_handle_calibrate(
printf("\n");
/* If optional calib. and user wants to skip it */
/* Loop back to calibrate() with inst_calc_optional_flag still set */
- if ((calc & inst_calc_optional_flag) != 0 && (ch == 's' || ch == 'S')) {
+ if ((calc & inst_calc_optional_flag) != 0 && ch == 's' || ch == 'S') {
printf("Skipped\n");
goto oloop;
}
diff --git a/spectro/kleink10.c b/spectro/kleink10.c
index 9599972..461cb28 100644
--- a/spectro/kleink10.c
+++ b/spectro/kleink10.c
@@ -62,7 +62,7 @@
#undef HIGH_SPEED /* [und] Use high speed flicker measure for refresh rate etc. */
#define AUTO_AVERAGE /* [def] Automatically average more readings for low light */
-#define RETRY_RANGE_ERROR 4 /* [4] Retry range error readings 4 times */
+#define RETRY_RANGE_ERROR 3 /* [3] Retry range error readings 3 times */
#undef PLOT_REFRESH /* [und] Plot refresh rate measurement info */
#undef PLOT_UPDELAY /* [und] Plot update delay measurement info */
@@ -81,7 +81,6 @@ static inst_code k10_read_flicker_samples(kleink10 *p, double duration, double *
/* Decode a K10 error letter */
static int decodeK10err(char c) {
-//printf("~1 decoding error code 0x%x\n",c);
if (c == '0') {
return K10_OK;
} else if (c == 'B') {
@@ -126,34 +125,28 @@ extract_ec(char *s, int *nlength, int bread) {
if (*p == '>')
break;
}
- if (p < s) {
-//printf("p %d < s %d ? %d\n", p, s, p < s);
+ if (p < s)
return K10_BAD_RETVAL;
- }
//printf("trailing is at %d '%s'\n",p - s, p);
/* Find the leading '<' */
for (f = p-1; f >= (p-MAXECHARS-1) && f >= s; f--) {
if (*f == '<')
break;
- /* Turns out the error code may be non-text */
-#ifdef NEVER
if ((*f < '0' || *f > '9')
&& (*f < 'a' || *f > 'z')
&& (*f < 'A' || *f > 'Z'))
return K10_BAD_RETVAL;
-#endif /* NEVER */
}
if (f < s || f < (p-MAXECHARS-1) || (p-f) <= 1) {
-//printf("f < s ? %d, f < (p-MAXECHARS-1) ? %d, (p-f) <= 1 ? %d\n", f < s, f < (p-10), (p-f) <= 1);
+//printf("f < s ? %d, f < (p-MAXECHARS-1) ? %d, (p-f) <= 1 ? %d\n",
+//f < s, f < (p-10), (p-f) <= 1);
return K10_BAD_RETVAL;
}
//printf("leading is at %d '%s'\n",f - s, f);
- if (p-f-1 <= 0) {
-//printf("p-f-1 %d <= 0 ? %d\n", p-f-1, p-f-1 <= 0);
+ if (p-f-1 <= 0)
return K10_BAD_RETVAL;
- }
strncpy(tt, f+1, p-f-1);
tt[p-f-1] = '\000';
@@ -162,7 +155,7 @@ extract_ec(char *s, int *nlength, int bread) {
/* Interpret the error character(s) */
/* It's not clear if more than one error can be returned. */
/* We are only looking at the first character - we should */
- /* really prioritize them if more than one can occur. */
+ /* really prioritize them id more than one can occur. */
for (p = tt; *p != '\000'; p++) {
rv = decodeK10err(*p);
break;
@@ -474,15 +467,7 @@ k10_init_inst(inst *pp) {
amutex_lock(p->lock);
/* Make sure the target lights are off */
- if ((ev = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 1.0)) != inst_ok
- /* Strangely the L0/1 command mat return irrelevant error codes... */
- && (ev & inst_imask) != K10_UNKNOWN
- && (ev & inst_imask) != K10_BLACK_EXCESS
- && (ev & inst_imask) != K10_BLACK_OVERDRIVE
- && (ev & inst_imask) != K10_BLACK_ZERO
- && (ev & inst_imask) != K10_OVER_HIGH_RANGE
- && (ev & inst_imask) != K10_TOP_OVER_RANGE
- && (ev & inst_imask) != K10_BOT_UNDER_RANGE) {
+ if ((ev = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 1.0)) != inst_ok) {
amutex_unlock(p->lock);
return ev;
}
@@ -525,20 +510,14 @@ k10_init_inst(inst *pp) {
if (p->log->verb) {
char *model = "Unknown";
switch (p->model) {
- case k10_k1:
- model = "K-1";
- break;
- case k10_k8:
- model = "K-8";
- break;
case k10_k10:
- model = "K-10";
+ model = "K10";
break;
case k10_k10a:
- model = "K-10A";
+ model = "K10-A";
break;
case k10_kv10a:
- model = "KV-10A";
+ model = "KV10-A";
break;
}
a1logv(p->log, 1, " Model: '%s'\n",model);
@@ -907,7 +886,7 @@ kleink10 *p) {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-static void abort_flicker(kleink10 *p, int isnew, double *retbuf) {
+static abort_flicker(kleink10 *p, int isnew, double *retbuf) {
char buf[MAX_MES_SIZE];
int bread;
@@ -997,15 +976,7 @@ int usefast /* If nz use fast rate is possible */
/* Make sure the target lights are off */
if (p->lights) {
int se;
- if ((ev = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 0.5)) != inst_ok
- /* Strangely the L0/1 command mat return irrelevant error codes... */
- && (ev & inst_imask) != K10_UNKNOWN
- && (ev & inst_imask) != K10_BLACK_EXCESS
- && (ev & inst_imask) != K10_BLACK_OVERDRIVE
- && (ev & inst_imask) != K10_BLACK_ZERO
- && (ev & inst_imask) != K10_OVER_HIGH_RANGE
- && (ev & inst_imask) != K10_TOP_OVER_RANGE
- && (ev & inst_imask) != K10_BOT_UNDER_RANGE) {
+ if ((ev = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 0.5)) != inst_ok) {
amutex_unlock(p->lock);
free(retbuf);
a1logd(p->log, 1, "k10_read_flicker: L0 failed\n");
@@ -1211,9 +1182,9 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
int user_trig = 0;
int bsize;
inst_code rv = inst_protocol_error;
- int range[3]; /* Range for RGB sensor values */
- int i, tries, ntav = 1; /* Number of readings to average */
- double v, vv;
+ int range[3]; /* Range for RGB sensor values */
+ int i, tries,ntav = 1; /* Number of readings to average */
+ double v, vv, XYZ[3];
if (!p->gotcoms)
return inst_no_coms;
@@ -1259,15 +1230,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
/* Make sure the target lights are off */
if (p->lights) {
- if ((rv = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 1.0)) != inst_ok
- /* Strangely the L0/1 command mat return irrelevant error codes... */
- && (rv & inst_imask) != K10_UNKNOWN
- && (rv & inst_imask) != K10_BLACK_EXCESS
- && (rv & inst_imask) != K10_BLACK_OVERDRIVE
- && (rv & inst_imask) != K10_BLACK_ZERO
- && (rv & inst_imask) != K10_OVER_HIGH_RANGE
- && (rv & inst_imask) != K10_TOP_OVER_RANGE
- && (rv & inst_imask) != K10_BOT_UNDER_RANGE) {
+ if ((rv = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 1.0)) != inst_ok) {
amutex_unlock(p->lock);
a1logd(p->log, 1, "k10_read_sample: L0 failed\n");
return rv;
@@ -1293,7 +1256,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (rv == inst_ok
|| ( (rv & inst_imask) != K10_TOP_OVER_RANGE
&& (rv & inst_imask) != K10_BOT_UNDER_RANGE))
- break;
+ break;
}
if (rv == inst_ok)
@@ -1310,6 +1273,7 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
if (val->XYZ[2] > v)
v = val->XYZ[2];
+ ntav = 1;
#ifdef AUTO_AVERAGE
if (!IMODETST(p->mode, inst_mode_emis_nonadaptive)) {
/* Decide how many extra readings to average into result. */
@@ -1328,26 +1292,13 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
vv = 1.0 - (v - thr[2]) / (thr[3] - thr[2]);
vv = vv * vv * vv;
ntav = (int)(vv * (nav[2] - nav[3]) + nav[3] + 0.5);
- } /* else default 1 */
+ }
}
#endif
- /* Measure extras up to ntav */
for (i = 1; i < ntav; i++) {
- double XYZ[3];
-
- for (tries = 0; tries < RETRY_RANGE_ERROR; tries++) {
- rv = k10_command(p, "N5\r", buf, MAX_MES_SIZE, &bsize, 15, ec_ec, 2.0);
- if (rv == inst_ok
- || ( (rv & inst_imask) != K10_TOP_OVER_RANGE
- && (rv & inst_imask) != K10_BOT_UNDER_RANGE))
- break;
- }
-
- if (rv != inst_ok) { // An error, or retry failed
+ if ((rv = k10_command(p, "N5\r", buf, MAX_MES_SIZE, &bsize, 15, ec_ec, 2.0)) != inst_ok)
break;
- }
-
if ((rv = decodeN5(p, XYZ, range, buf, bsize)) != inst_ok)
break;
@@ -1370,6 +1321,10 @@ instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
amutex_unlock(p->lock);
+ if ((rv = decodeN5(p, val->XYZ, range, buf, bsize)) != inst_ok) {
+ return rv;
+ }
+
/* Apply the calibration correction matrix */
icmMulBy3x3(val->XYZ, p->ccmat, val->XYZ);
@@ -2441,7 +2396,6 @@ k10_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
amutex_del(p->lock);
- p->vdel(pp);
free(p);
}
}
@@ -2787,30 +2741,14 @@ k10_get_set_opt(inst *pp, inst_opt_type m, ...)
}
if (state == 1) { /* Turn on */
- if ((ev = k10_command(p, "L1\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 0.5)) != inst_ok
- /* Strangely the L0/1 command mat return irrelevant error codes... */
- && (ev & inst_imask) != K10_UNKNOWN
- && (ev & inst_imask) != K10_BLACK_EXCESS
- && (ev & inst_imask) != K10_BLACK_OVERDRIVE
- && (ev & inst_imask) != K10_BLACK_ZERO
- && (ev & inst_imask) != K10_OVER_HIGH_RANGE
- && (ev & inst_imask) != K10_TOP_OVER_RANGE
- && (ev & inst_imask) != K10_BOT_UNDER_RANGE) {
+ if ((ev = k10_command(p, "L1\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 0.5)) != inst_ok) {
amutex_unlock(p->lock);
a1logd(p->log, 1, "k10_get_set_opt: L1 failed\n");
return ev;
}
p->lights = 1;
} else if (state == 0) { /* Turn off */
- if ((ev = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 0.5)) != inst_ok
- /* Strangely the L0/1 command mat return irrelevant error codes... */
- && (ev & inst_imask) != K10_UNKNOWN
- && (ev & inst_imask) != K10_BLACK_EXCESS
- && (ev & inst_imask) != K10_BLACK_OVERDRIVE
- && (ev & inst_imask) != K10_BLACK_ZERO
- && (ev & inst_imask) != K10_OVER_HIGH_RANGE
- && (ev & inst_imask) != K10_TOP_OVER_RANGE
- && (ev & inst_imask) != K10_BOT_UNDER_RANGE) {
+ if ((ev = k10_command(p, "L0\r", buf, MAX_MES_SIZE, NULL, 2+3, ec_ec, 0.5)) != inst_ok) {
amutex_unlock(p->lock);
a1logd(p->log, 1, "k10_get_set_opt: L0 failed\n");
return ev;
diff --git a/spectro/linear.cal b/spectro/linear.cal
deleted file mode 100644
index 9c88605..0000000
--- a/spectro/linear.cal
+++ /dev/null
@@ -1,272 +0,0 @@
-CAL
-
-DESCRIPTOR "Argyll Device Calibration Curves"
-ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
-DEVICE_CLASS "DISPLAY"
-COLOR_REP "RGB"
-
-NUMBER_OF_FIELDS 4
-BEGIN_DATA_FORMAT
-RGB_I RGB_R RGB_G RGB_B
-END_DATA_FORMAT
-
-NUMBER_OF_SETS 256
-BEGIN_DATA
-0.00000 0.00000 0.00000 0.00000
-0.00392157 0.00392157 0.00392157 0.00392157
-0.00784314 0.00784314 0.00784314 0.00784314
-0.0117647 0.0117647 0.0117647 0.0117647
-0.0156863 0.0156863 0.0156863 0.0156863
-0.0196078 0.0196078 0.0196078 0.0196078
-0.0235294 0.0235294 0.0235294 0.0235294
-0.0274510 0.0274510 0.0274510 0.0274510
-0.0313725 0.0313725 0.0313725 0.0313725
-0.0352941 0.0352941 0.0352941 0.0352941
-0.0392157 0.0392157 0.0392157 0.0392157
-0.0431373 0.0431373 0.0431373 0.0431373
-0.0470588 0.0470588 0.0470588 0.0470588
-0.0509804 0.0509804 0.0509804 0.0509804
-0.0549020 0.0549020 0.0549020 0.0549020
-0.0588235 0.0588235 0.0588235 0.0588235
-0.0627451 0.0627451 0.0627451 0.0627451
-0.0666667 0.0666667 0.0666667 0.0666667
-0.0705882 0.0705882 0.0705882 0.0705882
-0.0745098 0.0745098 0.0745098 0.0745098
-0.0784314 0.0784314 0.0784314 0.0784314
-0.0823529 0.0823529 0.0823529 0.0823529
-0.0862745 0.0862745 0.0862745 0.0862745
-0.0901961 0.0901961 0.0901961 0.0901961
-0.0941176 0.0941176 0.0941176 0.0941176
-0.0980392 0.0980392 0.0980392 0.0980392
-0.101961 0.101961 0.101961 0.101961
-0.105882 0.105882 0.105882 0.105882
-0.109804 0.109804 0.109804 0.109804
-0.113725 0.113725 0.113725 0.113725
-0.117647 0.117647 0.117647 0.117647
-0.121569 0.121569 0.121569 0.121569
-0.125490 0.125490 0.125490 0.125490
-0.129412 0.129412 0.129412 0.129412
-0.133333 0.133333 0.133333 0.133333
-0.137255 0.137255 0.137255 0.137255
-0.141176 0.141176 0.141176 0.141176
-0.145098 0.145098 0.145098 0.145098
-0.149020 0.149020 0.149020 0.149020
-0.152941 0.152941 0.152941 0.152941
-0.156863 0.156863 0.156863 0.156863
-0.160784 0.160784 0.160784 0.160784
-0.164706 0.164706 0.164706 0.164706
-0.168627 0.168627 0.168627 0.168627
-0.172549 0.172549 0.172549 0.172549
-0.176471 0.176471 0.176471 0.176471
-0.180392 0.180392 0.180392 0.180392
-0.184314 0.184314 0.184314 0.184314
-0.188235 0.188235 0.188235 0.188235
-0.192157 0.192157 0.192157 0.192157
-0.196078 0.196078 0.196078 0.196078
-0.200000 0.200000 0.200000 0.200000
-0.203922 0.203922 0.203922 0.203922
-0.207843 0.207843 0.207843 0.207843
-0.211765 0.211765 0.211765 0.211765
-0.215686 0.215686 0.215686 0.215686
-0.219608 0.219608 0.219608 0.219608
-0.223529 0.223529 0.223529 0.223529
-0.227451 0.227451 0.227451 0.227451
-0.231373 0.231373 0.231373 0.231373
-0.235294 0.235294 0.235294 0.235294
-0.239216 0.239216 0.239216 0.239216
-0.243137 0.243137 0.243137 0.243137
-0.247059 0.247059 0.247059 0.247059
-0.250980 0.250980 0.250980 0.250980
-0.254902 0.254902 0.254902 0.254902
-0.258824 0.258824 0.258824 0.258824
-0.262745 0.262745 0.262745 0.262745
-0.266667 0.266667 0.266667 0.266667
-0.270588 0.270588 0.270588 0.270588
-0.274510 0.274510 0.274510 0.274510
-0.278431 0.278431 0.278431 0.278431
-0.282353 0.282353 0.282353 0.282353
-0.286275 0.286275 0.286275 0.286275
-0.290196 0.290196 0.290196 0.290196
-0.294118 0.294118 0.294118 0.294118
-0.298039 0.298039 0.298039 0.298039
-0.301961 0.301961 0.301961 0.301961
-0.305882 0.305882 0.305882 0.305882
-0.309804 0.309804 0.309804 0.309804
-0.313725 0.313725 0.313725 0.313725
-0.317647 0.317647 0.317647 0.317647
-0.321569 0.321569 0.321569 0.321569
-0.325490 0.325490 0.325490 0.325490
-0.329412 0.329412 0.329412 0.329412
-0.333333 0.333333 0.333333 0.333333
-0.337255 0.337255 0.337255 0.337255
-0.341176 0.341176 0.341176 0.341176
-0.345098 0.345098 0.345098 0.345098
-0.349020 0.349020 0.349020 0.349020
-0.352941 0.352941 0.352941 0.352941
-0.356863 0.356863 0.356863 0.356863
-0.360784 0.360784 0.360784 0.360784
-0.364706 0.364706 0.364706 0.364706
-0.368627 0.368627 0.368627 0.368627
-0.372549 0.372549 0.372549 0.372549
-0.376471 0.376471 0.376471 0.376471
-0.380392 0.380392 0.380392 0.380392
-0.384314 0.384314 0.384314 0.384314
-0.388235 0.388235 0.388235 0.388235
-0.392157 0.392157 0.392157 0.392157
-0.396078 0.396078 0.396078 0.396078
-0.400000 0.400000 0.400000 0.400000
-0.403922 0.403922 0.403922 0.403922
-0.407843 0.407843 0.407843 0.407843
-0.411765 0.411765 0.411765 0.411765
-0.415686 0.415686 0.415686 0.415686
-0.419608 0.419608 0.419608 0.419608
-0.423529 0.423529 0.423529 0.423529
-0.427451 0.427451 0.427451 0.427451
-0.431373 0.431373 0.431373 0.431373
-0.435294 0.435294 0.435294 0.435294
-0.439216 0.439216 0.439216 0.439216
-0.443137 0.443137 0.443137 0.443137
-0.447059 0.447059 0.447059 0.447059
-0.450980 0.450980 0.450980 0.450980
-0.454902 0.454902 0.454902 0.454902
-0.458824 0.458824 0.458824 0.458824
-0.462745 0.462745 0.462745 0.462745
-0.466667 0.466667 0.466667 0.466667
-0.470588 0.470588 0.470588 0.470588
-0.474510 0.474510 0.474510 0.474510
-0.478431 0.478431 0.478431 0.478431
-0.482353 0.482353 0.482353 0.482353
-0.486275 0.486275 0.486275 0.486275
-0.490196 0.490196 0.490196 0.490196
-0.494118 0.494118 0.494118 0.494118
-0.498039 0.498039 0.498039 0.498039
-0.501961 0.501961 0.501961 0.501961
-0.505882 0.505882 0.505882 0.505882
-0.509804 0.509804 0.509804 0.509804
-0.513725 0.513725 0.513725 0.513725
-0.517647 0.517647 0.517647 0.517647
-0.521569 0.521569 0.521569 0.521569
-0.525490 0.525490 0.525490 0.525490
-0.529412 0.529412 0.529412 0.529412
-0.533333 0.533333 0.533333 0.533333
-0.537255 0.537255 0.537255 0.537255
-0.541176 0.541176 0.541176 0.541176
-0.545098 0.545098 0.545098 0.545098
-0.549020 0.549020 0.549020 0.549020
-0.552941 0.552941 0.552941 0.552941
-0.556863 0.556863 0.556863 0.556863
-0.560784 0.560784 0.560784 0.560784
-0.564706 0.564706 0.564706 0.564706
-0.568627 0.568627 0.568627 0.568627
-0.572549 0.572549 0.572549 0.572549
-0.576471 0.576471 0.576471 0.576471
-0.580392 0.580392 0.580392 0.580392
-0.584314 0.584314 0.584314 0.584314
-0.588235 0.588235 0.588235 0.588235
-0.592157 0.592157 0.592157 0.592157
-0.596078 0.596078 0.596078 0.596078
-0.600000 0.600000 0.600000 0.600000
-0.603922 0.603922 0.603922 0.603922
-0.607843 0.607843 0.607843 0.607843
-0.611765 0.611765 0.611765 0.611765
-0.615686 0.615686 0.615686 0.615686
-0.619608 0.619608 0.619608 0.619608
-0.623529 0.623529 0.623529 0.623529
-0.627451 0.627451 0.627451 0.627451
-0.631373 0.631373 0.631373 0.631373
-0.635294 0.635294 0.635294 0.635294
-0.639216 0.639216 0.639216 0.639216
-0.643137 0.643137 0.643137 0.643137
-0.647059 0.647059 0.647059 0.647059
-0.650980 0.650980 0.650980 0.650980
-0.654902 0.654902 0.654902 0.654902
-0.658824 0.658824 0.658824 0.658824
-0.662745 0.662745 0.662745 0.662745
-0.666667 0.666667 0.666667 0.666667
-0.670588 0.670588 0.670588 0.670588
-0.674510 0.674510 0.674510 0.674510
-0.678431 0.678431 0.678431 0.678431
-0.682353 0.682353 0.682353 0.682353
-0.686275 0.686275 0.686275 0.686275
-0.690196 0.690196 0.690196 0.690196
-0.694118 0.694118 0.694118 0.694118
-0.698039 0.698039 0.698039 0.698039
-0.701961 0.701961 0.701961 0.701961
-0.705882 0.705882 0.705882 0.705882
-0.709804 0.709804 0.709804 0.709804
-0.713725 0.713725 0.713725 0.713725
-0.717647 0.717647 0.717647 0.717647
-0.721569 0.721569 0.721569 0.721569
-0.725490 0.725490 0.725490 0.725490
-0.729412 0.729412 0.729412 0.729412
-0.733333 0.733333 0.733333 0.733333
-0.737255 0.737255 0.737255 0.737255
-0.741176 0.741176 0.741176 0.741176
-0.745098 0.745098 0.745098 0.745098
-0.749020 0.749020 0.749020 0.749020
-0.752941 0.752941 0.752941 0.752941
-0.756863 0.756863 0.756863 0.756863
-0.760784 0.760784 0.760784 0.760784
-0.764706 0.764706 0.764706 0.764706
-0.768627 0.768627 0.768627 0.768627
-0.772549 0.772549 0.772549 0.772549
-0.776471 0.776471 0.776471 0.776471
-0.780392 0.780392 0.780392 0.780392
-0.784314 0.784314 0.784314 0.784314
-0.788235 0.788235 0.788235 0.788235
-0.792157 0.792157 0.792157 0.792157
-0.796078 0.796078 0.796078 0.796078
-0.800000 0.800000 0.800000 0.800000
-0.803922 0.803922 0.803922 0.803922
-0.807843 0.807843 0.807843 0.807843
-0.811765 0.811765 0.811765 0.811765
-0.815686 0.815686 0.815686 0.815686
-0.819608 0.819608 0.819608 0.819608
-0.823529 0.823529 0.823529 0.823529
-0.827451 0.827451 0.827451 0.827451
-0.831373 0.831373 0.831373 0.831373
-0.835294 0.835294 0.835294 0.835294
-0.839216 0.839216 0.839216 0.839216
-0.843137 0.843137 0.843137 0.843137
-0.847059 0.847059 0.847059 0.847059
-0.850980 0.850980 0.850980 0.850980
-0.854902 0.854902 0.854902 0.854902
-0.858824 0.858824 0.858824 0.858824
-0.862745 0.862745 0.862745 0.862745
-0.866667 0.866667 0.866667 0.866667
-0.870588 0.870588 0.870588 0.870588
-0.874510 0.874510 0.874510 0.874510
-0.878431 0.878431 0.878431 0.878431
-0.882353 0.882353 0.882353 0.882353
-0.886275 0.886275 0.886275 0.886275
-0.890196 0.890196 0.890196 0.890196
-0.894118 0.894118 0.894118 0.894118
-0.898039 0.898039 0.898039 0.898039
-0.901961 0.901961 0.901961 0.901961
-0.905882 0.905882 0.905882 0.905882
-0.909804 0.909804 0.909804 0.909804
-0.913725 0.913725 0.913725 0.913725
-0.917647 0.917647 0.917647 0.917647
-0.921569 0.921569 0.921569 0.921569
-0.925490 0.925490 0.925490 0.925490
-0.929412 0.929412 0.929412 0.929412
-0.933333 0.933333 0.933333 0.933333
-0.937255 0.937255 0.937255 0.937255
-0.941176 0.941176 0.941176 0.941176
-0.945098 0.945098 0.945098 0.945098
-0.949020 0.949020 0.949020 0.949020
-0.952941 0.952941 0.952941 0.952941
-0.956863 0.956863 0.956863 0.956863
-0.960784 0.960784 0.960784 0.960784
-0.964706 0.964706 0.964706 0.964706
-0.968627 0.968627 0.968627 0.968627
-0.972549 0.972549 0.972549 0.972549
-0.976471 0.976471 0.976471 0.976471
-0.980392 0.980392 0.980392 0.980392
-0.984314 0.984314 0.984314 0.984314
-0.988235 0.988235 0.988235 0.988235
-0.992157 0.992157 0.992157 0.992157
-0.996078 0.996078 0.996078 0.996078
-1.000000 1.000000 1.000000 1.000000
-END_DATA
diff --git a/spectro/munki.c b/spectro/munki.c
index df54cd9..57f5ce8 100644
--- a/spectro/munki.c
+++ b/spectro/munki.c
@@ -66,7 +66,7 @@ static inst_code munki_interp_code(munki *p, munki_code ec);
/* Establish communications with a Munki */
/* If it's a serial port, use the baud rate given, and timeout in to secs */
-/* Return MUNKI_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
munki *p = (munki *) pp;
@@ -937,7 +937,6 @@ munki_del(inst *pp) {
del_munkiimp(p);
if (p->icom != NULL)
p->icom->del(p->icom);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/rspec.c b/spectro/rspec.c
index e0e0194..49d725b 100644
--- a/spectro/rspec.c
+++ b/spectro/rspec.c
@@ -43,7 +43,6 @@
#include "sa_config.h"
#include "numsup.h"
#endif /* !SALONEINSTLIB */
-#include "plot.h"
#include "xspect.h"
#include "insttypes.h"
#include "conv.h"
@@ -153,6 +152,9 @@ double rspec_raw2nm(rspec_inf *inf, double rix) {
if (inf->nwlcal == 0)
error("rspec_raw2nm: nwlcal == 0");
+// ~~~~9999 test fudge
+// rix += 15;
+
/* Compute polinomial */
for (wl = inf->wlcal[inf->nwlcal-1], k = inf->nwlcal-2; k >= 0; k--)
wl = wl * rix + inf->wlcal[k];
diff --git a/spectro/rspec.h b/spectro/rspec.h
index 0cbee58..bc5d427 100644
--- a/spectro/rspec.h
+++ b/spectro/rspec.h
@@ -33,12 +33,12 @@
/* - - - - - - - - - - - - - */
/* Collection of raw samples */
typedef enum {
- rspec_sensor, /* Includes shielded/temperature values */
+ rspec_sensor, /* Includes shielded/temperaturee values */
rspec_raw, /* Potential light values */
rspec_wav /* Valid wavelength values */
} rspec_type;
-/* The order the state is changed in, is device workflow dependent */
+/* The order the state is changed in is device workflow dependent */
typedef enum {
rspec_none = 0x0000, /* No processing */
rspec_shld = 0x0002, /* Shielded cell corrected */
@@ -136,7 +136,7 @@ struct _rspec_inf {
/* Completely clear an rspec_inf. */
void clear_rspec_inf(rspec_inf *inf);
-/* Completely free contents of rspec_inf. */
+/* Completely free contesnt of rspec_inf. */
void free_rspec_inf(rspec_inf *inf);
/* return the number of samples for the given spectral type */
diff --git a/spectro/smcube.c b/spectro/smcube.c
index 8a788ec..1618447 100644
--- a/spectro/smcube.c
+++ b/spectro/smcube.c
@@ -140,12 +140,6 @@ static inst_code smcube_measure(smcube *p, double *XYZ);
static void cube_rgb2XYZ(double *xyz, double *irgb);
-int static smcube_save_calibration(smcube *p);
-int static smcube_touch_calibration(smcube *p);
-int static smcube_restore_calibration(smcube *p);
-
-/* ------------------------------------------------- */
-
/* Do a full command/response echange with the smcube */
/* (This level is not multi-thread safe) */
/* Return the smcube error code. */
@@ -855,7 +849,6 @@ smcube_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
amutex_del(p->lock);
- p->vdel(pp);
free(p);
}
}
@@ -2016,7 +2009,7 @@ static void cube_rgb2XYZ(double *xyz, double *irgb) {
/* The cube doesn't have an easily accessible serial number :-( */
/* So if you have more than one, you'll be sharing the same calibration !! */
-int static smcube_save_calibration(smcube *p) {
+int smcube_save_calibration(smcube *p) {
int ev = SMCUBE_OK;
int i;
char fname[100]; /* Name */
@@ -2074,7 +2067,7 @@ int static smcube_save_calibration(smcube *p) {
}
/* Restore the all modes calibration from the local system */
-int static smcube_restore_calibration(smcube *p) {
+int smcube_restore_calibration(smcube *p) {
int ev = SMCUBE_OK;
int i, j;
char fname[100]; /* Name */
@@ -2176,7 +2169,7 @@ int static smcube_restore_calibration(smcube *p) {
return ev;
}
-int static smcube_touch_calibration(smcube *p) {
+int smcube_touch_calibration(smcube *p) {
int ev = SMCUBE_OK;
char fname[100]; /* Name */
int rv;
diff --git a/spectro/spec2cie.c b/spectro/spec2cie.c
index 322ab05..aa91ebb 100644
--- a/spectro/spec2cie.c
+++ b/spectro/spec2cie.c
@@ -389,7 +389,7 @@ main(int argc, char *argv[])
if (illum == icxIT_none)
illum = icxIT_D50;
- if (observ == icxOT_none)
+ if (observ = icxOT_none)
observ = icxOT_CIE_1931_2;
/* Figure out what sort of device it is */
diff --git a/spectro/specbos.c b/spectro/specbos.c
index 491fe97..e819c06 100644
--- a/spectro/specbos.c
+++ b/spectro/specbos.c
@@ -1434,7 +1434,6 @@ specbos_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
amutex_del(p->lock);
- p->vdel(pp);
free(p);
}
}
diff --git a/spectro/spyd2.c b/spectro/spyd2.c
index 6833e89..b546f6b 100644
--- a/spectro/spyd2.c
+++ b/spectro/spyd2.c
@@ -642,13 +642,12 @@ spyd2_GetReading_ll(
int value;
int index;
int flag;
- int retr;
+ int nords, retr;
unsigned char buf1[8]; /* send bytes */
unsigned char buf2[9 * 8]; /* return bytes read */
int rvals[3][8]; /* Raw values */
int _maxtcnt = 0; /* Maximum transition count */
int _mintcnt = 0x7fffffff; /* Minumum transition count */
- double maxfreq = 0.0; /* Maximum sensor frequency found */
int i, j, k;
a1logd(p->log, 3, "spyd2_GetReading_ll: clocks = %d, minfc = %d, maxfc = %d\n",*clocks,*minfclks,*maxfclks);
@@ -692,7 +691,7 @@ spyd2_GetReading_ll(
}
/* The Spyder comms seems especially flakey... */
- for (retr = 0; ; retr++) {
+ for (retr = 0, nords = 1; ; retr++, nords++) {
//int start = msec_time();
@@ -889,14 +888,13 @@ spyd2_GetReading_ll(
} else { /* We discard 0'th L2F transion to give transitions */
/* over the time period. */
if (sensv != NULL)
- sensv[k] = ((double)transcnt - 1.0) * (double)CLKRATE / (double)intclks;
+ sensv[k] = ((double)transcnt - 1.0) * (double)CLKRATE
+ / ((double)nords * (double)intclks);
if (transcnt > _maxtcnt)
_maxtcnt = transcnt;
if (transcnt < _mintcnt)
_mintcnt = transcnt;
}
- if (sensv != NULL && sensv[k] > maxfreq)
- maxfreq = sensv[k];
if (p->log->debug >= 4 && sensv != NULL)
a1logd(p->log, 4, "%d: initial senv %f from transcnt %d and intclls %d\n",
k,sensv[k],transcnt,intclks);
@@ -969,8 +967,6 @@ spyd2_GetReading_ll(
if (transcnt < _mintcnt)
_mintcnt = transcnt;
}
- if (sensv != NULL && (8.125 * sensv[k]) > maxfreq)
- maxfreq = 8.125 * sensv[k];
if (p->log->debug >= 4 && sensv != NULL)
a1logd(p->log, 4, "%d: initial senv %f from transcnt %d and intclls %d\n",
k,sensv[k],transcnt,intclks);
@@ -982,16 +978,6 @@ spyd2_GetReading_ll(
if (mintcnt != NULL)
*mintcnt = _mintcnt;
- if (p->log->debug >= 4 && sensv != NULL)
- a1logd(p->log, 4, "Maximum sensor frequency = %f\n",maxfreq);
-
- /* Problem is that the HW starts loosing count above a certain */
- /* frequency, so we depend on one less bright sensor acting as a canary, */
- /* so we can't make the threshold too low. */
- if (maxfreq > 500000.0) {
- return spyd2_interp_code((inst *)p, SPYD2_TOOBRIGHT);
- }
-
return rv;
}
@@ -2857,7 +2843,7 @@ spyd4_load_cal(spyd2 *p) {
/* Establish communications with a SPYD2 */
/* If it's a serial port, use the baud rate given, and timeout in to secs */
-/* Return SPYD2_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
spyd2_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
spyd2 *p = (spyd2 *) pp;
@@ -2880,7 +2866,7 @@ spyd2_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
/* (and Spyder 2 hangs if a reset ep is done on MSWin.) */
/* The spyder 2 doesn't work well with the winusb driver either, */
/* it needs icomuf_resetep_before_read to work at all, and */
- /* gets retries anyway. So we use the libusb-win32 driver for it. */
+ /* gets retries anyway. So we use the libusb0 driver for it. */
#if defined(NT)
if (p->itype == instSpyder3) {
usbflags |= icomuf_resetep_before_read; /* The spyder USB is buggy ? */
@@ -3405,8 +3391,6 @@ spyd2_interp_error(inst *pp, int ec) {
return "Display device selection out of range";
/* User error */
- case SPYD2_TOOBRIGHT:
- return "Too bright to read accuractly";
case SPYD2_NO_REFRESH_DET:
return "Unable to detect & measure refresh rate";
@@ -3461,7 +3445,6 @@ spyd2_interp_code(inst *pp, int ec) {
case SPYD2_DISP_SEL_RANGE:
return inst_wrong_setup | ec;
- case SPYD2_TOOBRIGHT:
case SPYD2_NO_REFRESH_DET:
return inst_misread | ec;
@@ -3478,7 +3461,6 @@ spyd2_del(inst *pp) {
inst_del_disptype_list(p->dtlist, p->ndtlist);
if (p->samples != NULL)
free(p->samples);
- p->vdel(pp);
free(p);
}
diff --git a/spectro/spyd2.h b/spectro/spyd2.h
index 0588b9b..923234f 100644
--- a/spectro/spyd2.h
+++ b/spectro/spyd2.h
@@ -56,7 +56,6 @@
#define SPYD2_TRIGTIMEOUT 0x04
#define SPYD2_OVERALLTIMEOUT 0x05
#define SPYD2_BAD_EE_CRC 0x06
-#define SPYD2_TOOBRIGHT 0x07
/* Internal software errors */
#define SPYD2_BAD_EE_ADDRESS 0x21
diff --git a/spectro/ss.c b/spectro/ss.c
index 837e264..90720ca 100644
--- a/spectro/ss.c
+++ b/spectro/ss.c
@@ -131,7 +131,7 @@ static void check_calcount(ss *p, int atstart) {
/* Establish communications with a Spectrolino/Spectroscan */
/* Use the baud rate given, and timeout in to secs */
-/* Return SS_COMS_FAIL on failure to establish communications */
+/* Return DTP_COMS_FAIL on failure to establish communications */
static inst_code
ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
ss *p = (ss *)pp;
@@ -2037,7 +2037,6 @@ ss_del(inst *pp) {
if (p->icom != NULL)
p->icom->del(p->icom);
- p->vdel(pp);
free (p);
}
diff --git a/spectro/strange.cal b/spectro/strange.cal
deleted file mode 100644
index 5f2e94d..0000000
--- a/spectro/strange.cal
+++ /dev/null
@@ -1,272 +0,0 @@
-CAL
-
-DESCRIPTOR "Argyll Device Calibration Curves"
-ORIGINATOR "Argyll synthcal"
-CREATED "Mon Oct 26 01:10:48 2015"
-DEVICE_CLASS "DISPLAY"
-COLOR_REP "RGB"
-
-NUMBER_OF_FIELDS 4
-BEGIN_DATA_FORMAT
-RGB_I RGB_R RGB_G RGB_B
-END_DATA_FORMAT
-
-NUMBER_OF_SETS 256
-BEGIN_DATA
-0.00000 0.00000 0.00000 0.00000
-0.00392157 0.0000567518 0.0118787 0.0186065
-0.00784314 0.000184387 0.0206820 0.0302263
-0.0117647 0.000367355 0.0286065 0.0401466
-0.0156863 0.000599076 0.0360094 0.0491028
-0.0196078 0.000875445 0.0430471 0.0574042
-0.0235294 0.00119354 0.0498068 0.0652184
-0.0274510 0.00155112 0.0563438 0.0726496
-0.0313725 0.00194640 0.0626960 0.0797678
-0.0352941 0.00237789 0.0688909 0.0866232
-0.0392157 0.00284433 0.0749493 0.0932533
-0.0431373 0.00334462 0.0808876 0.0996872
-0.0470588 0.00387782 0.0867187 0.105948
-0.0509804 0.00444307 0.0924533 0.112053
-0.0549020 0.00503962 0.0981003 0.118020
-0.0588235 0.00566676 0.103667 0.123859
-0.0627451 0.00632388 0.109160 0.129583
-0.0666667 0.00701040 0.114585 0.135201
-0.0705882 0.00772579 0.119946 0.140720
-0.0745098 0.00846956 0.125248 0.146148
-0.0784314 0.00924125 0.130494 0.151490
-0.0823529 0.0100404 0.135689 0.156754
-0.0862745 0.0108667 0.140834 0.161942
-0.0901961 0.0117197 0.145932 0.167061
-0.0941176 0.0125991 0.150986 0.172112
-0.0980392 0.0135045 0.155998 0.177102
-0.101961 0.0144356 0.160971 0.182031
-0.105882 0.0153921 0.165905 0.186904
-0.109804 0.0163738 0.170803 0.191723
-0.113725 0.0173803 0.175665 0.196491
-0.117647 0.0184114 0.180495 0.201210
-0.121569 0.0194668 0.185292 0.205882
-0.125490 0.0205464 0.190059 0.210508
-0.129412 0.0216498 0.194796 0.215092
-0.133333 0.0227769 0.199504 0.219634
-0.137255 0.0239274 0.204184 0.224136
-0.141176 0.0251012 0.208838 0.228600
-0.145098 0.0262980 0.213466 0.233027
-0.149020 0.0275177 0.218069 0.237418
-0.152941 0.0287600 0.222648 0.241774
-0.156863 0.0300249 0.227204 0.246097
-0.160784 0.0313121 0.231737 0.250388
-0.164706 0.0326215 0.236248 0.254647
-0.168627 0.0339528 0.240737 0.258876
-0.172549 0.0353061 0.245205 0.263076
-0.176471 0.0366810 0.249654 0.267247
-0.180392 0.0380775 0.254082 0.271391
-0.184314 0.0394954 0.258491 0.275507
-0.188235 0.0409345 0.262882 0.279597
-0.192157 0.0423948 0.267254 0.283662
-0.196078 0.0438762 0.271609 0.287702
-0.200000 0.0453784 0.275946 0.291718
-0.203922 0.0469014 0.280266 0.295710
-0.207843 0.0484450 0.284570 0.299680
-0.211765 0.0500091 0.288857 0.303627
-0.215686 0.0515937 0.293128 0.307552
-0.219608 0.0531985 0.297384 0.311455
-0.223529 0.0548235 0.301625 0.315338
-0.227451 0.0564686 0.305851 0.319201
-0.231373 0.0581337 0.310063 0.323043
-0.235294 0.0598187 0.314260 0.326866
-0.239216 0.0615234 0.318443 0.330670
-0.243137 0.0632478 0.322613 0.334456
-0.247059 0.0649918 0.326769 0.338223
-0.250980 0.0667553 0.330911 0.341972
-0.254902 0.0685382 0.335041 0.345703
-0.258824 0.0703403 0.339159 0.349418
-0.262745 0.0721617 0.343264 0.353115
-0.266667 0.0740022 0.347356 0.356797
-0.270588 0.0758618 0.351437 0.360461
-0.274510 0.0777403 0.355505 0.364110
-0.278431 0.0796377 0.359563 0.367744
-0.282353 0.0815539 0.363608 0.371362
-0.286275 0.0834889 0.367643 0.374965
-0.290196 0.0854424 0.371666 0.378553
-0.294118 0.0874146 0.375679 0.382127
-0.298039 0.0894052 0.379681 0.385686
-0.301961 0.0914143 0.383672 0.389231
-0.305882 0.0934417 0.387653 0.392763
-0.309804 0.0954873 0.391624 0.396281
-0.313725 0.0975512 0.395585 0.399786
-0.317647 0.0996332 0.399536 0.403277
-0.321569 0.101733 0.403477 0.406756
-0.325490 0.103851 0.407409 0.410222
-0.329412 0.105987 0.411331 0.413676
-0.333333 0.108141 0.415244 0.417117
-0.337255 0.110313 0.419147 0.420546
-0.341176 0.112503 0.423042 0.423963
-0.345098 0.114710 0.426927 0.427368
-0.349020 0.116935 0.430804 0.430762
-0.352941 0.119177 0.434672 0.434144
-0.356863 0.121437 0.438532 0.437515
-0.360784 0.123714 0.442383 0.440875
-0.364706 0.126009 0.446225 0.444224
-0.368627 0.128321 0.450060 0.447563
-0.372549 0.130650 0.453886 0.450890
-0.376471 0.132997 0.457704 0.454207
-0.380392 0.135360 0.461514 0.457514
-0.384314 0.137741 0.465317 0.460811
-0.388235 0.140139 0.469111 0.464097
-0.392157 0.142554 0.472898 0.467374
-0.396078 0.144986 0.476678 0.470641
-0.400000 0.147435 0.480450 0.473898
-0.403922 0.149900 0.484214 0.477145
-0.407843 0.152383 0.487972 0.480383
-0.411765 0.154882 0.491722 0.483612
-0.415686 0.157398 0.495465 0.486831
-0.419608 0.159931 0.499200 0.490042
-0.423529 0.162480 0.502929 0.493243
-0.427451 0.165046 0.506651 0.496436
-0.431373 0.167628 0.510366 0.499619
-0.435294 0.170227 0.514075 0.502794
-0.439216 0.172842 0.517776 0.505961
-0.443137 0.175474 0.521472 0.509119
-0.447059 0.178122 0.525160 0.512269
-0.450980 0.180787 0.528842 0.515410
-0.454902 0.183467 0.532518 0.518543
-0.458824 0.186164 0.536187 0.521668
-0.462745 0.188877 0.539850 0.524785
-0.466667 0.191606 0.543507 0.527895
-0.470588 0.194351 0.547158 0.530996
-0.474510 0.197113 0.550803 0.534090
-0.478431 0.199890 0.554441 0.537176
-0.482353 0.202684 0.558074 0.540254
-0.486275 0.205493 0.561701 0.543325
-0.490196 0.208318 0.565322 0.546388
-0.494118 0.211159 0.568937 0.549444
-0.498039 0.214016 0.572547 0.552493
-0.501961 0.216889 0.576150 0.555535
-0.505882 0.219777 0.579748 0.558569
-0.509804 0.222681 0.583341 0.561597
-0.513725 0.225601 0.586928 0.564617
-0.517647 0.228536 0.590510 0.567631
-0.521569 0.231487 0.594086 0.570638
-0.525490 0.234454 0.597657 0.573638
-0.529412 0.237436 0.601222 0.576631
-0.533333 0.240434 0.604782 0.579618
-0.537255 0.243447 0.608337 0.582598
-0.541176 0.246476 0.611887 0.585571
-0.545098 0.249520 0.615431 0.588538
-0.549020 0.252579 0.618971 0.591499
-0.552941 0.255654 0.622505 0.594453
-0.556863 0.258744 0.626035 0.597401
-0.560784 0.261849 0.629559 0.600343
-0.564706 0.264970 0.633079 0.603279
-0.568627 0.268105 0.636594 0.606208
-0.572549 0.271256 0.640103 0.609132
-0.576471 0.274422 0.643608 0.612049
-0.580392 0.277603 0.647109 0.614961
-0.584314 0.280800 0.650604 0.617867
-0.588235 0.284011 0.654095 0.620766
-0.592157 0.287237 0.657581 0.623661
-0.596078 0.290478 0.661063 0.626549
-0.600000 0.293735 0.664540 0.629431
-0.603922 0.297006 0.668012 0.632308
-0.607843 0.300292 0.671480 0.635180
-0.611765 0.303593 0.674944 0.638045
-0.615686 0.306909 0.678403 0.640906
-0.619608 0.310239 0.681857 0.643761
-0.623529 0.313585 0.685308 0.646610
-0.627451 0.316945 0.688754 0.649454
-0.631373 0.320320 0.692195 0.652293
-0.635294 0.323709 0.695633 0.655126
-0.639216 0.327114 0.699066 0.657954
-0.643137 0.330533 0.702495 0.660777
-0.647059 0.333966 0.705919 0.663595
-0.650980 0.337414 0.709340 0.666408
-0.654902 0.340877 0.712756 0.669215
-0.658824 0.344354 0.716169 0.672018
-0.662745 0.347846 0.719577 0.674816
-0.666667 0.351352 0.722981 0.677608
-0.670588 0.354873 0.726381 0.680396
-0.674510 0.358408 0.729778 0.683179
-0.678431 0.361958 0.733170 0.685957
-0.682353 0.365522 0.736559 0.688730
-0.686275 0.369100 0.739943 0.691498
-0.690196 0.372693 0.743324 0.694262
-0.694118 0.376300 0.746701 0.697021
-0.698039 0.379921 0.750074 0.699775
-0.701961 0.383557 0.753443 0.702525
-0.705882 0.387207 0.756808 0.705270
-0.709804 0.390871 0.760170 0.708010
-0.713725 0.394549 0.763528 0.710746
-0.717647 0.398242 0.766882 0.713477
-0.721569 0.401948 0.770233 0.716204
-0.725490 0.405669 0.773580 0.718927
-0.729412 0.409404 0.776923 0.721645
-0.733333 0.413153 0.780263 0.724358
-0.737255 0.416916 0.783599 0.727068
-0.741176 0.420693 0.786932 0.729773
-0.745098 0.424484 0.790261 0.732473
-0.749020 0.428289 0.793587 0.735170
-0.752941 0.432108 0.796909 0.737862
-0.756863 0.435940 0.800228 0.740550
-0.760784 0.439787 0.803543 0.743234
-0.764706 0.443648 0.806855 0.745914
-0.768627 0.447523 0.810164 0.748589
-0.772549 0.451411 0.813469 0.751261
-0.776471 0.455314 0.816770 0.753928
-0.780392 0.459230 0.820069 0.756592
-0.784314 0.463160 0.823364 0.759251
-0.788235 0.467103 0.826656 0.761906
-0.792157 0.471061 0.829944 0.764558
-0.796078 0.475032 0.833230 0.767205
-0.800000 0.479017 0.836512 0.769849
-0.803922 0.483016 0.839790 0.772489
-0.807843 0.487028 0.843066 0.775124
-0.811765 0.491054 0.846339 0.777756
-0.815686 0.495094 0.849608 0.780385
-0.819608 0.499147 0.852874 0.783009
-0.823529 0.503214 0.856137 0.785630
-0.827451 0.507294 0.859397 0.788247
-0.831373 0.511388 0.862654 0.790860
-0.835294 0.515496 0.865908 0.793469
-0.839216 0.519617 0.869158 0.796075
-0.843137 0.523751 0.872406 0.798677
-0.847059 0.527899 0.875651 0.801276
-0.850980 0.532061 0.878892 0.803871
-0.854902 0.536236 0.882131 0.806462
-0.858824 0.540424 0.885367 0.809050
-0.862745 0.544626 0.888599 0.811634
-0.866667 0.548841 0.891829 0.814215
-0.870588 0.553070 0.895056 0.816792
-0.874510 0.557311 0.898280 0.819366
-0.878431 0.561567 0.901501 0.821936
-0.882353 0.565835 0.904719 0.824503
-0.886275 0.570117 0.907935 0.827066
-0.890196 0.574412 0.911147 0.829626
-0.894118 0.578721 0.914357 0.832183
-0.898039 0.583042 0.917564 0.834736
-0.901961 0.587377 0.920768 0.837286
-0.905882 0.591725 0.923969 0.839833
-0.909804 0.596087 0.927168 0.842376
-0.913725 0.600461 0.930363 0.844916
-0.917647 0.604849 0.933556 0.847453
-0.921569 0.609249 0.936747 0.849986
-0.925490 0.613663 0.939934 0.852516
-0.929412 0.618090 0.943119 0.855044
-0.933333 0.622530 0.946301 0.857567
-0.937255 0.626984 0.949481 0.860088
-0.941176 0.631450 0.952658 0.862606
-0.945098 0.635929 0.955832 0.865120
-0.949020 0.640421 0.959003 0.867631
-0.952941 0.644927 0.962172 0.870139
-0.956863 0.649445 0.965339 0.872644
-0.960784 0.653976 0.968502 0.875146
-0.964706 0.658521 0.971664 0.877645
-0.968627 0.663078 0.974822 0.880141
-0.972549 0.667648 0.977978 0.882634
-0.976471 0.672231 0.981132 0.885124
-0.980392 0.676827 0.984283 0.887610
-0.984314 0.681436 0.987431 0.890094
-0.988235 0.686058 0.990577 0.892575
-0.992157 0.690692 0.993721 0.895053
-0.996078 0.695340 0.996862 0.897528
-1.000000 0.700000 1.000000 0.900000
-END_DATA
diff --git a/spectro/usbio.c b/spectro/usbio.c
index 9f8964a..668544a 100644
--- a/spectro/usbio.c
+++ b/spectro/usbio.c
@@ -118,7 +118,7 @@ int rwsize, /* Bytes to read or write */
double tout /* Timeout in seconds */
) {
int rv = 0; /* Return value */
- int rwbytes; /* Data bytes read or written */
+ int c, rwbytes; /* Data bytes read or written */
long top; /* timeout in msec */
if (p->log->debug >= 8) {
@@ -412,7 +412,7 @@ double tout)
/* Until data is all written, we time out, or the user aborts */
for (top = ttop; top > 0 && len > 0;) {
- int rv;
+ int c, rv;
a1logd(p->log, 8, "icoms_usb_ser_write: attempting to write %d bytes to usb top = %d\n",len,top);
rv = icoms_usb_transaction(p, NULL, &wbytes, type, (unsigned char)ep, (unsigned char *)wbuf, len, top);
diff --git a/spectro/usbio_nt.c b/spectro/usbio_nt.c
index f5c3af8..8daac0d 100644
--- a/spectro/usbio_nt.c
+++ b/spectro/usbio_nt.c
@@ -567,7 +567,7 @@ char **pnames /* List of process names to try and kill before opening */
/* -------------------------------------------------------------- */
-/* Our universal USB transfer function, used for rd/wr. */
+/* Our universal USB transfer function */
/* It appears that we may return a timeout with valid characters. */
static int icoms_usb_transaction(
icoms *p,
diff --git a/target/ifarp.c b/target/ifarp.c
index 03fc914..544f316 100644
--- a/target/ifarp.c
+++ b/target/ifarp.c
@@ -310,7 +310,6 @@ ifarp_del(ifarp *s) {
/* Constructor */
ifarp *new_ifarp(
-int verb, /* Verbosity */
int di, /* Dimensionality of device space */
double ilimit, /* Ink limit (sum of device coords max) */
int inp, /* Number of points to generate */
@@ -321,6 +320,7 @@ void *od /* context for Perceptual function */
) {
ifarp *s;
int e, i;
+ int verb = 1;
#ifdef DEBUG
printf("new_ifarp called with di %d, inp %d, fxno = %d\n",di,inp,fxno);
@@ -855,7 +855,7 @@ char *argv[];
error ("Creation of xcolorant lu object failed");
/* Create the required points */
- s = new_ifarp(1, di, 1.5, npoints, NULL, 0, sa_percept, (void *)NULL);
+ s = new_ifarp(di, 1.5, npoints, NULL, 0, sa_percept, (void *)NULL);
#ifdef DEBUG
/* Dump perceptual map */
diff --git a/target/ifarp.h b/target/ifarp.h
index ee18840..083411b 100644
--- a/target/ifarp.h
+++ b/target/ifarp.h
@@ -59,10 +59,9 @@ struct _ifarp {
}; typedef struct _ifarp ifarp;
/* Constructor */
-extern ifarp *new_ifarp(int verb, int di, double ilimit, int npoints,
+extern ifarp *new_ifarp(int di, double ilimit, int npoints,
fxpos *fxlist, int fxno,
- void (*percept)(void *od, double *out, double *in), void *od
-);
+ void (*percept)(void *od, double *out, double *in), void *od);
#define IFARP_H
#endif /* IFARP_H */
diff --git a/target/printtarg.c b/target/printtarg.c
index 1b03b3c..863537f 100644
--- a/target/printtarg.c
+++ b/target/printtarg.c
@@ -2912,8 +2912,8 @@ void usage(char *diag, ...) {
fprintf(stderr," -b Force B&W spacers\n");
fprintf(stderr," -n Force no spacers\n");
fprintf(stderr," -f Create PostScript DeviceN Color fallback\n");
- fprintf(stderr," -w g|r|s|n White colorspace encoding: DeviceGray (def), DeviceRGB, Separation or DeviceN\n");
- fprintf(stderr," -k g|c|s|n Black colorspace encoding: DeviceGray (def), DeviceCMYK, Separation or DeviceN\n");
+ fprintf(stderr," -w g|r|s|n White colorspace encoding DeviceGray (def), DeviceRGB, Separation or DeviceN\n");
+ fprintf(stderr," -k g|c|s|n Black colorspace encoding DeviceGray (def), DeviceCMYK, Separation or DeviceN\n");
fprintf(stderr," -o k|r|n CMY colorspace encoding DeviceCMYK (def), inverted DeviceRGB or DeviceN\n");
fprintf(stderr," -e Output EPS compatible file\n");
fprintf(stderr," -t [res] Output 8 bit TIFF raster file, optional res DPI (default 100)\n");
@@ -3645,16 +3645,12 @@ char *argv[];
}
}
- if (pap != NULL) {
- sprintf(buf, "%.1fx%.1f",pap->w, pap->h);
- if (verb)
+ if (verb) {
+ if (pap != NULL)
printf("Paper chosen is %s [%.1f x %.1f mm]\n", pap->name, pap->w, pap->h);
- } else {
- sprintf(buf, "%.1fx%.1f",cwidth, cheight);
- if (verb)
+ else
printf("Paper chosen is custom %.1f x %.1f mm\n", cwidth, cheight);
}
- ocg->add_kword(ocg, 0, "PAPER_SIZE", buf, NULL);
if (rstart == -1) {
rstart = clk % npat;
diff --git a/target/targen.c b/target/targen.c
index a29ef63..4d1d7ac 100644
--- a/target/targen.c
+++ b/target/targen.c
@@ -2165,7 +2165,7 @@ int main(int argc, char *argv[]) {
/* for some of these (new_prand). */
if (uselat) {
/* A "greedy"/incremental far point approach */
- t = new_ifarp(verb, di, uilimit, fsteps, fxlist, fxno,
+ t = new_ifarp(di, uilimit, fsteps, fxlist, fxno,
(void(*)(void *, double *, double *))pdata->dev_to_perc, (void *)pdata);
sprintf(buf,"%d",fsteps - fxno);
pp->add_kword(pp, 0, "IFP_PATCHES", buf, NULL);
diff --git a/usb/ArgyllCMS.cat b/usb/ArgyllCMS.cat
index 2b713c9..91c5a81 100644
--- a/usb/ArgyllCMS.cat
+++ b/usb/ArgyllCMS.cat
Binary files differ
diff --git a/usb/ArgyllCMS.inf b/usb/ArgyllCMS.inf
index db0995f..4de9f51 100644
--- a/usb/ArgyllCMS.inf
+++ b/usb/ArgyllCMS.inf
@@ -1,229 +1,229 @@
-;--------------------------------------------------------------------------
-; Copyright 2012 Graeme W. Gill.
-;
-; Permission is hereby granted, free of charge, to any person obtaining a copy
-; of this file, to deal
-; in this file without restriction, including without limitation the rights
-; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-; copies of this file, and to permit persons to whom this file is
-; furnished to do so, subject to the following conditions:
-;
-; The above copyright notice and this permission notice shall be included in
-; all copies or substantial portions of this file.
-;
-; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
-; THIS FILE.
-;--------------------------------------------------------------------------
-
-; ==== Strings ====
-
-[Strings]
-
-DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
-
-Date = "01/17/2012" ; MM/DD/YYYY
-libusb0ver = "1.2.6.0"
-
-Libusb_ClassName = "Argyll LibUSB-win32 devices"
-Libusb_DiskName = "LibUSB-win32 Device Install Disk"
-
-libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
-
-; ==== Version ====
-
-[Version]
-Signature = "$Windows NT$"
-DriverVer = %Date%,%libusb0ver%
-Provider = "ArgyllCMS"
-
-; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
-Class = %Libusb_ClassName%
-ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
-CatalogFile = "ArgyllCMS.cat"
-CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
-
-[ClassInstall32]
-AddReg=class_install_add_reg
-
-[class_install_add_reg]
-HKR,,,,%Libusb_ClassName%
-HKR,,Icon,,"-20" ; -20 is for the USB icon
-
-; ==== Files Sources and Destinations ====
-
-[SourceDisksNames]
-1 = %Libusb_DiskName%
-
-[SourceDisksFiles]
-libusb0.sys = 1,\bin\x86,
-
-[SourceDisksFiles.amd64]
-libusb0.sys = 1,\bin\amd64,
-
-[DestinationDirs]
-libusb0_files_sys = 10,system32\drivers
-
-; ==== libusb0 Device driver ====
-
-[libusb0_files_sys]
-libusb0.sys,libusb0.sys
-
-; For each one of these, there must be one for Services !!!
-[LIBUSB0_DEV]
-CopyFiles = Libusb0_files_sys
-
-[LIBUSB0_DEV.HW]
-AddReg = libusb0_add_reg_hw
-
-[libusb0_add_reg]
-HKR,,DevLoader,,*ntkern
-HKR,,NTMPDriver,,libusb0.sys
-
-[libusb0_add_reg_hw]
-HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
-HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
-
-[LIBUSB0_DEV.Services]
-AddService = libusb0, 0x00000002, libusb0_add_service
-
-[libusb0_add_service]
-DisplayName = %libusb0_SvcDesc%
-ServiceType = 1
-StartType = 3
-ErrorControl = 0
-ServiceBinary = %12%\libusb0.sys
-
-; ==== Manufacturers ====
-
-[Manufacturer]
-"HCFR Association"=HCFR_Devices,NTx86,NTamd64
-"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
-"X-Rite"=X_Rite_Devices,NTx86,NTamd64
-"ColorVision"=ColorVision_Devices,NTx86,NTamd64
-"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
-"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
-"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
-
-; ==== Devices ====
-
-[HCFR_Devices]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
-
-[HCFR_Devices.NTx86]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices.NTx86]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices.NTx86]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices.NTx86]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices.NTx86]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices.NTx86]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices.NTx86]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
-
-[HCFR_Devices.NTamd64]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices.NTamd64]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices.NTamd64]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices.NTamd64]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices.NTamd64]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices.NTamd64]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices.NTamd64]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
+;--------------------------------------------------------------------------
+; Copyright 2012 Graeme W. Gill.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this file, to deal
+; in this file without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of this file, and to permit persons to whom this file is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of this file.
+;
+; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
+; THIS FILE.
+;--------------------------------------------------------------------------
+
+; ==== Strings ====
+
+[Strings]
+
+DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
+
+Date = "01/17/2012" ; MM/DD/YYYY
+libusb0ver = "1.2.6.0"
+
+Libusb_ClassName = "Argyll LibUSB-win32 devices"
+Libusb_DiskName = "LibUSB-win32 Device Install Disk"
+
+libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
+
+; ==== Version ====
+
+[Version]
+Signature = "$Windows NT$"
+DriverVer = %Date%,%libusb0ver%
+Provider = "ArgyllCMS"
+
+; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
+Class = %Libusb_ClassName%
+ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
+CatalogFile = "ArgyllCMS.cat"
+CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
+
+[ClassInstall32]
+AddReg=class_install_add_reg
+
+[class_install_add_reg]
+HKR,,,,%Libusb_ClassName%
+HKR,,Icon,,"-20" ; -20 is for the USB icon
+
+; ==== Files Sources and Destinations ====
+
+[SourceDisksNames]
+1 = %Libusb_DiskName%
+
+[SourceDisksFiles]
+libusb0.sys = 1,\bin\x86,
+
+[SourceDisksFiles.amd64]
+libusb0.sys = 1,\bin\amd64,
+
+[DestinationDirs]
+libusb0_files_sys = 10,system32\drivers
+
+; ==== libusb0 Device driver ====
+
+[libusb0_files_sys]
+libusb0.sys,libusb0.sys
+
+; For each one of these, there must be one for Services !!!
+[LIBUSB0_DEV]
+CopyFiles = Libusb0_files_sys
+
+[LIBUSB0_DEV.HW]
+AddReg = libusb0_add_reg_hw
+
+[libusb0_add_reg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,libusb0.sys
+
+[libusb0_add_reg_hw]
+HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
+HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
+
+[LIBUSB0_DEV.Services]
+AddService = libusb0, 0x00000002, libusb0_add_service
+
+[libusb0_add_service]
+DisplayName = %libusb0_SvcDesc%
+ServiceType = 1
+StartType = 3
+ErrorControl = 0
+ServiceBinary = %12%\libusb0.sys
+
+; ==== Manufacturers ====
+
+[Manufacturer]
+"HCFR Association"=HCFR_Devices,NTx86,NTamd64
+"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
+"X-Rite"=X_Rite_Devices,NTx86,NTamd64
+"ColorVision"=ColorVision_Devices,NTx86,NTamd64
+"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
+"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
+"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
+
+; ==== Devices ====
+
+[HCFR_Devices]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
+
+[HCFR_Devices.NTx86]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices.NTx86]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices.NTx86]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices.NTx86]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices.NTx86]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices.NTx86]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices.NTx86]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
+
+[HCFR_Devices.NTamd64]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices.NTamd64]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices.NTamd64]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices.NTamd64]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices.NTamd64]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices.NTamd64]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices.NTamd64]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
diff --git a/usb/ArgyllCMS.inf.d b/usb/ArgyllCMS.inf.d
index c0809e9..c130cee 100644
--- a/usb/ArgyllCMS.inf.d
+++ b/usb/ArgyllCMS.inf.d
@@ -1,39 +1,39 @@
-
-[HCFR_Devices#PLAT#]
-"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
-"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
-
-[Sequel_Devices#PLAT#]
-"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
-
-[X_Rite_Devices#PLAT#]
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
-"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
-"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
-"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
-"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
-"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
-"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
-
-[ColorVision_Devices#PLAT#]
-"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
-"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
-"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
-"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
-"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
-
-[GM_X_Rite_Devices#PLAT#]
-"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
-"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
-"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
-"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
-"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
-
-[Hughski_Devices#PLAT#]
-"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
-"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
-
-[ImageEngineering_Devices#PLAT#]
-"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
-
+
+[HCFR_Devices#PLAT#]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices#PLAT#]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices#PLAT#]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices#PLAT#]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+"Spyder5 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0500
+
+[GM_X_Rite_Devices#PLAT#]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices#PLAT#]
+"ColorHug 2 (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1004
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+[ImageEngineering_Devices#PLAT#]
+"EX1 (Argyll)" = LIBUSB0_DEV, USB\VID_2457&PID_4000
+
diff --git a/usb/ArgyllCMS.inf.t b/usb/ArgyllCMS.inf.t
index a185d03..635d9ef 100644
--- a/usb/ArgyllCMS.inf.t
+++ b/usb/ArgyllCMS.inf.t
@@ -1,112 +1,112 @@
-;--------------------------------------------------------------------------
-; Copyright 2012 Graeme W. Gill.
-;
-; Permission is hereby granted, free of charge, to any person obtaining a copy
-; of this file, to deal
-; in this file without restriction, including without limitation the rights
-; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-; copies of this file, and to permit persons to whom this file is
-; furnished to do so, subject to the following conditions:
-;
-; The above copyright notice and this permission notice shall be included in
-; all copies or substantial portions of this file.
-;
-; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
-; THIS FILE.
-;--------------------------------------------------------------------------
-
-; ==== Strings ====
-
-[Strings]
-
-DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
-
-Date = "01/17/2012" ; MM/DD/YYYY
-libusb0ver = "1.2.6.0"
-
-Libusb_ClassName = "Argyll LibUSB-win32 devices"
-Libusb_DiskName = "LibUSB-win32 Device Install Disk"
-
-libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
-
-; ==== Version ====
-
-[Version]
-Signature = "$Windows NT$"
-DriverVer = %Date%,%libusb0ver%
-Provider = "ArgyllCMS"
-
-; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
-Class = %Libusb_ClassName%
-ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
-CatalogFile = "ArgyllCMS.cat"
-CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
-
-[ClassInstall32]
-AddReg=class_install_add_reg
-
-[class_install_add_reg]
-HKR,,,,%Libusb_ClassName%
-HKR,,Icon,,"-20" ; -20 is for the USB icon
-
-; ==== Files Sources and Destinations ====
-
-[SourceDisksNames]
-1 = %Libusb_DiskName%
-
-[SourceDisksFiles]
-libusb0.sys = 1,\bin\x86,
-
-[SourceDisksFiles.amd64]
-libusb0.sys = 1,\bin\amd64,
-
-[DestinationDirs]
-libusb0_files_sys = 10,system32\drivers
-
-; ==== libusb0 Device driver ====
-
-[libusb0_files_sys]
-libusb0.sys,libusb0.sys
-
-; For each one of these, there must be one for Services !!!
-[LIBUSB0_DEV]
-CopyFiles = Libusb0_files_sys
-
-[LIBUSB0_DEV.HW]
-AddReg = libusb0_add_reg_hw
-
-[libusb0_add_reg]
-HKR,,DevLoader,,*ntkern
-HKR,,NTMPDriver,,libusb0.sys
-
-[libusb0_add_reg_hw]
-HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
-HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
-
-[LIBUSB0_DEV.Services]
-AddService = libusb0, 0x00000002, libusb0_add_service
-
-[libusb0_add_service]
-DisplayName = %libusb0_SvcDesc%
-ServiceType = 1
-StartType = 3
-ErrorControl = 0
-ServiceBinary = %12%\libusb0.sys
-
-; ==== Manufacturers ====
-
-[Manufacturer]
-"HCFR Association"=HCFR_Devices,NTx86,NTamd64
-"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
-"X-Rite"=X_Rite_Devices,NTx86,NTamd64
-"ColorVision"=ColorVision_Devices,NTx86,NTamd64
-"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
-"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
-"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
-
-; ==== Devices ====
+;--------------------------------------------------------------------------
+; Copyright 2012 Graeme W. Gill.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this file, to deal
+; in this file without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of this file, and to permit persons to whom this file is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of this file.
+;
+; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
+; THIS FILE.
+;--------------------------------------------------------------------------
+
+; ==== Strings ====
+
+[Strings]
+
+DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
+
+Date = "01/17/2012" ; MM/DD/YYYY
+libusb0ver = "1.2.6.0"
+
+Libusb_ClassName = "Argyll LibUSB-win32 devices"
+Libusb_DiskName = "LibUSB-win32 Device Install Disk"
+
+libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
+
+; ==== Version ====
+
+[Version]
+Signature = "$Windows NT$"
+DriverVer = %Date%,%libusb0ver%
+Provider = "ArgyllCMS"
+
+; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
+Class = %Libusb_ClassName%
+ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
+CatalogFile = "ArgyllCMS.cat"
+CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
+
+[ClassInstall32]
+AddReg=class_install_add_reg
+
+[class_install_add_reg]
+HKR,,,,%Libusb_ClassName%
+HKR,,Icon,,"-20" ; -20 is for the USB icon
+
+; ==== Files Sources and Destinations ====
+
+[SourceDisksNames]
+1 = %Libusb_DiskName%
+
+[SourceDisksFiles]
+libusb0.sys = 1,\bin\x86,
+
+[SourceDisksFiles.amd64]
+libusb0.sys = 1,\bin\amd64,
+
+[DestinationDirs]
+libusb0_files_sys = 10,system32\drivers
+
+; ==== libusb0 Device driver ====
+
+[libusb0_files_sys]
+libusb0.sys,libusb0.sys
+
+; For each one of these, there must be one for Services !!!
+[LIBUSB0_DEV]
+CopyFiles = Libusb0_files_sys
+
+[LIBUSB0_DEV.HW]
+AddReg = libusb0_add_reg_hw
+
+[libusb0_add_reg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,libusb0.sys
+
+[libusb0_add_reg_hw]
+HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
+HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
+
+[LIBUSB0_DEV.Services]
+AddService = libusb0, 0x00000002, libusb0_add_service
+
+[libusb0_add_service]
+DisplayName = %libusb0_SvcDesc%
+ServiceType = 1
+StartType = 3
+ErrorControl = 0
+ServiceBinary = %12%\libusb0.sys
+
+; ==== Manufacturers ====
+
+[Manufacturer]
+"HCFR Association"=HCFR_Devices,NTx86,NTamd64
+"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
+"X-Rite"=X_Rite_Devices,NTx86,NTamd64
+"ColorVision"=ColorVision_Devices,NTx86,NTamd64
+"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
+"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
+"Image Engineering"=ImageEngineering_Devices,NTx86,NTamd64
+
+; ==== Devices ====
diff --git a/usb/ArgyllCMS_x64.cat b/usb/ArgyllCMS_x64.cat
index 1bed3d1..24b915e 100644
--- a/usb/ArgyllCMS_x64.cat
+++ b/usb/ArgyllCMS_x64.cat
Binary files differ
diff --git a/xicc/bt1886.c b/xicc/bt1886.c
index ddd6066..3f94dbe 100644
--- a/xicc/bt1886.c
+++ b/xicc/bt1886.c
@@ -107,8 +107,8 @@ void bt1886_setnop(bt1886_info *p) {
p->outsc = 1.0;
p->outo = 0.0;
p->outL = 0.0;
- p->tab[0] = 0.0;
p->tab[1] = 0.0;
+ p->tab[2] = 0.0;
}
/* Setup the bt1886_info for the given target black point, proportion of */
diff --git a/xicc/cam02.c b/xicc/cam02.c
index 376d2c8..5140f04 100644
--- a/xicc/cam02.c
+++ b/xicc/cam02.c
@@ -9,7 +9,7 @@
* Conference, with the addition of the Viewing Flare
* model described on page 487 of "Digital Color Management",
* by Edward Giorgianni and Thomas Madden, and the
- * Helmholtz-Kohlrausch effect, using the equation from
+ * Helmholtz-Kohlraush effect, using the equation from
* the Bradford-Hunt 96C model as detailed in Mark Fairchild's
* book "Color Appearance Models".
* The Slight modification to the Hunt-Pointer-Estevez matrix
@@ -40,9 +40,7 @@
/*
TTBD: Should convert to using Timo Kunkel and Erik Reinhard's simplified
- and improved version of CIECAM02
- [ "A Neurophysiology-Inspired Steady-State Color Appearance Model",
- ie. "CIECAM02-KR" ? ]
+ and improved version of CIECAM02 (ie. "CIECAM02-KR").
The rgbp compression has it's problems in terms of perceptual
uniformity. A color with one component near zero might shift
@@ -107,7 +105,7 @@
XYZ space, the J value used to multiply Chroma, is limited
to be equivalent to not less than A == 0.1.
- The Helmholtz-Kohlrausch effect is crafted to have resonable
+ The Helmholtz-Kohlraush effect is crafted to have resonable
effects over the range of J from 0 to 100, and have more
moderate effects outside this range.
@@ -138,11 +136,7 @@
#undef DISABLE_HPE /* Debug - disable just Hunt-Pointer_Estevez matrix */
#undef DISABLE_NONLIN /* Debug - wire rgbp to rgba */
#undef DISABLE_TTD /* Debug - disable ttd vector 'tilt' */
-#undef DISABLE_HHKR /* Debug - disable Helmholtz-Kohlrausch */
-
- /* We reduce the HK effect from the Hunt equation, in the */
- /* light of real wold experiments. */
-#define HHKR_MUL 0.25 /* [0.25] - Helmholtz-Kohlrausch strength multiplier */
+#undef DISABLE_HHKR /* Debug - disable Helmholtz-Kohlraush */
#ifdef ENABLE_COMPR
# define BC_WHMINY 0.2 /* [0.2] Compression direction minimum Y value */
@@ -175,7 +169,7 @@
#define DDULIMIT 0.34 /* [0.34] ab component k3:k1 ratio limit (must be < 1.0) */
#define SSMINcJ 0.005 /* [0.005] ab scale cJ minimum value */
#define JLIMIT 0.005 /* [0.005] J encoding cutover point straight line (0 - 1.0 range) */
-#define HKLIMIT 0.7 /* [0.7] Maximum Helmholtz-Kohlrausch lift out of 1.0 */
+#define HKLIMIT 0.7 /* [0.7] Maximum Helmholtz-Kohlraush lift */
#ifdef TRACKMINMAX
double minss = 1e60;
@@ -288,7 +282,7 @@ double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) *
double Yg, /* Flare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
double Gxyz[3], /* The Glare white coordinates (typically the Ambient color) */
/* If <= 0 will Wxyz will be used. */
-int hk /* Flag, NZ to use Helmholtz-Kohlrausch effect */
+int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
) {
double tt, t1, t2;
double tm[3][3];
@@ -946,10 +940,9 @@ double XYZ[3]
JJ = J;
#ifndef DISABLE_HHKR
- /* Helmholtz-Kohlrausch effect */
+ /* Helmholtz-Kohlraush effect */
if (s->hk && J < 1.0) {
-// double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
- double kk = HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
if (kk > 1e-6) /* Limit kk to a reasonable range */
kk = 1.0/(s->hklimit + 1.0/kk);
JJ = J + (1.0 - (J > 0.0 ? J : 0.0)) * kk;
@@ -1042,10 +1035,9 @@ double Jab[3]
J = JJ;
#ifndef DISABLE_HHKR
- /* Undo Helmholtz-Kohlrausch effect */
+ /* Undo Helmholtz-Kohlraush effect */
if (s->hk && J < 1.0) {
-// double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
- double kk = HHKR_MUL * C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
if (kk > 1e-6) /* Limit kk to a reasonable range */
kk = 1.0/(s->hklimit + 1.0/kk);
J = (JJ - kk)/(1.0 - kk);
diff --git a/xicc/iccgamut.c b/xicc/iccgamut.c
index 77f8fdd..a77653f 100644
--- a/xicc/iccgamut.c
+++ b/xicc/iccgamut.c
@@ -86,7 +86,7 @@ void usage(char *diag) {
fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
fprintf(stderr," l:imagewhite Image white in cd.m^2 if surround = auto (default 250)\n");
fprintf(stderr," f:flare Flare light %% of image luminance (default 0)\n");
- fprintf(stderr," g:glare Flare light %% of ambient (default %d)\n",XICC_DEFAULT_GLARE);
+ fprintf(stderr," g:glare Flare light %% of ambient (default 1)\n");
fprintf(stderr," g:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
fprintf(stderr," g:x:y Flare color as x, y\n");
fprintf(stderr," -s Create special cube surface topology plot\n");
diff --git a/xicc/tiffgamut.c b/xicc/tiffgamut.c
index e373fbd..9ddb62b 100644
--- a/xicc/tiffgamut.c
+++ b/xicc/tiffgamut.c
@@ -96,7 +96,7 @@ void usage(void) {
fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
fprintf(stderr," l:imagewhite Image white in cd.m^2 if surround = auto (default 250)\n");
fprintf(stderr," f:flare Flare light %% of image luminance (default 0)\n");
- fprintf(stderr," g:glare Flare light %% of ambient (default %d)\n",XICC_DEFAULT_GLARE);
+ fprintf(stderr," g:glare Flare light %% of ambient (default 1)\n");
fprintf(stderr," g:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
fprintf(stderr," g:x:y Flare color as x, y\n");
fprintf(stderr," -O outputfile Override the default output filename.\n");
diff --git a/xicc/tiffgmts.c b/xicc/tiffgmts.c
index 446ea5c..c31f852 100644
--- a/xicc/tiffgmts.c
+++ b/xicc/tiffgmts.c
@@ -58,7 +58,7 @@ void usage(void) {
fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n");
fprintf(stderr," s = saturation, a = absolute (default), d = profile default\n");
// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
- fprintf(stderr," -p oride l = Lab_PCS (default), j = %s Appearance Jab\n",icxcam_description(cam_default));
+ fprintf(stderr," -p oride l = Lab_PCS (default), j = %s Appearance Jab\n",icxcam_description(cam_default),icxcam_description(cam_default));
fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
fprintf(stderr," -c viewcond set appearance mode and viewing conditions for %s,\n",icxcam_description(cam_default));
@@ -77,7 +77,7 @@ void usage(void) {
fprintf(stderr," a:adaptation Adaptation luminance in cd.m^2 (default 50.0)\n");
fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
fprintf(stderr," f:flare Flare light %% of image luminance (default 0)\n");
- fprintf(stderr," g:glare Flare light %% of ambient (default 2)\n");
+ fprintf(stderr," g:glare Flare light %% of ambient (default 1)\n");
fprintf(stderr," g:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
fprintf(stderr," g:x:y Flare color as x, y\n");
fprintf(stderr," -V L,a,b Overide normal vector direction for span\n");
diff --git a/xicc/xicc.c b/xicc/xicc.c
index 058f492..a7556d5 100644
--- a/xicc/xicc.c
+++ b/xicc/xicc.c
@@ -1704,7 +1704,7 @@ double *wp /* Provide white point if xicc is NULL */
Glare is assumed to be from the ambient light reflecting from the display
and also striking the observer directly, and is (typically) defaulted
- to 1% of ambient here. (too low ? Typical displays are 4-10%)
+ to 1% of ambient here.
*/
@@ -1719,7 +1719,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 250.0; /* Average viewing conditions ratio */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 2
@@ -1733,7 +1733,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 2000.0/3.1415; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 0
@@ -1747,7 +1747,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 500.0/3.1415; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 1
@@ -1761,7 +1761,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 150.0; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 4
@@ -1775,7 +1775,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 150.0; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 3
@@ -1789,7 +1789,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 120.0; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 5
@@ -1803,7 +1803,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 100.0; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 6
@@ -1817,7 +1817,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 80.0; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 7
@@ -1831,7 +1831,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Lv = 80.0; /* White of the image field */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 8
@@ -1845,7 +1845,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->Yb = 0.2; /* Grey world */
vc->Lv = 1000.0/3.1415; /* White of the image field */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else if (no == 9
@@ -1884,7 +1884,7 @@ double *wp /* Provide white point if xicc is NULL */
vc->La = 53.0; /* Dim, adapted to slide ? */
vc->Yb = 0.2; /* Grey world */
vc->Yf = 0.0; /* 0% flare */
- vc->Yg = 0.01 * XICC_DEFAULT_GLARE; /* 5% glare */
+ vc->Yg = 0.01; /* 1% glare */
}
}
else {
@@ -2023,7 +2023,6 @@ char *as /* Alias string selector, NULL for none */
gmi->gamcknf = 0.0;
gmi->gamxknf = 0.0;
gmi->gampwf = 0.0;
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0;
gmi->satenh = 0.0; /* No saturation enhancement */
}
@@ -2056,7 +2055,6 @@ char *as /* Alias string selector, NULL for none */
gmi->gamcknf = 0.0;
gmi->gamxknf = 0.0;
gmi->gampwf = 0.0;
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0;
gmi->satenh = 0.0; /* No saturation enhancement */
}
@@ -2082,7 +2080,6 @@ char *as /* Alias string selector, NULL for none */
gmi->gamcknf = 0.0;
gmi->gamxknf = 0.0;
gmi->gampwf = 0.0;
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0;
gmi->satenh = 0.0; /* No saturation enhancement */
}
@@ -2110,7 +2107,6 @@ char *as /* Alias string selector, NULL for none */
gmi->gamcknf = 0.0;
gmi->gamxknf = 0.0;
gmi->gampwf = 0.0;
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0;
gmi->satenh = 0.0; /* No saturation enhancement */
}
@@ -2137,7 +2133,6 @@ char *as /* Alias string selector, NULL for none */
gmi->gamcknf = 0.0; /* No knee in gamut compress */
gmi->gamxknf = 0.0; /* No knee in gamut expand */
gmi->gampwf = 0.0; /* No Perceptual surface weighting factor */
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0; /* No Saturation surface weighting factor */
gmi->satenh = 0.0; /* No saturation enhancement */
}
@@ -2163,10 +2158,9 @@ char *as /* Alias string selector, NULL for none */
gmi->bph = gmm_bendBP; /* extent and bend */
gmi->gamcpf = 1.0; /* Full gamut compression */
gmi->gamexf = 0.0; /* No gamut expansion */
- gmi->gamcknf = 1.0; /* Full Sigma knee in gamut compress */
+ gmi->gamcknf = 0.9; /* 0.9 High Sigma knee in gamut compress */
gmi->gamxknf = 0.0; /* No knee in gamut expand */
gmi->gampwf = 1.0; /* Full Perceptual surface weighting factor */
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0; /* No Saturation surface weighting factor */
gmi->satenh = 0.0; /* No saturation enhancement */
}
@@ -2190,49 +2184,18 @@ char *as /* Alias string selector, NULL for none */
gmi->bph = gmm_bendBP; /* extent and bend */
gmi->gamcpf = 1.0; /* Full gamut compression */
gmi->gamexf = 0.0; /* No gamut expansion */
- gmi->gamcknf = 1.0; /* Full Sigma knee in gamut compress */
+ gmi->gamcknf = 0.9; /* 0.9 High Sigma knee in gamut compress */
gmi->gamxknf = 0.0; /* No knee in gamut expand */
gmi->gampwf = 1.0; /* Full Perceptual surface weighting factor */
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0; /* No Saturation surface weighting factor */
gmi->satenh = 0.0; /* No saturation enhancement */
}
else if (no == 7
- || (as != NULL && stricmp(as,"lp") == 0)) {
-
- /* Align neutral axes and perceptually map white and black points, */
- /* perceptually compress out of gamut and map appearance space Jab to Jab, */
- /* and heavily weight preserving the luminance over saturation. */
- /* No neutral axis sigma enhancement. */
- no = 7;
- gmi->as = "lp";
- gmi->desc = "lp - Luminance Preserving Perceptual";
- gmi->icci = icPerceptual;
- gmi->usecas = perccas; /* Appearance space */
-// gmi->usecas = 0; /* Lab space */
- gmi->usemap = 1; /* Use gamut mapping */
- gmi->greymf = 1.0; /* Fully align grey axis */
- gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
- gmi->glumwexf = 1.0; /* Fully expand grey axis at white end */
- gmi->glumbcpf = 1.0; /* Fully compress grey axis at black end */
- gmi->glumbexf = 1.0; /* Fully expand grey axis at black end */
- gmi->glumknf = 0.3; /* Low Sigma knee in grey compress/expand */
- gmi->bph = gmm_bendBP; /* extent and bend */
- gmi->gamcpf = 1.0; /* Full gamut compression */
- gmi->gamexf = 0.0; /* No gamut expansion */
- gmi->gamcknf = 1.3; /* [1.3] High Sigma knee in gamut compress */
- gmi->gamxknf = 0.0; /* No knee in gamut expand */
- gmi->gampwf = 0.0; /* No Perceptual weighting factor */
- gmi->gamlpwf = 1.0; /* Full Linear Preserving Perceptual wghtg. factor */
- gmi->gamswf = 0.0; /* No Saturation weighting factor */
- gmi->satenh = 0.0; /* No saturation enhancement */
- }
- else if (no == 8
|| (as != NULL && stricmp(as,"ms") == 0)) {
/* Align neutral axes and perceptually map white and black points, */
/* perceptually compress and expand to match gamuts and map Jab to Jab. */
- no = 8;
+ no = 7;
gmi->as = "ms";
gmi->desc = "ms - Saturation";
gmi->icci = icSaturation;
@@ -2247,19 +2210,18 @@ char *as /* Alias string selector, NULL for none */
gmi->bph = gmm_bendBP; /* extent and bend */
gmi->gamcpf = 1.0; /* Full gamut compression */
gmi->gamexf = 1.0; /* Full gamut expansion */
- gmi->gamcknf = 1.1; /* Sigma knee in gamut compress */
- gmi->gamxknf = 0.4; /* Moderate Sigma knee in gamut expand */
+ gmi->gamcknf = 1.0; /* High Sigma knee in gamut compress/expand */
+ gmi->gamxknf = 0.4; /* Moderate Sigma knee in gamut compress/expand */
gmi->gampwf = 0.2; /* Slight perceptual surface weighting factor */
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.8; /* Most saturation surface weighting factor */
gmi->satenh = 0.0; /* No saturation enhancement */
}
- else if (no == 9
+ else if (no == 8
|| no == icxSaturationGMIntent
|| (as != NULL && stricmp(as,"s") == 0)) {
/* Same as "ms" but enhance saturation */
- no = 9;
+ no = 8;
gmi->as = "s";
gmi->desc = " s - Enhanced Saturation [ICC Saturation]";
gmi->icci = icSaturation;
@@ -2274,18 +2236,17 @@ char *as /* Alias string selector, NULL for none */
gmi->bph = gmm_bendBP; /* extent and bend */
gmi->gamcpf = 1.0; /* Full gamut compression */
gmi->gamexf = 1.0; /* Full gamut expansion */
- gmi->gamcknf = 1.1; /* High sigma knee in gamut compress */
+ gmi->gamcknf = 1.0; /* High sigma knee in gamut compress */
gmi->gamxknf = 0.5; /* Moderate sigma knee in gamut expand */
gmi->gampwf = 0.0; /* No Perceptual surface weighting factor */
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 1.0; /* Full Saturation surface weighting factor */
gmi->satenh = 0.9; /* Medium saturation enhancement */
}
- else if (no == 10
+ else if (no == 9
|| (as != NULL && stricmp(as,"al") == 0)) {
/* Map absolute L*a*b* to L*a*b* and clip out of gamut */
- no = 10;
+ no = 9;
gmi->as = "al";
gmi->desc = "al - Absolute Colorimetric (Lab)";
gmi->icci = icAbsoluteColorimetric;
@@ -2303,16 +2264,15 @@ char *as /* Alias string selector, NULL for none */
gmi->gamcknf = 0.0;
gmi->gamxknf = 0.0;
gmi->gampwf = 0.0;
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0;
gmi->satenh = 0.0; /* No saturation enhancement */
}
- else if (no == 11
+ else if (no == 10
|| (as != NULL && stricmp(as,"rl") == 0)) {
/* Align neutral axes and linearly map white point, then */
/* map L*a*b* to L*a*b* and clip out of gamut */
- no = 11;
+ no = 10;
gmi->as = "rl";
gmi->desc = "rl - White Point Matched Colorimetric (Lab)";
gmi->icci = icRelativeColorimetric;
@@ -2330,7 +2290,6 @@ char *as /* Alias string selector, NULL for none */
gmi->gamcknf = 0.0;
gmi->gamxknf = 0.0;
gmi->gampwf = 0.0;
- gmi->gamlpwf = 0.0; /* No Linear Preserving Perceptual surface wghtg. factor */
gmi->gamswf = 0.0;
gmi->satenh = 0.0; /* No saturation enhancement */
}
@@ -2385,7 +2344,6 @@ icxGMappingIntent *gmi /* Gamut Mapping parameters to return */
printf(" Gamut compression knee factor %f\n", gmi->gamcknf);
printf(" Gamut expansion knee factor %f\n", gmi->gamxknf);
printf(" Gamut Perceptual mapping weighting factor %f\n", gmi->gampwf);
- printf(" Gamut Lightness Preserving Perceptual mapping weighting %f\n", gmi->gamlpwf);
printf(" Gamut Saturation mapping weighting factor %f\n", gmi->gamswf);
printf(" Saturation enhancement factor %f\n", gmi->satenh);
}
diff --git a/xicc/xicc.h b/xicc/xicc.h
index a5ecf95..f521de2 100644
--- a/xicc/xicc.h
+++ b/xicc/xicc.h
@@ -194,8 +194,6 @@ typedef struct {
char *desc; /* Possible description of this VC */
} icxViewCond;
-#define XICC_DEFAULT_GLARE 5 /* Default glare in % */
-
/* Method of black point adaptation */
typedef enum {
gmm_BPadpt = 0, /* Adapt source black point to destination */
@@ -224,7 +222,6 @@ typedef struct {
double gamcknf; /* Gamut compression knee factor, 0.0 - 1.0 */
double gamxknf; /* Gamut expansion knee factor, 0.0 - 1.0 */
double gampwf; /* Gamut Perceptual Map weighting factor, 0.0 - 1.0 */
- double gamlpwf; /* Gamut Lightness preserving perceptual Map whtg. factor, 0.0 - 1.0 */
double gamswf; /* Gamut Saturation Map weighting factor, 0.0 - 1.0 */
double satenh; /* Saturation enhancement value, 0.0 - Inf */
char *as; /* Alias string (option name) */
diff --git a/xicc/xicclu.c b/xicc/xicclu.c
index f8fb9d6..0ca00aa 100644
--- a/xicc/xicclu.c
+++ b/xicc/xicclu.c
@@ -116,7 +116,7 @@ void usage(char *diag) {
fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
fprintf(stderr," l:imagewhite Image white in cd.m^2 if surround = auto (default 250)\n");
fprintf(stderr," f:flare Flare light %% of image luminance (default 0)\n");
- fprintf(stderr," g:glare Flare light %% of ambient (default %d)\n",XICC_DEFAULT_GLARE);
+ fprintf(stderr," g:glare Flare light %% of ambient (default 1)\n");
fprintf(stderr," g:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
fprintf(stderr," g:x:y Flare color as x, y\n");
fprintf(stderr,"\n");
diff --git a/yajl/afiles b/yajl/afiles
index 00a884b..9292ab8 100644
--- a/yajl/afiles
+++ b/yajl/afiles
@@ -25,6 +25,8 @@ yajl_parse.h
yajl_parser.c
yajl_parser.h
yajl_test.c
+yajl_test.exe
+yajl_test.obj
yajl_tree.c
yajl_tree.h
yajl_version.c