diff --git a/CHANGES.md b/CHANGES.md index 2b87ecce..e46a3693 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +V1.10 Under construction + +* Addition of JSON output for orbtop +* povray splash screen generator + 9th September 2019 (Version 1.00) * Change to BSD from GPL License diff --git a/Inc/bfd_wrapper.h b/Inc/bfd_wrapper.h index 071956b2..ca5bca61 100644 --- a/Inc/bfd_wrapper.h +++ b/Inc/bfd_wrapper.h @@ -28,14 +28,14 @@ * SUCH DAMAGE. */ - /* avoid issues with libbfd expecting to have - * an automake config.h - * - * see: - * https://sourceware.org/bugzilla/show_bug.cgi?id=14243 - * https://github.com/mlpack/mlpack/pull/575/commits/eedd99da548a92a05788a69fae05fb5024f079c0 - * https://github.com/Grive/grive/issues/204 - */ +/* avoid issues with libbfd expecting to have +* an automake config.h +* +* see: +* https://sourceware.org/bugzilla/show_bug.cgi?id=14243 +* https://github.com/mlpack/mlpack/pull/575/commits/eedd99da548a92a05788a69fae05fb5024f079c0 +* https://github.com/Grive/grive/issues/204 +*/ #ifndef PACKAGE # define PACKAGE diff --git a/Inc/external/cJSON.h b/Inc/external/cJSON.h new file mode 100644 index 00000000..c514141b --- /dev/null +++ b/Inc/external/cJSON.h @@ -0,0 +1,287 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. + + THE SOFTWARE 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 THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 12 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *( CJSON_CDECL *malloc_fn )( size_t sz ); + void ( CJSON_CDECL *free_fn )( void *ptr ); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC( const char * ) cJSON_Version( void ); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC( void ) cJSON_InitHooks( cJSON_Hooks *hooks ); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC( cJSON * ) cJSON_Parse( const char *value ); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC( cJSON * ) cJSON_ParseWithOpts( const char *value, const char **return_parse_end, cJSON_bool require_null_terminated ); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC( char * ) cJSON_Print( const cJSON *item ); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC( char * ) cJSON_PrintUnformatted( const cJSON *item ); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC( char * ) cJSON_PrintBuffered( const cJSON *item, int prebuffer, cJSON_bool fmt ); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC( cJSON_bool ) cJSON_PrintPreallocated( cJSON *item, char *buffer, const int length, const cJSON_bool format ); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC( void ) cJSON_Delete( cJSON *item ); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC( int ) cJSON_GetArraySize( const cJSON *array ); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC( cJSON * ) cJSON_GetArrayItem( const cJSON *array, int index ); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC( cJSON * ) cJSON_GetObjectItem( const cJSON *const object, const char *const string ); +CJSON_PUBLIC( cJSON * ) cJSON_GetObjectItemCaseSensitive( const cJSON *const object, const char *const string ); +CJSON_PUBLIC( cJSON_bool ) cJSON_HasObjectItem( const cJSON *object, const char *string ); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC( const char * ) cJSON_GetErrorPtr( void ); + +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC( char * ) cJSON_GetStringValue( cJSON *item ); + +/* These functions check the type of an item */ +CJSON_PUBLIC( cJSON_bool ) cJSON_IsInvalid( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsFalse( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsTrue( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsBool( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsNull( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsNumber( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsString( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsArray( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsObject( const cJSON *const item ); +CJSON_PUBLIC( cJSON_bool ) cJSON_IsRaw( const cJSON *const item ); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC( cJSON * ) cJSON_CreateNull( void ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateTrue( void ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateFalse( void ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateBool( cJSON_bool boolean ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateNumber( double num ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateString( const char *string ); +/* raw json */ +CJSON_PUBLIC( cJSON * ) cJSON_CreateRaw( const char *raw ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateArray( void ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateObject( void ); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC( cJSON * ) cJSON_CreateStringReference( const char *string ); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC( cJSON * ) cJSON_CreateObjectReference( const cJSON *child ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateArrayReference( const cJSON *child ); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC( cJSON * ) cJSON_CreateIntArray( const int *numbers, int count ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateFloatArray( const float *numbers, int count ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateDoubleArray( const double *numbers, int count ); +CJSON_PUBLIC( cJSON * ) cJSON_CreateStringArray( const char **strings, int count ); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC( void ) cJSON_AddItemToArray( cJSON *array, cJSON *item ); +CJSON_PUBLIC( void ) cJSON_AddItemToObject( cJSON *object, const char *string, cJSON *item ); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC( void ) cJSON_AddItemToObjectCS( cJSON *object, const char *string, cJSON *item ); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC( void ) cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item ); +CJSON_PUBLIC( void ) cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item ); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemViaPointer( cJSON *parent, cJSON *const item ); +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemFromArray( cJSON *array, int which ); +CJSON_PUBLIC( void ) cJSON_DeleteItemFromArray( cJSON *array, int which ); +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemFromObject( cJSON *object, const char *string ); +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemFromObjectCaseSensitive( cJSON *object, const char *string ); +CJSON_PUBLIC( void ) cJSON_DeleteItemFromObject( cJSON *object, const char *string ); +CJSON_PUBLIC( void ) cJSON_DeleteItemFromObjectCaseSensitive( cJSON *object, const char *string ); + +/* Update array items. */ +CJSON_PUBLIC( void ) cJSON_InsertItemInArray( cJSON *array, int which, cJSON *newitem ); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC( cJSON_bool ) cJSON_ReplaceItemViaPointer( cJSON *const parent, cJSON *const item, cJSON *replacement ); +CJSON_PUBLIC( void ) cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem ); +CJSON_PUBLIC( void ) cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem ); +CJSON_PUBLIC( void ) cJSON_ReplaceItemInObjectCaseSensitive( cJSON *object, const char *string, cJSON *newitem ); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC( cJSON * ) cJSON_Duplicate( const cJSON *item, cJSON_bool recurse ); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC( cJSON_bool ) cJSON_Compare( const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive ); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ +CJSON_PUBLIC( void ) cJSON_Minify( char *json ); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC( cJSON * ) cJSON_AddNullToObject( cJSON *const object, const char *const name ); +CJSON_PUBLIC( cJSON * ) cJSON_AddTrueToObject( cJSON *const object, const char *const name ); +CJSON_PUBLIC( cJSON * ) cJSON_AddFalseToObject( cJSON *const object, const char *const name ); +CJSON_PUBLIC( cJSON * ) cJSON_AddBoolToObject( cJSON *const object, const char *const name, const cJSON_bool boolean ); +CJSON_PUBLIC( cJSON * ) cJSON_AddNumberToObject( cJSON *const object, const char *const name, const double number ); +CJSON_PUBLIC( cJSON * ) cJSON_AddStringToObject( cJSON *const object, const char *const name, const char *const string ); +CJSON_PUBLIC( cJSON * ) cJSON_AddRawToObject( cJSON *const object, const char *const name, const char *const raw ); +CJSON_PUBLIC( cJSON * ) cJSON_AddObjectToObject( cJSON *const object, const char *const name ); +CJSON_PUBLIC( cJSON * ) cJSON_AddArrayToObject( cJSON *const object, const char *const name ); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC( double ) cJSON_SetNumberHelper( cJSON *object, double number ); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC( void * ) cJSON_malloc( size_t size ); +CJSON_PUBLIC( void ) cJSON_free( void *object ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Inc/ftdispi.h b/Inc/external/ftdispi.h similarity index 100% rename from Inc/ftdispi.h rename to Inc/external/ftdispi.h diff --git a/Inc/uthash.h b/Inc/external/uthash.h similarity index 100% rename from Inc/uthash.h rename to Inc/external/uthash.h diff --git a/Makefile b/Makefile index de2294fa..36015efb 100644 --- a/Makefile +++ b/Makefile @@ -33,32 +33,33 @@ endif # Overall system defines for compilation ifdef DEBUG GCC_DEFINE= -DDEBUG +DEBUG_OPTS = -g3 -gdwarf-2 -ggdb OPT_LEVEL = else GCC_DEFINE= +DEBUG_OPTS = OPT_LEVEL = -O2 endif +# Directories for sources +App_DIR=Src +Inc_DIR=Inc +EXT=$(App_DIR)/external +EXTINC=$(Inc_DIR)/external +INCLUDE_PATHS = -I$(Inc_DIR) -I$(EXTINC) -I$(OLOC) + GCC_DEFINE+= -std=gnu99 CFILES = SFILES = OLOC = ofiles -INCLUDE_PATHS = -I/usr/local/include/libusb-1.0 -I/usr/include/libiberty +INCLUDE_PATHS += -I/usr/local/include/libusb-1.0 -I/usr/include/libiberty LDLIBS = -L/usr/local/lib -lusb-1.0 -lelf -lbfd -lz -ldl -liberty #ifdef LINUX LDLIBS += -lpthread #endif -ifeq ($(WITH_FPGA),1) -CFLAGS+=-DINCLUDE_FPGA_SUPPORT -LDLIBS += -lftdi1 -FPGA_CFILES=$(App_DIR)/ftdispi.c -endif - -DEBUG_OPTS = -g3 -gdwarf-2 -ggdb - ########################################################################## # Generic multi-project files ########################################################################## @@ -69,14 +70,21 @@ DEBUG_OPTS = -g3 -gdwarf-2 -ggdb # Main Files # ========== -App_DIR=Src -INCLUDE_PATHS += -IInc -I$(OLOC) ORBUCULUM_CFILES = $(App_DIR)/$(ORBUCULUM).c $(App_DIR)/filewriter.c $(FPGA_CFILES) ORBCAT_CFILES = $(App_DIR)/$(ORBCAT).c -ORBTOP_CFILES = $(App_DIR)/$(ORBTOP).c $(App_DIR)/symbols.c +ORBTOP_CFILES = $(App_DIR)/$(ORBTOP).c $(App_DIR)/symbols.c $(EXT)/cJSON.c ORBDUMP_CFILES = $(App_DIR)/$(ORBDUMP).c -ORBSTAT_CFILES = $(App_DIR)/$(ORBSTAT).c $(App_DIR)/symbols.c +ORBSTAT_CFILES = $(App_DIR)/$(ORBSTAT).c $(App_DIR)/symbols.c + +# FPGA Files +# ========== + +ifeq ($(WITH_FPGA),1) +CFLAGS+=-DINCLUDE_FPGA_SUPPORT +LDLIBS += -lftdi1 +FPGA_CFILES=$(EXT)/ftdispi.c +endif ########################################################################## # GNU GCC compiler prefix and location diff --git a/README.md b/README.md index 0de4990b..7974607c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ * Latest Changes: -Upissue to V1.00. The number doesn't really mean anything, but it does represent a change from GPL to BSD licence. See the CONTRIBUTORS file for details on all authors agreement to this change. +This is V1.10 in progress. + +* JSON output has been added into orbtop. The CHANGES file now tells you what's been done when. @@ -139,8 +141,8 @@ parameters for each macro are available via the help system too. In general, you will configure orbuculum via your local `.gdbinit` file. Several example files are also in the Support directory. Generically, it looks like this; - source config/gdbtrace.init <---- Source the trace specific stuff - target extended-remote /dev/ttyACM1 <- + source Support/gdbtrace.init <---- Source the trace specific stuff + target extended-remote /dev/ttyACM0 <- monitor swdp_scan <- file ofiles/firmware.elf <- attach 1 <---- Connect to the target @@ -148,10 +150,9 @@ also in the Support directory. Generically, it looks like this; set print pretty <- load <---- Load the program - start <---- and get to main - enableSTM32SWD <*--- turn on SWO output pin on CPU + enableSTM32SWO <*--- turn on SWO output pin on CPU # ---------- EITHER, IF USING A BLUEPILL------------------------- monitor traceswo 2250000 <*--- wakeup tracing on the probe @@ -163,8 +164,8 @@ also in the Support directory. Generically, it looks like this; # ----------END OF ALTERNATIVE----------------------------------- dwtSamplePC 1 <- - dwtSyncTAP 3 <- - dwtPostTAP 1 <- + dwtSyncTap 3 <- + dwtPostTap 1 <- dwtPostInit 1 <- dwtPostReset 15 <- dwtCycEna 1 <---- Configure Data Watch/Trace @@ -404,6 +405,8 @@ Command line options for orbtop are; `-I [Interval]`: Set integration and display interval in milliseconds (defaults to 1000 mS) + `-j`: Output in JSON, rather than human-readable, form + `-l`: Aggregate per line rather than per function `-n`: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs) diff --git a/Src/external/cJSON.c b/Src/external/cJSON.c new file mode 100644 index 00000000..421aac8a --- /dev/null +++ b/Src/external/cJSON.c @@ -0,0 +1,3189 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. + + THE SOFTWARE 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 THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) + #define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ + #pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) + #pragma warning (push) + /* disable warning about single line comments in system headers */ + #pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES + #include +#endif + +#if defined(_MSC_VER) + #pragma warning (pop) +#endif +#ifdef __GNUC__ + #pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true + #undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false + #undef false +#endif +#define false ((cJSON_bool)0) + +typedef struct +{ + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC( const char * ) cJSON_GetErrorPtr( void ) +{ + return ( const char * ) ( global_error.json + global_error.position ); +} + +CJSON_PUBLIC( char * ) cJSON_GetStringValue( cJSON *item ) +{ + if ( !cJSON_IsString( item ) ) + { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 12) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC( const char * ) cJSON_Version( void ) +{ + static char version[15]; + sprintf( version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH ); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp( const unsigned char *string1, const unsigned char *string2 ) +{ + if ( ( string1 == NULL ) || ( string2 == NULL ) ) + { + return 1; + } + + if ( string1 == string2 ) + { + return 0; + } + + for ( ; tolower( *string1 ) == tolower( *string2 ); ( void )string1++, string2++ ) + { + if ( *string1 == '\0' ) + { + return 0; + } + } + + return tolower( *string1 ) - tolower( *string2 ); +} + +typedef struct internal_hooks +{ + void *( CJSON_CDECL *allocate )( size_t size ); + void ( CJSON_CDECL *deallocate )( void *pointer ); + void *( CJSON_CDECL *reallocate )( void *pointer, size_t size ); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void *CJSON_CDECL internal_malloc( size_t size ) +{ + return malloc( size ); +} +static void CJSON_CDECL internal_free( void *pointer ) +{ + free( pointer ); +} +static void *CJSON_CDECL internal_realloc( void *pointer, size_t size ) +{ + return realloc( pointer, size ); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char *cJSON_strdup( const unsigned char *string, const internal_hooks *const hooks ) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if ( string == NULL ) + { + return NULL; + } + + length = strlen( ( const char * )string ) + sizeof( "" ); + copy = ( unsigned char * )hooks->allocate( length ); + + if ( copy == NULL ) + { + return NULL; + } + + memcpy( copy, string, length ); + + return copy; +} + +CJSON_PUBLIC( void ) cJSON_InitHooks( cJSON_Hooks *hooks ) +{ + if ( hooks == NULL ) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + + if ( hooks->malloc_fn != NULL ) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + + if ( hooks->free_fn != NULL ) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + + if ( ( global_hooks.allocate == malloc ) && ( global_hooks.deallocate == free ) ) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item( const internal_hooks *const hooks ) +{ + cJSON *node = ( cJSON * )hooks->allocate( sizeof( cJSON ) ); + + if ( node ) + { + memset( node, '\0', sizeof( cJSON ) ); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC( void ) cJSON_Delete( cJSON *item ) +{ + cJSON *next = NULL; + + while ( item != NULL ) + { + next = item->next; + + if ( !( item->type & cJSON_IsReference ) && ( item->child != NULL ) ) + { + cJSON_Delete( item->child ); + } + + if ( !( item->type & cJSON_IsReference ) && ( item->valuestring != NULL ) ) + { + global_hooks.deallocate( item->valuestring ); + } + + if ( !( item->type & cJSON_StringIsConst ) && ( item->string != NULL ) ) + { + global_hooks.deallocate( item->string ); + } + + global_hooks.deallocate( item ); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point( void ) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return ( unsigned char ) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number( cJSON *const item, parse_buffer *const input_buffer ) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ( ( input_buffer == NULL ) || ( input_buffer->content == NULL ) ) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for ( i = 0; ( i < ( sizeof( number_c_string ) - 1 ) ) && can_access_at_index( input_buffer, i ); i++ ) + { + switch ( buffer_at_offset( input_buffer )[i] ) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset( input_buffer )[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } + +loop_end: + number_c_string[i] = '\0'; + + number = strtod( ( const char * )number_c_string, ( char ** )&after_end ); + + if ( number_c_string == after_end ) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if ( number >= INT_MAX ) + { + item->valueint = INT_MAX; + } + else if ( number <= ( double )INT_MIN ) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = ( int )number; + } + + item->type = cJSON_Number; + + input_buffer->offset += ( size_t )( after_end - number_c_string ); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC( double ) cJSON_SetNumberHelper( cJSON *object, double number ) +{ + if ( number >= INT_MAX ) + { + object->valueint = INT_MAX; + } + else if ( number <= ( double )INT_MIN ) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = ( int )number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char *ensure( printbuffer *const p, size_t needed ) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ( ( p == NULL ) || ( p->buffer == NULL ) ) + { + return NULL; + } + + if ( ( p->length > 0 ) && ( p->offset >= p->length ) ) + { + /* make sure that offset is valid */ + return NULL; + } + + if ( needed > INT_MAX ) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + + if ( needed <= p->length ) + { + return p->buffer + p->offset; + } + + if ( p->noalloc ) + { + return NULL; + } + + /* calculate new buffer size */ + if ( needed > ( INT_MAX / 2 ) ) + { + /* overflow of int, use INT_MAX if possible */ + if ( needed <= INT_MAX ) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if ( p->hooks.reallocate != NULL ) + { + /* reallocate with realloc if available */ + newbuffer = ( unsigned char * )p->hooks.reallocate( p->buffer, newsize ); + + if ( newbuffer == NULL ) + { + p->hooks.deallocate( p->buffer ); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = ( unsigned char * )p->hooks.allocate( newsize ); + + if ( !newbuffer ) + { + p->hooks.deallocate( p->buffer ); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + + if ( newbuffer ) + { + memcpy( newbuffer, p->buffer, p->offset + 1 ); + } + + p->hooks.deallocate( p->buffer ); + } + + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset( printbuffer *const buffer ) +{ + const unsigned char *buffer_pointer = NULL; + + if ( ( buffer == NULL ) || ( buffer->buffer == NULL ) ) + { + return; + } + + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen( ( const char * )buffer_pointer ); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number( const cJSON *const item, printbuffer *const output_buffer ) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if ( output_buffer == NULL ) + { + return false; + } + + /* This checks for NaN and Infinity */ + if ( ( d * 0 ) != 0 ) + { + length = sprintf( ( char * )number_buffer, "null" ); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf( ( char * )number_buffer, "%1.15g", d ); + + /* Check whether the original double can be recovered */ + if ( ( sscanf( ( char * )number_buffer, "%lg", &test ) != 1 ) || ( ( double )test != d ) ) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf( ( char * )number_buffer, "%1.17g", d ); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ( ( length < 0 ) || ( length > ( int )( sizeof( number_buffer ) - 1 ) ) ) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure( output_buffer, ( size_t )length + sizeof( "" ) ); + + if ( output_pointer == NULL ) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for ( i = 0; i < ( ( size_t )length ); i++ ) + { + if ( number_buffer[i] == decimal_point ) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + + output_pointer[i] = '\0'; + + output_buffer->offset += ( size_t )length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4( const unsigned char *const input ) +{ + unsigned int h = 0; + size_t i = 0; + + for ( i = 0; i < 4; i++ ) + { + /* parse digit */ + if ( ( input[i] >= '0' ) && ( input[i] <= '9' ) ) + { + h += ( unsigned int ) input[i] - '0'; + } + else if ( ( input[i] >= 'A' ) && ( input[i] <= 'F' ) ) + { + h += ( unsigned int ) 10 + input[i] - 'A'; + } + else if ( ( input[i] >= 'a' ) && ( input[i] <= 'f' ) ) + { + h += ( unsigned int ) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if ( i < 3 ) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8( const unsigned char *const input_pointer, const unsigned char *const input_end, unsigned char **output_pointer ) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ( ( input_end - first_sequence ) < 6 ) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4( first_sequence + 2 ); + + /* check that the code is valid */ + if ( ( ( first_code >= 0xDC00 ) && ( first_code <= 0xDFFF ) ) ) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ( ( first_code >= 0xD800 ) && ( first_code <= 0xDBFF ) ) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ( ( input_end - second_sequence ) < 6 ) + { + /* input ends unexpectedly */ + goto fail; + } + + if ( ( second_sequence[0] != '\\' ) || ( second_sequence[1] != 'u' ) ) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4( second_sequence + 2 ); + + /* check that the code is valid */ + if ( ( second_code < 0xDC00 ) || ( second_code > 0xDFFF ) ) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + ( ( ( first_code & 0x3FF ) << 10 ) | ( second_code & 0x3FF ) ); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if ( codepoint < 0x80 ) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if ( codepoint < 0x800 ) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if ( codepoint < 0x10000 ) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if ( codepoint <= 0x10FFFF ) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for ( utf8_position = ( unsigned char )( utf8_length - 1 ); utf8_position > 0; utf8_position-- ) + { + /* 10xxxxxx */ + ( *output_pointer )[utf8_position] = ( unsigned char )( ( codepoint | 0x80 ) & 0xBF ); + codepoint >>= 6; + } + + /* encode first byte */ + if ( utf8_length > 1 ) + { + ( *output_pointer )[0] = ( unsigned char )( ( codepoint | first_byte_mark ) & 0xFF ); + } + else + { + ( *output_pointer )[0] = ( unsigned char )( codepoint & 0x7F ); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string( cJSON *const item, parse_buffer *const input_buffer ) +{ + const unsigned char *input_pointer = buffer_at_offset( input_buffer ) + 1; + const unsigned char *input_end = buffer_at_offset( input_buffer ) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if ( buffer_at_offset( input_buffer )[0] != '\"' ) + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + + while ( ( ( size_t )( input_end - input_buffer->content ) < input_buffer->length ) && ( *input_end != '\"' ) ) + { + /* is escape sequence */ + if ( input_end[0] == '\\' ) + { + if ( ( size_t )( input_end + 1 - input_buffer->content ) >= input_buffer->length ) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + + skipped_bytes++; + input_end++; + } + + input_end++; + } + + if ( ( ( size_t )( input_end - input_buffer->content ) >= input_buffer->length ) || ( *input_end != '\"' ) ) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = ( size_t ) ( input_end - buffer_at_offset( input_buffer ) ) - skipped_bytes; + output = ( unsigned char * )input_buffer->hooks.allocate( allocation_length + sizeof( "" ) ); + + if ( output == NULL ) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + + /* loop through the string literal */ + while ( input_pointer < input_end ) + { + if ( *input_pointer != '\\' ) + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + + if ( ( input_end - input_pointer ) < 1 ) + { + goto fail; + } + + switch ( input_pointer[1] ) + { + case 'b': + *output_pointer++ = '\b'; + break; + + case 'f': + *output_pointer++ = '\f'; + break; + + case 'n': + *output_pointer++ = '\n'; + break; + + case 'r': + *output_pointer++ = '\r'; + break; + + case 't': + *output_pointer++ = '\t'; + break; + + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8( input_pointer, input_end, &output_pointer ); + + if ( sequence_length == 0 ) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + + break; + + default: + goto fail; + } + + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = ( char * )output; + + input_buffer->offset = ( size_t ) ( input_end - input_buffer->content ); + input_buffer->offset++; + + return true; + +fail: + + if ( output != NULL ) + { + input_buffer->hooks.deallocate( output ); + } + + if ( input_pointer != NULL ) + { + input_buffer->offset = ( size_t )( input_pointer - input_buffer->content ); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr( const unsigned char *const input, printbuffer *const output_buffer ) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if ( output_buffer == NULL ) + { + return false; + } + + /* empty string */ + if ( input == NULL ) + { + output = ensure( output_buffer, sizeof( "\"\"" ) ); + + if ( output == NULL ) + { + return false; + } + + strcpy( ( char * )output, "\"\"" ); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for ( input_pointer = input; *input_pointer; input_pointer++ ) + { + switch ( *input_pointer ) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + + default: + if ( *input_pointer < 32 ) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + + break; + } + } + + output_length = ( size_t )( input_pointer - input ) + escape_characters; + + output = ensure( output_buffer, output_length + sizeof( "\"\"" ) ); + + if ( output == NULL ) + { + return false; + } + + /* no characters have to be escaped */ + if ( escape_characters == 0 ) + { + output[0] = '\"'; + memcpy( output + 1, input, output_length ); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + + /* copy the string */ + for ( input_pointer = input; *input_pointer != '\0'; ( void )input_pointer++, output_pointer++ ) + { + if ( ( *input_pointer > 31 ) && ( *input_pointer != '\"' ) && ( *input_pointer != '\\' ) ) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + + switch ( *input_pointer ) + { + case '\\': + *output_pointer = '\\'; + break; + + case '\"': + *output_pointer = '\"'; + break; + + case '\b': + *output_pointer = 'b'; + break; + + case '\f': + *output_pointer = 'f'; + break; + + case '\n': + *output_pointer = 'n'; + break; + + case '\r': + *output_pointer = 'r'; + break; + + case '\t': + *output_pointer = 't'; + break; + + default: + /* escape and print as unicode codepoint */ + sprintf( ( char * )output_pointer, "u%04x", *input_pointer ); + output_pointer += 4; + break; + } + } + } + + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string( const cJSON *const item, printbuffer *const p ) +{ + return print_string_ptr( ( unsigned char * )item->valuestring, p ); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value( cJSON *const item, parse_buffer *const input_buffer ); +static cJSON_bool print_value( const cJSON *const item, printbuffer *const output_buffer ); +static cJSON_bool parse_array( cJSON *const item, parse_buffer *const input_buffer ); +static cJSON_bool print_array( const cJSON *const item, printbuffer *const output_buffer ); +static cJSON_bool parse_object( cJSON *const item, parse_buffer *const input_buffer ); +static cJSON_bool print_object( const cJSON *const item, printbuffer *const output_buffer ); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace( parse_buffer *const buffer ) +{ + if ( ( buffer == NULL ) || ( buffer->content == NULL ) ) + { + return NULL; + } + + while ( can_access_at_index( buffer, 0 ) && ( buffer_at_offset( buffer )[0] <= 32 ) ) + { + buffer->offset++; + } + + if ( buffer->offset == buffer->length ) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom( parse_buffer *const buffer ) +{ + if ( ( buffer == NULL ) || ( buffer->content == NULL ) || ( buffer->offset != 0 ) ) + { + return NULL; + } + + if ( can_access_at_index( buffer, 4 ) && ( strncmp( ( const char * )buffer_at_offset( buffer ), "\xEF\xBB\xBF", 3 ) == 0 ) ) + { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC( cJSON * ) cJSON_ParseWithOpts( const char *value, const char **return_parse_end, cJSON_bool require_null_terminated ) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if ( value == NULL ) + { + goto fail; + } + + buffer.content = ( const unsigned char * )value; + buffer.length = strlen( ( const char * )value ) + sizeof( "" ); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item( &global_hooks ); + + if ( item == NULL ) /* memory fail */ + { + goto fail; + } + + if ( !parse_value( item, buffer_skip_whitespace( skip_utf8_bom( &buffer ) ) ) ) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if ( require_null_terminated ) + { + buffer_skip_whitespace( &buffer ); + + if ( ( buffer.offset >= buffer.length ) || buffer_at_offset( &buffer )[0] != '\0' ) + { + goto fail; + } + } + + if ( return_parse_end ) + { + *return_parse_end = ( const char * )buffer_at_offset( &buffer ); + } + + return item; + +fail: + + if ( item != NULL ) + { + cJSON_Delete( item ); + } + + if ( value != NULL ) + { + error local_error; + local_error.json = ( const unsigned char * )value; + local_error.position = 0; + + if ( buffer.offset < buffer.length ) + { + local_error.position = buffer.offset; + } + else if ( buffer.length > 0 ) + { + local_error.position = buffer.length - 1; + } + + if ( return_parse_end != NULL ) + { + *return_parse_end = ( const char * )local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC( cJSON * ) cJSON_Parse( const char *value ) +{ + return cJSON_ParseWithOpts( value, 0, 0 ); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print( const cJSON *const item, cJSON_bool format, const internal_hooks *const hooks ) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset( buffer, 0, sizeof( buffer ) ); + + /* create buffer */ + buffer->buffer = ( unsigned char * ) hooks->allocate( default_buffer_size ); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + + if ( buffer->buffer == NULL ) + { + goto fail; + } + + /* print the value */ + if ( !print_value( item, buffer ) ) + { + goto fail; + } + + update_offset( buffer ); + + /* check if reallocate is available */ + if ( hooks->reallocate != NULL ) + { + printed = ( unsigned char * ) hooks->reallocate( buffer->buffer, buffer->offset + 1 ); + + if ( printed == NULL ) + { + goto fail; + } + + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = ( unsigned char * ) hooks->allocate( buffer->offset + 1 ); + + if ( printed == NULL ) + { + goto fail; + } + + memcpy( printed, buffer->buffer, cjson_min( buffer->length, buffer->offset + 1 ) ); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate( buffer->buffer ); + } + + return printed; + +fail: + + if ( buffer->buffer != NULL ) + { + hooks->deallocate( buffer->buffer ); + } + + if ( printed != NULL ) + { + hooks->deallocate( printed ); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC( char * ) cJSON_Print( const cJSON *item ) +{ + return ( char * )print( item, true, &global_hooks ); +} + +CJSON_PUBLIC( char * ) cJSON_PrintUnformatted( const cJSON *item ) +{ + return ( char * )print( item, false, &global_hooks ); +} + +CJSON_PUBLIC( char * ) cJSON_PrintBuffered( const cJSON *item, int prebuffer, cJSON_bool fmt ) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ( prebuffer < 0 ) + { + return NULL; + } + + p.buffer = ( unsigned char * )global_hooks.allocate( ( size_t )prebuffer ); + + if ( !p.buffer ) + { + return NULL; + } + + p.length = ( size_t )prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if ( !print_value( item, &p ) ) + { + global_hooks.deallocate( p.buffer ); + return NULL; + } + + return ( char * )p.buffer; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_PrintPreallocated( cJSON *item, char *buf, const int len, const cJSON_bool fmt ) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ( ( len < 0 ) || ( buf == NULL ) ) + { + return false; + } + + p.buffer = ( unsigned char * )buf; + p.length = ( size_t )len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value( item, &p ); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value( cJSON *const item, parse_buffer *const input_buffer ) +{ + if ( ( input_buffer == NULL ) || ( input_buffer->content == NULL ) ) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if ( can_read( input_buffer, 4 ) && ( strncmp( ( const char * )buffer_at_offset( input_buffer ), "null", 4 ) == 0 ) ) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + + /* false */ + if ( can_read( input_buffer, 5 ) && ( strncmp( ( const char * )buffer_at_offset( input_buffer ), "false", 5 ) == 0 ) ) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + + /* true */ + if ( can_read( input_buffer, 4 ) && ( strncmp( ( const char * )buffer_at_offset( input_buffer ), "true", 4 ) == 0 ) ) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + + /* string */ + if ( can_access_at_index( input_buffer, 0 ) && ( buffer_at_offset( input_buffer )[0] == '\"' ) ) + { + return parse_string( item, input_buffer ); + } + + /* number */ + if ( can_access_at_index( input_buffer, 0 ) && ( ( buffer_at_offset( input_buffer )[0] == '-' ) || ( ( buffer_at_offset( input_buffer )[0] >= '0' ) + && ( buffer_at_offset( input_buffer )[0] <= '9' ) ) ) ) + { + return parse_number( item, input_buffer ); + } + + /* array */ + if ( can_access_at_index( input_buffer, 0 ) && ( buffer_at_offset( input_buffer )[0] == '[' ) ) + { + return parse_array( item, input_buffer ); + } + + /* object */ + if ( can_access_at_index( input_buffer, 0 ) && ( buffer_at_offset( input_buffer )[0] == '{' ) ) + { + return parse_object( item, input_buffer ); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value( const cJSON *const item, printbuffer *const output_buffer ) +{ + unsigned char *output = NULL; + + if ( ( item == NULL ) || ( output_buffer == NULL ) ) + { + return false; + } + + switch ( ( item->type ) & 0xFF ) + { + case cJSON_NULL: + output = ensure( output_buffer, 5 ); + + if ( output == NULL ) + { + return false; + } + + strcpy( ( char * )output, "null" ); + return true; + + case cJSON_False: + output = ensure( output_buffer, 6 ); + + if ( output == NULL ) + { + return false; + } + + strcpy( ( char * )output, "false" ); + return true; + + case cJSON_True: + output = ensure( output_buffer, 5 ); + + if ( output == NULL ) + { + return false; + } + + strcpy( ( char * )output, "true" ); + return true; + + case cJSON_Number: + return print_number( item, output_buffer ); + + case cJSON_Raw: + { + size_t raw_length = 0; + + if ( item->valuestring == NULL ) + { + return false; + } + + raw_length = strlen( item->valuestring ) + sizeof( "" ); + output = ensure( output_buffer, raw_length ); + + if ( output == NULL ) + { + return false; + } + + memcpy( output, item->valuestring, raw_length ); + return true; + } + + case cJSON_String: + return print_string( item, output_buffer ); + + case cJSON_Array: + return print_array( item, output_buffer ); + + case cJSON_Object: + return print_object( item, output_buffer ); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array( cJSON *const item, parse_buffer *const input_buffer ) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if ( input_buffer->depth >= CJSON_NESTING_LIMIT ) + { + return false; /* to deeply nested */ + } + + input_buffer->depth++; + + if ( buffer_at_offset( input_buffer )[0] != '[' ) + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace( input_buffer ); + + if ( can_access_at_index( input_buffer, 0 ) && ( buffer_at_offset( input_buffer )[0] == ']' ) ) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if ( cannot_access_at_index( input_buffer, 0 ) ) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item( &( input_buffer->hooks ) ); + + if ( new_item == NULL ) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if ( head == NULL ) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace( input_buffer ); + + if ( !parse_value( current_item, input_buffer ) ) + { + goto fail; /* failed to parse value */ + } + + buffer_skip_whitespace( input_buffer ); + } + while ( can_access_at_index( input_buffer, 0 ) && ( buffer_at_offset( input_buffer )[0] == ',' ) ); + + if ( cannot_access_at_index( input_buffer, 0 ) || buffer_at_offset( input_buffer )[0] != ']' ) + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + + if ( head != NULL ) + { + cJSON_Delete( head ); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array( const cJSON *const item, printbuffer *const output_buffer ) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if ( output_buffer == NULL ) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure( output_buffer, 1 ); + + if ( output_pointer == NULL ) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while ( current_element != NULL ) + { + if ( !print_value( current_element, output_buffer ) ) + { + return false; + } + + update_offset( output_buffer ); + + if ( current_element->next ) + { + length = ( size_t ) ( output_buffer->format ? 2 : 1 ); + output_pointer = ensure( output_buffer, length + 1 ); + + if ( output_pointer == NULL ) + { + return false; + } + + *output_pointer++ = ','; + + if ( output_buffer->format ) + { + *output_pointer++ = ' '; + } + + *output_pointer = '\0'; + output_buffer->offset += length; + } + + current_element = current_element->next; + } + + output_pointer = ensure( output_buffer, 2 ); + + if ( output_pointer == NULL ) + { + return false; + } + + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object( cJSON *const item, parse_buffer *const input_buffer ) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if ( input_buffer->depth >= CJSON_NESTING_LIMIT ) + { + return false; /* to deeply nested */ + } + + input_buffer->depth++; + + if ( cannot_access_at_index( input_buffer, 0 ) || ( buffer_at_offset( input_buffer )[0] != '{' ) ) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace( input_buffer ); + + if ( can_access_at_index( input_buffer, 0 ) && ( buffer_at_offset( input_buffer )[0] == '}' ) ) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if ( cannot_access_at_index( input_buffer, 0 ) ) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item( &( input_buffer->hooks ) ); + + if ( new_item == NULL ) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if ( head == NULL ) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace( input_buffer ); + + if ( !parse_string( current_item, input_buffer ) ) + { + goto fail; /* failed to parse name */ + } + + buffer_skip_whitespace( input_buffer ); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if ( cannot_access_at_index( input_buffer, 0 ) || ( buffer_at_offset( input_buffer )[0] != ':' ) ) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace( input_buffer ); + + if ( !parse_value( current_item, input_buffer ) ) + { + goto fail; /* failed to parse value */ + } + + buffer_skip_whitespace( input_buffer ); + } + while ( can_access_at_index( input_buffer, 0 ) && ( buffer_at_offset( input_buffer )[0] == ',' ) ); + + if ( cannot_access_at_index( input_buffer, 0 ) || ( buffer_at_offset( input_buffer )[0] != '}' ) ) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + + if ( head != NULL ) + { + cJSON_Delete( head ); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object( const cJSON *const item, printbuffer *const output_buffer ) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if ( output_buffer == NULL ) + { + return false; + } + + /* Compose the output: */ + length = ( size_t ) ( output_buffer->format ? 2 : 1 ); /* fmt: {\n */ + output_pointer = ensure( output_buffer, length + 1 ); + + if ( output_pointer == NULL ) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + + if ( output_buffer->format ) + { + *output_pointer++ = '\n'; + } + + output_buffer->offset += length; + + while ( current_item ) + { + if ( output_buffer->format ) + { + size_t i; + output_pointer = ensure( output_buffer, output_buffer->depth ); + + if ( output_pointer == NULL ) + { + return false; + } + + for ( i = 0; i < output_buffer->depth; i++ ) + { + *output_pointer++ = '\t'; + } + + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if ( !print_string_ptr( ( unsigned char * )current_item->string, output_buffer ) ) + { + return false; + } + + update_offset( output_buffer ); + + length = ( size_t ) ( output_buffer->format ? 2 : 1 ); + output_pointer = ensure( output_buffer, length ); + + if ( output_pointer == NULL ) + { + return false; + } + + *output_pointer++ = ':'; + + if ( output_buffer->format ) + { + *output_pointer++ = '\t'; + } + + output_buffer->offset += length; + + /* print value */ + if ( !print_value( current_item, output_buffer ) ) + { + return false; + } + + update_offset( output_buffer ); + + /* print comma if not last */ + length = ( ( size_t )( output_buffer->format ? 1 : 0 ) + ( size_t )( current_item->next ? 1 : 0 ) ); + output_pointer = ensure( output_buffer, length + 1 ); + + if ( output_pointer == NULL ) + { + return false; + } + + if ( current_item->next ) + { + *output_pointer++ = ','; + } + + if ( output_buffer->format ) + { + *output_pointer++ = '\n'; + } + + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure( output_buffer, output_buffer->format ? ( output_buffer->depth + 1 ) : 2 ); + + if ( output_pointer == NULL ) + { + return false; + } + + if ( output_buffer->format ) + { + size_t i; + + for ( i = 0; i < ( output_buffer->depth - 1 ); i++ ) + { + *output_pointer++ = '\t'; + } + } + + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC( int ) cJSON_GetArraySize( const cJSON *array ) +{ + cJSON *child = NULL; + size_t size = 0; + + if ( array == NULL ) + { + return 0; + } + + child = array->child; + + while ( child != NULL ) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return ( int )size; +} + +static cJSON *get_array_item( const cJSON *array, size_t index ) +{ + cJSON *current_child = NULL; + + if ( array == NULL ) + { + return NULL; + } + + current_child = array->child; + + while ( ( current_child != NULL ) && ( index > 0 ) ) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC( cJSON * ) cJSON_GetArrayItem( const cJSON *array, int index ) +{ + if ( index < 0 ) + { + return NULL; + } + + return get_array_item( array, ( size_t )index ); +} + +static cJSON *get_object_item( const cJSON *const object, const char *const name, const cJSON_bool case_sensitive ) +{ + cJSON *current_element = NULL; + + if ( ( object == NULL ) || ( name == NULL ) ) + { + return NULL; + } + + current_element = object->child; + + if ( case_sensitive ) + { + while ( ( current_element != NULL ) && ( current_element->string != NULL ) && ( strcmp( name, current_element->string ) != 0 ) ) + { + current_element = current_element->next; + } + } + else + { + while ( ( current_element != NULL ) && ( case_insensitive_strcmp( ( const unsigned char * )name, ( const unsigned char * )( current_element->string ) ) != 0 ) ) + { + current_element = current_element->next; + } + } + + if ( ( current_element == NULL ) || ( current_element->string == NULL ) ) + { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC( cJSON * ) cJSON_GetObjectItem( const cJSON *const object, const char *const string ) +{ + return get_object_item( object, string, false ); +} + +CJSON_PUBLIC( cJSON * ) cJSON_GetObjectItemCaseSensitive( const cJSON *const object, const char *const string ) +{ + return get_object_item( object, string, true ); +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_HasObjectItem( const cJSON *object, const char *string ) +{ + return cJSON_GetObjectItem( object, string ) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object( cJSON *prev, cJSON *item ) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference( const cJSON *item, const internal_hooks *const hooks ) +{ + cJSON *reference = NULL; + + if ( item == NULL ) + { + return NULL; + } + + reference = cJSON_New_Item( hooks ); + + if ( reference == NULL ) + { + return NULL; + } + + memcpy( reference, item, sizeof( cJSON ) ); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array( cJSON *array, cJSON *item ) +{ + cJSON *child = NULL; + + if ( ( item == NULL ) || ( array == NULL ) ) + { + return false; + } + + child = array->child; + + if ( child == NULL ) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while ( child->next ) + { + child = child->next; + } + + suffix_object( child, item ); + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC( void ) cJSON_AddItemToArray( cJSON *array, cJSON *item ) +{ + add_item_to_array( array, item ); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ + #pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void *cast_away_const( const void *string ) +{ + return ( void * )string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object( cJSON *const object, const char *const string, cJSON *const item, const internal_hooks *const hooks, const cJSON_bool constant_key ) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ( ( object == NULL ) || ( string == NULL ) || ( item == NULL ) ) + { + return false; + } + + if ( constant_key ) + { + new_key = ( char * )cast_away_const( string ); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = ( char * )cJSON_strdup( ( const unsigned char * )string, hooks ); + + if ( new_key == NULL ) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if ( !( item->type & cJSON_StringIsConst ) && ( item->string != NULL ) ) + { + hooks->deallocate( item->string ); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array( object, item ); +} + +CJSON_PUBLIC( void ) cJSON_AddItemToObject( cJSON *object, const char *string, cJSON *item ) +{ + add_item_to_object( object, string, item, &global_hooks, false ); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC( void ) cJSON_AddItemToObjectCS( cJSON *object, const char *string, cJSON *item ) +{ + add_item_to_object( object, string, item, &global_hooks, true ); +} + +CJSON_PUBLIC( void ) cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item ) +{ + if ( array == NULL ) + { + return; + } + + add_item_to_array( array, create_reference( item, &global_hooks ) ); +} + +CJSON_PUBLIC( void ) cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item ) +{ + if ( ( object == NULL ) || ( string == NULL ) ) + { + return; + } + + add_item_to_object( object, string, create_reference( item, &global_hooks ), &global_hooks, false ); +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddNullToObject( cJSON *const object, const char *const name ) +{ + cJSON *null = cJSON_CreateNull(); + + if ( add_item_to_object( object, name, null, &global_hooks, false ) ) + { + return null; + } + + cJSON_Delete( null ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddTrueToObject( cJSON *const object, const char *const name ) +{ + cJSON *true_item = cJSON_CreateTrue(); + + if ( add_item_to_object( object, name, true_item, &global_hooks, false ) ) + { + return true_item; + } + + cJSON_Delete( true_item ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddFalseToObject( cJSON *const object, const char *const name ) +{ + cJSON *false_item = cJSON_CreateFalse(); + + if ( add_item_to_object( object, name, false_item, &global_hooks, false ) ) + { + return false_item; + } + + cJSON_Delete( false_item ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddBoolToObject( cJSON *const object, const char *const name, const cJSON_bool boolean ) +{ + cJSON *bool_item = cJSON_CreateBool( boolean ); + + if ( add_item_to_object( object, name, bool_item, &global_hooks, false ) ) + { + return bool_item; + } + + cJSON_Delete( bool_item ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddNumberToObject( cJSON *const object, const char *const name, const double number ) +{ + cJSON *number_item = cJSON_CreateNumber( number ); + + if ( add_item_to_object( object, name, number_item, &global_hooks, false ) ) + { + return number_item; + } + + cJSON_Delete( number_item ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddStringToObject( cJSON *const object, const char *const name, const char *const string ) +{ + cJSON *string_item = cJSON_CreateString( string ); + + if ( add_item_to_object( object, name, string_item, &global_hooks, false ) ) + { + return string_item; + } + + cJSON_Delete( string_item ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddRawToObject( cJSON *const object, const char *const name, const char *const raw ) +{ + cJSON *raw_item = cJSON_CreateRaw( raw ); + + if ( add_item_to_object( object, name, raw_item, &global_hooks, false ) ) + { + return raw_item; + } + + cJSON_Delete( raw_item ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddObjectToObject( cJSON *const object, const char *const name ) +{ + cJSON *object_item = cJSON_CreateObject(); + + if ( add_item_to_object( object, name, object_item, &global_hooks, false ) ) + { + return object_item; + } + + cJSON_Delete( object_item ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_AddArrayToObject( cJSON *const object, const char *const name ) +{ + cJSON *array = cJSON_CreateArray(); + + if ( add_item_to_object( object, name, array, &global_hooks, false ) ) + { + return array; + } + + cJSON_Delete( array ); + return NULL; +} + +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemViaPointer( cJSON *parent, cJSON *const item ) +{ + if ( ( parent == NULL ) || ( item == NULL ) ) + { + return NULL; + } + + if ( item->prev != NULL ) + { + /* not the first element */ + item->prev->next = item->next; + } + + if ( item->next != NULL ) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if ( item == parent->child ) + { + /* first element */ + parent->child = item->next; + } + + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemFromArray( cJSON *array, int which ) +{ + if ( which < 0 ) + { + return NULL; + } + + return cJSON_DetachItemViaPointer( array, get_array_item( array, ( size_t )which ) ); +} + +CJSON_PUBLIC( void ) cJSON_DeleteItemFromArray( cJSON *array, int which ) +{ + cJSON_Delete( cJSON_DetachItemFromArray( array, which ) ); +} + +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemFromObject( cJSON *object, const char *string ) +{ + cJSON *to_detach = cJSON_GetObjectItem( object, string ); + + return cJSON_DetachItemViaPointer( object, to_detach ); +} + +CJSON_PUBLIC( cJSON * ) cJSON_DetachItemFromObjectCaseSensitive( cJSON *object, const char *string ) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive( object, string ); + + return cJSON_DetachItemViaPointer( object, to_detach ); +} + +CJSON_PUBLIC( void ) cJSON_DeleteItemFromObject( cJSON *object, const char *string ) +{ + cJSON_Delete( cJSON_DetachItemFromObject( object, string ) ); +} + +CJSON_PUBLIC( void ) cJSON_DeleteItemFromObjectCaseSensitive( cJSON *object, const char *string ) +{ + cJSON_Delete( cJSON_DetachItemFromObjectCaseSensitive( object, string ) ); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC( void ) cJSON_InsertItemInArray( cJSON *array, int which, cJSON *newitem ) +{ + cJSON *after_inserted = NULL; + + if ( which < 0 ) + { + return; + } + + after_inserted = get_array_item( array, ( size_t )which ); + + if ( after_inserted == NULL ) + { + add_item_to_array( array, newitem ); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + + if ( after_inserted == array->child ) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_ReplaceItemViaPointer( cJSON *const parent, cJSON *const item, cJSON *replacement ) +{ + if ( ( parent == NULL ) || ( replacement == NULL ) || ( item == NULL ) ) + { + return false; + } + + if ( replacement == item ) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if ( replacement->next != NULL ) + { + replacement->next->prev = replacement; + } + + if ( replacement->prev != NULL ) + { + replacement->prev->next = replacement; + } + + if ( parent->child == item ) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete( item ); + + return true; +} + +CJSON_PUBLIC( void ) cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem ) +{ + if ( which < 0 ) + { + return; + } + + cJSON_ReplaceItemViaPointer( array, get_array_item( array, ( size_t )which ), newitem ); +} + +static cJSON_bool replace_item_in_object( cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive ) +{ + if ( ( replacement == NULL ) || ( string == NULL ) ) + { + return false; + } + + /* replace the name in the replacement */ + if ( !( replacement->type & cJSON_StringIsConst ) && ( replacement->string != NULL ) ) + { + cJSON_free( replacement->string ); + } + + replacement->string = ( char * )cJSON_strdup( ( const unsigned char * )string, &global_hooks ); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer( object, get_object_item( object, string, case_sensitive ), replacement ); + + return true; +} + +CJSON_PUBLIC( void ) cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem ) +{ + replace_item_in_object( object, string, newitem, false ); +} + +CJSON_PUBLIC( void ) cJSON_ReplaceItemInObjectCaseSensitive( cJSON *object, const char *string, cJSON *newitem ) +{ + replace_item_in_object( object, string, newitem, true ); +} + +/* Create basic types: */ +CJSON_PUBLIC( cJSON * ) cJSON_CreateNull( void ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateTrue( void ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateFalse( void ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateBool( cJSON_bool b ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateNumber( double num ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if ( num >= INT_MAX ) + { + item->valueint = INT_MAX; + } + else if ( num <= ( double )INT_MIN ) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = ( int )num; + } + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateString( const char *string ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_String; + item->valuestring = ( char * )cJSON_strdup( ( const unsigned char * )string, &global_hooks ); + + if ( !item->valuestring ) + { + cJSON_Delete( item ); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateStringReference( const char *string ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item != NULL ) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = ( char * )cast_away_const( string ); + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateObjectReference( const cJSON *child ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item != NULL ) + { + item->type = cJSON_Object | cJSON_IsReference; + item->child = ( cJSON * )cast_away_const( child ); + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateArrayReference( const cJSON *child ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item != NULL ) + { + item->type = cJSON_Array | cJSON_IsReference; + item->child = ( cJSON * )cast_away_const( child ); + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateRaw( const char *raw ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_Raw; + item->valuestring = ( char * )cJSON_strdup( ( const unsigned char * )raw, &global_hooks ); + + if ( !item->valuestring ) + { + cJSON_Delete( item ); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateArray( void ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateObject( void ) +{ + cJSON *item = cJSON_New_Item( &global_hooks ); + + if ( item ) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC( cJSON * ) cJSON_CreateIntArray( const int *numbers, int count ) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ( ( count < 0 ) || ( numbers == NULL ) ) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for ( i = 0; a && ( i < ( size_t )count ); i++ ) + { + n = cJSON_CreateNumber( numbers[i] ); + + if ( !n ) + { + cJSON_Delete( a ); + return NULL; + } + + if ( !i ) + { + a->child = n; + } + else + { + suffix_object( p, n ); + } + + p = n; + } + + return a; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateFloatArray( const float *numbers, int count ) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ( ( count < 0 ) || ( numbers == NULL ) ) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for ( i = 0; a && ( i < ( size_t )count ); i++ ) + { + n = cJSON_CreateNumber( ( double )numbers[i] ); + + if ( !n ) + { + cJSON_Delete( a ); + return NULL; + } + + if ( !i ) + { + a->child = n; + } + else + { + suffix_object( p, n ); + } + + p = n; + } + + return a; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateDoubleArray( const double *numbers, int count ) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ( ( count < 0 ) || ( numbers == NULL ) ) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for ( i = 0; a && ( i < ( size_t )count ); i++ ) + { + n = cJSON_CreateNumber( numbers[i] ); + + if ( !n ) + { + cJSON_Delete( a ); + return NULL; + } + + if ( !i ) + { + a->child = n; + } + else + { + suffix_object( p, n ); + } + + p = n; + } + + return a; +} + +CJSON_PUBLIC( cJSON * ) cJSON_CreateStringArray( const char **strings, int count ) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ( ( count < 0 ) || ( strings == NULL ) ) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for ( i = 0; a && ( i < ( size_t )count ); i++ ) + { + n = cJSON_CreateString( strings[i] ); + + if ( !n ) + { + cJSON_Delete( a ); + return NULL; + } + + if ( !i ) + { + a->child = n; + } + else + { + suffix_object( p, n ); + } + + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC( cJSON * ) cJSON_Duplicate( const cJSON *item, cJSON_bool recurse ) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if ( !item ) + { + goto fail; + } + + /* Create new item */ + newitem = cJSON_New_Item( &global_hooks ); + + if ( !newitem ) + { + goto fail; + } + + /* Copy over all vars */ + newitem->type = item->type & ( ~cJSON_IsReference ); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + + if ( item->valuestring ) + { + newitem->valuestring = ( char * )cJSON_strdup( ( unsigned char * )item->valuestring, &global_hooks ); + + if ( !newitem->valuestring ) + { + goto fail; + } + } + + if ( item->string ) + { + newitem->string = ( item->type & cJSON_StringIsConst ) ? item->string : ( char * )cJSON_strdup( ( unsigned char * )item->string, &global_hooks ); + + if ( !newitem->string ) + { + goto fail; + } + } + + /* If non-recursive, then we're done! */ + if ( !recurse ) + { + return newitem; + } + + /* Walk the ->next chain for the child. */ + child = item->child; + + while ( child != NULL ) + { + newchild = cJSON_Duplicate( child, true ); /* Duplicate (with recurse) each item in the ->next chain */ + + if ( !newchild ) + { + goto fail; + } + + if ( next != NULL ) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + + child = child->next; + } + + return newitem; + +fail: + + if ( newitem != NULL ) + { + cJSON_Delete( newitem ); + } + + return NULL; +} + +static void skip_oneline_comment( char **input ) +{ + *input += static_strlen( "//" ); + + for ( ; ( *input )[0] != '\0'; ++( *input ) ) + { + if ( ( *input )[0] == '\n' ) + { + *input += static_strlen( "\n" ); + return; + } + } +} + +static void skip_multiline_comment( char **input ) +{ + *input += static_strlen( "/*" ); + + for ( ; ( *input )[0] != '\0'; ++( *input ) ) + { + if ( ( ( *input )[0] == '*' ) && ( ( *input )[1] == '/' ) ) + { + *input += static_strlen( "*/" ); + return; + } + } +} + +static void minify_string( char **input, char **output ) +{ + ( *output )[0] = ( *input )[0]; + *input += static_strlen( "\"" ); + *output += static_strlen( "\"" ); + + + for ( ; ( *input )[0] != '\0'; ( void )++( *input ), ++( *output ) ) + { + ( *output )[0] = ( *input )[0]; + + if ( ( *input )[0] == '\"' ) + { + ( *output )[0] = '\"'; + *input += static_strlen( "\"" ); + *output += static_strlen( "\"" ); + return; + } + else if ( ( ( *input )[0] == '\\' ) && ( ( *input )[1] == '\"' ) ) + { + ( *output )[1] = ( *input )[1]; + *input += static_strlen( "\"" ); + *output += static_strlen( "\"" ); + } + } +} + +CJSON_PUBLIC( void ) cJSON_Minify( char *json ) +{ + char *into = json; + + if ( json == NULL ) + { + return; + } + + while ( json[0] != '\0' ) + { + switch ( json[0] ) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if ( json[1] == '/' ) + { + skip_oneline_comment( &json ); + } + else if ( json[1] == '*' ) + { + skip_multiline_comment( &json ); + } + else + { + json++; + } + + break; + + case '\"': + minify_string( &json, ( char ** )&into ); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsInvalid( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_Invalid; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsFalse( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_False; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsTrue( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xff ) == cJSON_True; +} + + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsBool( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & ( cJSON_True | cJSON_False ) ) != 0; +} +CJSON_PUBLIC( cJSON_bool ) cJSON_IsNull( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_NULL; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsNumber( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_Number; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsString( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_String; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsArray( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_Array; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsObject( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_Object; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_IsRaw( const cJSON *const item ) +{ + if ( item == NULL ) + { + return false; + } + + return ( item->type & 0xFF ) == cJSON_Raw; +} + +CJSON_PUBLIC( cJSON_bool ) cJSON_Compare( const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive ) +{ + if ( ( a == NULL ) || ( b == NULL ) || ( ( a->type & 0xFF ) != ( b->type & 0xFF ) ) || cJSON_IsInvalid( a ) ) + { + return false; + } + + /* check if type is valid */ + switch ( a->type & 0xFF ) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if ( a == b ) + { + return true; + } + + switch ( a->type & 0xFF ) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if ( a->valuedouble == b->valuedouble ) + { + return true; + } + + return false; + + case cJSON_String: + case cJSON_Raw: + if ( ( a->valuestring == NULL ) || ( b->valuestring == NULL ) ) + { + return false; + } + + if ( strcmp( a->valuestring, b->valuestring ) == 0 ) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for ( ; ( a_element != NULL ) && ( b_element != NULL ); ) + { + if ( !cJSON_Compare( a_element, b_element, case_sensitive ) ) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if ( a_element != b_element ) + { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach( a_element, a ) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item( b, a_element->string, case_sensitive ); + + if ( b_element == NULL ) + { + return false; + } + + if ( !cJSON_Compare( a_element, b_element, case_sensitive ) ) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach( b_element, b ) + { + a_element = get_object_item( a, b_element->string, case_sensitive ); + + if ( a_element == NULL ) + { + return false; + } + + if ( !cJSON_Compare( b_element, a_element, case_sensitive ) ) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC( void * ) cJSON_malloc( size_t size ) +{ + return global_hooks.allocate( size ); +} + +CJSON_PUBLIC( void ) cJSON_free( void *object ) +{ + global_hooks.deallocate( object ); +} diff --git a/Src/ftdispi.c b/Src/external/ftdispi.c similarity index 100% rename from Src/ftdispi.c rename to Src/external/ftdispi.c diff --git a/Src/orbtop.c b/Src/orbtop.c index 08f8f3ed..07f9d9ab 100644 --- a/Src/orbtop.c +++ b/Src/orbtop.c @@ -45,6 +45,8 @@ #include #include #include +#include + #include "bfd_wrapper.h" #if defined OSX #include @@ -63,6 +65,7 @@ #include #include +#include "cJSON.h" #include "generics.h" #include "uthash.h" #include "git_version_info.h" @@ -148,6 +151,7 @@ struct struct visitedAddr *addresses; /* Addresses we received in the SWV */ + uint64_t lastReport; /* Last time an output report was generated */ uint32_t interrupts; uint32_t sleeps; uint32_t notFound; @@ -160,34 +164,6 @@ struct // ==================================================================================================== // ==================================================================================================== // ==================================================================================================== - - - -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== -// Handler for individual message types from SWO -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== -void _handleException( struct ITMDecoder *i, struct ITMPacket *p ) - -{ - -} -// ==================================================================================================== -void _handleDWTEvent( struct ITMDecoder *i, struct ITMPacket *p ) - -{ - -} -// ==================================================================================================== -void _handleSW( struct ITMDecoder *i ) - -{ - -} -// ==================================================================================================== uint64_t _timestamp( void ) { @@ -240,26 +216,44 @@ int _report_sort_fn( const void *a, const void *b ) return ( ( struct reportLine * )b )->count - ( ( struct reportLine * )a )->count; } // ==================================================================================================== -void outputTop( void ) +// ==================================================================================================== +// ==================================================================================================== +// Handler for individual message types from SWO +// ==================================================================================================== +// ==================================================================================================== +// ==================================================================================================== +void _handleException( struct ITMDecoder *i, struct ITMPacket *p ) + +{ + +} +// ==================================================================================================== +void _handleDWTEvent( struct ITMDecoder *i, struct ITMPacket *p ) -/* Produce the output */ +{ + +} +// ==================================================================================================== +void _handleSW( struct ITMDecoder *i ) + +{ + +} +// ==================================================================================================== +// ==================================================================================================== +// Outputter routines +// ==================================================================================================== +// ==================================================================================================== +uint32_t _consolodateReport( struct reportLine **returnReport, uint32_t *returnReportLines ) { struct nameEntry *n; struct visitedAddr *a; - uint32_t reportLines = 0; struct reportLine *report = NULL; - uint32_t total = 0; - uint64_t samples = 0; - uint64_t dispSamples = 0; - uint32_t percentage; - uint32_t totPercent = 0; - FILE *p = NULL; - FILE *q = NULL; /* Put the address into order of the file and function names */ HASH_SORT( _r.addresses, _routines_sort_fn ); @@ -319,6 +313,40 @@ void outputTop( void ) /* Now put the whole thing into order of number of samples */ qsort( report, reportLines, sizeof( struct reportLine ), _report_sort_fn ); + *returnReport = report; + *returnReportLines = reportLines; + + return total; +} +// ==================================================================================================== +void _outputTop( void ) + +/* Produce the output */ + +{ + /* Returned materials from report generation */ + uint32_t reportLines = 0; + struct reportLine *report = NULL; + uint32_t total = 0; + + /* JSON output constructor */ + cJSON *jsonStore; + cJSON *jsonElement; + cJSON *jsonTopTable; + cJSON *jsonTableEntry; + char *opString; + + uint64_t samples = 0; + uint64_t dispSamples = 0; + uint32_t percentage; + uint32_t totPercent = 0; + + FILE *p = NULL; + FILE *q = NULL; + + /* Create the report that we will output */ + total = _consolodateReport( &report, &reportLines ); + /* This is the file retaining the current samples */ if ( options.outfile ) { @@ -331,18 +359,35 @@ void outputTop( void ) q = fopen( options.logfile, "a" ); } - if (!options.json) - { - fprintf( stdout, "\033[2J\033[;H" ); - } - else - { - /* Start of frame in JSON format */ - - } - if ( total ) { + if ( !options.json ) + { + fprintf( stdout, "\033[2J\033[;H" ); + } + else + { + /* Start of frame in JSON format */ + jsonStore = cJSON_CreateObject(); + assert( jsonStore ); + jsonElement = cJSON_CreateNumber( _timestamp() ); + assert( jsonElement ); + cJSON_AddItemToObject( jsonStore, "timestamp", jsonElement ); + jsonElement = cJSON_CreateNumber( total ); + assert( jsonElement ); + cJSON_AddItemToObject( jsonStore, "elements", jsonElement ); + uint64_t t = _timestamp(); + jsonElement = cJSON_CreateNumber( t - _r.lastReport ); + assert( jsonElement ); + _r.lastReport = t; + cJSON_AddItemToObject( jsonStore, "interval", jsonElement ); + + jsonTopTable = cJSON_CreateArray(); + assert( jsonTopTable ); + cJSON_AddItemToObject( jsonStore, "toptable", jsonTopTable ); + } + + for ( uint32_t n = 0; n < reportLines; n++ ) { percentage = ( report[n].count * 10000 ) / total; @@ -362,77 +407,107 @@ void outputTop( void ) dispSamples += report[n].count; totPercent += percentage; - if (!options.json) - { - fprintf( stdout, "%3d.%02d%% %8ld ", percentage / 100, percentage % 100, report[n].count ); - - - if ( ( options.reportFilenames ) && ( report[n].n->filename ) ) - { - fprintf( stdout, "%s::", report[n].n->filename ); - } - - if ( ( options.lineDisaggregation ) && ( report[n].n->line ) ) - { - fprintf( stdout, "%s::%d" EOL, d ? d : report[n].n->function, report[n].n->line ); - } - else - { - fprintf( stdout, "%s" EOL, d ? d : report[n].n->function ); - } - } - else - { - /* Output in JSON Format */ - } - } - - if ( ( p ) && ( n < options.maxRoutines ) && ( percentage >= CUTOFF ) ) - { - if ( !options.lineDisaggregation ) + if ( !options.json ) { - fprintf( p, "%s,%3d.%02d" EOL, d ? d : report[n].n->function, percentage / 100, percentage % 100 ); + fprintf( stdout, "%3d.%02d%% %8ld ", percentage / 100, percentage % 100, report[n].count ); + + + if ( ( options.reportFilenames ) && ( report[n].n->filename ) ) + { + fprintf( stdout, "%s::", report[n].n->filename ); + } + + if ( ( options.lineDisaggregation ) && ( report[n].n->line ) ) + { + fprintf( stdout, "%s::%d" EOL, d ? d : report[n].n->function, report[n].n->line ); + } + else + { + fprintf( stdout, "%s" EOL, d ? d : report[n].n->function ); + } } else { - fprintf( p, "%s::%d,%3d.%02d" EOL, d ? d : report[n].n->function, report[n].n->line, percentage / 100, percentage % 100 ); + /* Output in JSON Format */ + jsonTableEntry = cJSON_CreateObject(); + assert( jsonTableEntry ); + + jsonElement = cJSON_CreateNumber( report[n].count ); + assert( jsonElement ); + cJSON_AddItemToObject( jsonTableEntry, "count", jsonElement ); + jsonElement = cJSON_CreateString( report[n].n->filename ? report[n].n->filename : "" ); + assert( jsonElement ); + cJSON_AddItemToObject( jsonTableEntry, "filename", jsonElement ); + jsonElement = cJSON_CreateString( d ? d : report[n].n->function ); + assert( jsonElement ); + cJSON_AddItemToObject( jsonTableEntry, "function", jsonElement ); + + if ( options.lineDisaggregation ) + { + jsonElement = cJSON_CreateNumber( report[n].n->line ? report[n].n->line : 0 ); + assert( jsonElement ); + cJSON_AddItemToObject( jsonTableEntry, "line", jsonElement ); + } + + cJSON_AddItemToObject( jsonTopTable, "top", jsonTableEntry ); } } - if ( ( q ) && ( percentage >= CUTOFF ) ) + /* Write to current and historical data files if appropriate */ + if ( percentage >= CUTOFF ) { if ( !options.lineDisaggregation ) { - fprintf( q, "%s,%3d.%02d" EOL, d ? d : report[n].n->function, percentage / 100, percentage % 100 ); + if ( ( p ) && ( n < options.maxRoutines ) ) + { + fprintf( p, "%s,%3d.%02d" EOL, d ? d : report[n].n->function, percentage / 100, percentage % 100 ); + } + + if ( q ) + { + fprintf( q, "%s,%3d.%02d" EOL, d ? d : report[n].n->function, percentage / 100, percentage % 100 ); + } } else { - fprintf( q, "%s::%d,%3d.%02d" EOL, d ? d : report[n].n->function, report[n].n->line, percentage / 100, percentage % 100 ); + if ( ( p ) && ( n < options.maxRoutines ) ) + { + fprintf( p, "%s::%d,%3d.%02d" EOL, d ? d : report[n].n->function, report[n].n->line, percentage / 100, percentage % 100 ); + } + + if ( q ) + { + fprintf( q, "%s::%d,%3d.%02d" EOL, d ? d : report[n].n->function, report[n].n->line, percentage / 100, percentage % 100 ); + } } } - } } } - if (!options.json) - { - fprintf( stdout, "-----------------" EOL ); - - if ( samples == dispSamples ) - { - fprintf( stdout, "%3d.%02d%% %8ld Samples" EOL, totPercent / 100, totPercent % 100, samples ); - } - else - { - fprintf( stdout, "%3d.%02d%% %8ld of %ld Samples" EOL, totPercent / 100, totPercent % 100, dispSamples, samples ); - } - } + if ( !options.json ) + { + fprintf( stdout, "-----------------" EOL ); + + if ( samples == dispSamples ) + { + fprintf( stdout, "%3d.%02d%% %8ld Samples" EOL, totPercent / 100, totPercent % 100, samples ); + } + else + { + fprintf( stdout, "%3d.%02d%% %8ld of %ld Samples" EOL, totPercent / 100, totPercent % 100, dispSamples, samples ); + } + } else - { - /* Close off JSON report */ + { + /* Close off JSON report - if you want your printing pretty then use the first line */ + //opString=cJSON_Print(jsonStore); - } + opString = cJSON_PrintUnformatted( jsonStore ); + cJSON_Delete( jsonStore ); + fprintf( stdout, "%s" EOL, opString ); + free( opString ); + } if ( p ) { @@ -599,11 +674,9 @@ void _itmPumpProcess( char c ) } // ==================================================================================================== // ==================================================================================================== -// ==================================================================================================== // Protocol pump for decoding messages // ==================================================================================================== // ==================================================================================================== -// ==================================================================================================== void _protocolPump( uint8_t c ) /* Top level protocol pump */ @@ -681,7 +754,7 @@ void _printHelp( char *progName ) fprintf( stdout, " h: This help" EOL ); fprintf( stdout, " i: Set ITM Channel in TPIU decode (defaults to 1)" EOL ); fprintf( stdout, " I: Display interval in milliseconds (defaults to %d mS)" EOL, TOP_UPDATE_INTERVAL ); - fprintf( stdout, " j: Output in JSON format" EOL); + fprintf( stdout, " j: Output in JSON format" EOL ); fprintf( stdout, " l: Aggregate per line rather than per function" EOL ); fprintf( stdout, " n: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); fprintf( stdout, " o: to be used for output live file" EOL ); @@ -731,10 +804,10 @@ int _processOptions( int argc, char *argv[] ) // ------------------------------------ case 'j': - options.json = true; + options.json = true; break; - // ------------------------------------ + // ------------------------------------ case 'l': options.lineDisaggregation = true; break; @@ -850,6 +923,12 @@ int _processOptions( int argc, char *argv[] ) return true; } // ==================================================================================================== +// ==================================================================================================== +// ==================================================================================================== +// Externally available routines +// ==================================================================================================== +// ==================================================================================================== +// ==================================================================================================== int main( int argc, char *argv[] ) { @@ -913,6 +992,9 @@ int main( int argc, char *argv[] ) return -1; } + /* First interval will be from startup to first packet arriving */ + _r.lastReport = _timestamp(); + while ( ( t = read( sockfd, cbw, TRANSFER_SIZE ) ) > 0 ) { uint8_t *c = cbw; @@ -925,7 +1007,7 @@ int main( int argc, char *argv[] ) if ( ( _timestamp() - lastTime ) > options.displayInterval ) { lastTime = _timestamp(); - outputTop(); + _outputTop(); if ( !SymbolSetCheckValidity( &_r.s, options.elffile ) ) { diff --git a/Src/orbuculum.c b/Src/orbuculum.c index b9b525c3..6c322f56 100644 --- a/Src/orbuculum.c +++ b/Src/orbuculum.c @@ -262,10 +262,12 @@ static void *_runFifo( void *arg ) /* Build 32 value the long way around to avoid type-punning issues */ w = ( p.d[3] << 24 ) | ( p.d[2] << 16 ) | ( p.d[1] << 8 ) | ( p.d[0] ); - if (options.channel[params->portNo].presFormat) + + if ( options.channel[params->portNo].presFormat ) { // formatted output. writeDataLen = snprintf( constructString, MAX_STRING_LENGTH, options.channel[params->portNo].presFormat, w ); + if ( write( fifo, constructString, ( writeDataLen < MAX_STRING_LENGTH ) ? writeDataLen : MAX_STRING_LENGTH ) <= 0 ) { break; @@ -274,7 +276,7 @@ static void *_runFifo( void *arg ) else { // raw output. - if ( write( fifo, &w, sizeof (w) ) <= 0 ) + if ( write( fifo, &w, sizeof ( w ) ) <= 0 ) { break; } @@ -673,7 +675,7 @@ void _handleDataRWWP( struct ITMDecoder *i, struct ITMPacket *p ) { uint64_t ts = _timestampuS(); /* Stamp as early as possible */ - uint8_t comp = ( p->srcAddr >> 1) & 0x3; + uint8_t comp = ( p->srcAddr >> 1 ) & 0x3; bool isWrite = ( ( p->srcAddr & 0x01 ) != 0 ); uint32_t data; char outputString[MAX_STRING_LENGTH]; @@ -707,7 +709,7 @@ void _handleDataAccessWP( struct ITMDecoder *i, struct ITMPacket *p ) { uint64_t ts = _timestampuS(); /* Stamp as early as possible */ - uint8_t comp = ( p->srcAddr >> 1) & 0x3; + uint8_t comp = ( p->srcAddr >> 1 ) & 0x3; uint32_t data = ( p->d[0] ) | ( ( p->d[1] ) << 8 ) | ( ( p->d[2] ) << 16 ) | ( ( p->d[3] ) << 24 ); char outputString[MAX_STRING_LENGTH]; int opLen; @@ -725,7 +727,7 @@ void _handleDataOffsetWP( struct ITMDecoder *i, struct ITMPacket *p ) { uint64_t ts = _timestampuS(); /* Stamp as early as possible */ - uint8_t comp = ( p->srcAddr >> 1) & 0x3; + uint8_t comp = ( p->srcAddr >> 1 ) & 0x3; uint32_t offset = ( p->d[0] ) | ( ( p->d[1] ) << 8 ); char outputString[MAX_STRING_LENGTH]; int opLen; @@ -790,7 +792,7 @@ void _handleHW( struct ITMDecoder *i ) // -------------- default: - if ( ( p.srcAddr & 0x19 ) == 0x11) + if ( ( p.srcAddr & 0x19 ) == 0x11 ) { _handleDataRWWP( i, &p ); } @@ -1235,7 +1237,7 @@ int _processOptions( int argc, char *argv[] ) { if ( options.channel[g].chanName ) { - genericsReport( V_INFO, " %02d [%s] [%s]" EOL, g, GenericsEscape( options.channel[g].presFormat ?: "RAW" ), options.channel[g].chanName ); + genericsReport( V_INFO, " %02d [%s] [%s]" EOL, g, GenericsEscape( options.channel[g].presFormat ? : "RAW" ), options.channel[g].chanName ); } } diff --git a/Tools/povray/CIE.inc b/Tools/povray/CIE.inc new file mode 100644 index 00000000..28a7d333 --- /dev/null +++ b/Tools/povray/CIE.inc @@ -0,0 +1,2574 @@ +/* + Persistence of Vision Ray Tracer Include File + + COMMISSION INTERNATIONALE DE L'ECLAIRAGE + + CIE XYZ Color Model for PoV-Ray, Version 1.8 + + This started as a simple replacement for the spectrum sample calculation + for Jaimes' lightsys but meanwhile it's a kind of multi purpose CIE color + transformation system. + + -Ive 2003 email: ive@lilysoft.org + + ------------------------------------------------------------------------- + + update (version 1.71) + - corrected some pass-by-reference issue + - email address updated + + -Ive 2012 + + ------------------------------------------------------------------------- + + update (version 1.8) + - added the XYZ2K() macro to calculate the correlated color temperature + from a given XYZ coordinate. + - corrected some errors in the comments. + + -Ive 2016 + + ------------------------------------------------------------------------- + + Main features: + + CIE observer + CIE 1931 2°observer, CIE 1964 10°observer, CIE 1978 Judd/Vos + + CIE reference white + Illuminant A, B, C, D50, D55, D65, D75, E and all F-types are supported. + + CIE color system and default illuminant + with 13 predifined color systems together with the illuminant and the + possibility to select also 'custom-made' systems. + + CIE color system with custum illuminant + use any non-default illuminant for the predefined color system + already 20 CIE standard illuminants are defined and in addition you + can convert temperatures to whitepoints. + + CIE color order systems and conversion utilities between + RGB, XYZ, xyY, Lab, Lch + + Wavelength, blackbody, daylight(D illuminant), reflective-, emissive- + and line-spectrum color conversion tools + + Gamut mapping with different functions (for xyz->RGB conversion) + + Chromatic adaption with different functions + (used for Lab,Lch <-> xyz and reflectance spectrum -> xyz and + 'reference rgb' conversion) + + Grayscale feature + +*/ + +// Standard include file beginning stuff +#ifndef (CIE_Inc_Temp) +#declare CIE_Inc_Temp = version; + + +#ifdef(View_POV_Include_Stack) + #debug "Including CIE.inc\n" +#end + + +// additional CIE.inc settings +#ifndef (CIE_Debug) + #declare CIE_Debug = false; +#end + +#ifndef (CIE_MultiObserver) + #declare CIE_MultiObserver = false; +#end + +#ifndef (CIE_IntegralStep) + #declare CIE_IntegralStep = 5; // step width for integral over spectra +#end + + +//===================================================================== +// first all the lookup tables and pre-definitions +// +/* CIE observer color matching function tables + * xyz spectral coordinates in steps of 5 nm. + * see also Fig. 13.24 in [Foley96 p.581] + * taken from http://cvision.ucsd.edu/cie.htm + * For consistence and easy access all tables are reduced to the + * range of 380 to 825 nanometers. + * The first column is the original 1931 2° observer CMF, the second + * the 1964 10° and the third is the 2° observer modified by Judd/Vos + */ +#if (CIE_MultiObserver) +#declare CMF_table = array[90][3] { +{<0.001368000000,0.000039000000,0.006450001000>,<0.000159952000,0.000017364000,0.000704776000>,<0.002689900000,0.000200000000,0.012260000000>},//380 +{<0.002236000000,0.000064000000,0.010549990000>,<0.000662440000,0.000071560000,0.002927800000>,<0.005310500000,0.000395560000,0.024222000000>},//385 +{<0.004243000000,0.000120000000,0.020050010000>,<0.002361600000,0.000253400000,0.010482200000>,<0.010781000000,0.000800000000,0.049250000000>},//390 +{<0.007650000000,0.000217000000,0.036210000000>,<0.007242300000,0.000768500000,0.032344000000>,<0.020792000000,0.001545700000,0.095135000000>},//395 +{<0.014310000000,0.000396000000,0.067850010000>,<0.019109700000,0.002004400000,0.086010900000>,<0.037981000000,0.002800000000,0.174090000000>},//400 +{<0.023190000000,0.000640000000,0.110200000000>,<0.043400000000,0.004509000000,0.197120000000>,<0.063157000000,0.004656200000,0.290130000000>},//405 +{<0.043510000000,0.001210000000,0.207400000000>,<0.084736000000,0.008756000000,0.389366000000>,<0.099941000000,0.007400000000,0.460530000000>},//410 +{<0.077630000000,0.002180000000,0.371300000000>,<0.140638000000,0.014456000000,0.656760000000>,<0.158240000000,0.011779000000,0.731660000000>},//415 +{<0.134380000000,0.004000000000,0.645600000000>,<0.204492000000,0.021391000000,0.972542000000>,<0.229480000000,0.017500000000,1.065800000000>},//420 +{<0.214770000000,0.007300000000,1.039050100000>,<0.264737000000,0.029497000000,1.282500000000>,<0.281080000000,0.022678000000,1.314600000000>},//425 +{<0.283900000000,0.011600000000,1.385600000000>,<0.314679000000,0.038676000000,1.553480000000>,<0.310950000000,0.027300000000,1.467200000000>},//430 +{<0.328500000000,0.016840000000,1.622960000000>,<0.357719000000,0.049602000000,1.798500000000>,<0.330720000000,0.032584000000,1.579600000000>},//435 +{<0.348280000000,0.023000000000,1.747060000000>,<0.383734000000,0.062077000000,1.967280000000>,<0.333360000000,0.037900000000,1.616600000000>},//440 +{<0.348060000000,0.029800000000,1.782600000000>,<0.386726000000,0.074704000000,2.027300000000>,<0.316720000000,0.042391000000,1.568200000000>},//445 +{<0.336200000000,0.038000000000,1.772110000000>,<0.370702000000,0.089456000000,1.994800000000>,<0.288820000000,0.046800000000,1.471700000000>},//450 +{<0.318700000000,0.048000000000,1.744100000000>,<0.342957000000,0.106256000000,1.900700000000>,<0.259690000000,0.052122000000,1.374000000000>},//455 +{<0.290800000000,0.060000000000,1.669200000000>,<0.302273000000,0.128201000000,1.745370000000>,<0.232760000000,0.060000000000,1.291700000000>},//460 +{<0.251100000000,0.073900000000,1.528100000000>,<0.254085000000,0.152761000000,1.554900000000>,<0.209990000000,0.072942000000,1.235600000000>},//465 +{<0.195360000000,0.090980000000,1.287640000000>,<0.195618000000,0.185190000000,1.317560000000>,<0.174760000000,0.090980000000,1.113800000000>},//470 +{<0.142100000000,0.112600000000,1.041900000000>,<0.132349000000,0.219940000000,1.030200000000>,<0.132870000000,0.112840000000,0.942200000000>},//475 +{<0.095640000000,0.139020000000,0.812950100000>,<0.080507000000,0.253589000000,0.772125000000>,<0.091944000000,0.139020000000,0.755960000000>},//480 +{<0.057950010000,0.169300000000,0.616200000000>,<0.041072000000,0.297665000000,0.570600000000>,<0.056985000000,0.169870000000,0.586400000000>},//485 +{<0.032010000000,0.208020000000,0.465180000000>,<0.016172000000,0.339133000000,0.415254000000>,<0.031731000000,0.208020000000,0.446690000000>},//490 +{<0.014700000000,0.258600000000,0.353300000000>,<0.005132000000,0.395379000000,0.302356000000>,<0.014613000000,0.258080000000,0.341160000000>},//495 +{<0.004900000000,0.323000000000,0.272000000000>,<0.003816000000,0.460777000000,0.218502000000>,<0.004849100000,0.323000000000,0.264370000000>},//500 +{<0.002400000000,0.407300000000,0.212300000000>,<0.015444000000,0.531360000000,0.159249000000>,<0.002321500000,0.405400000000,0.205940000000>},//505 +{<0.009300000000,0.503000000000,0.158200000000>,<0.037465000000,0.606741000000,0.112044000000>,<0.009289900000,0.503000000000,0.154450000000>},//510 +{<0.029100000000,0.608200000000,0.111700000000>,<0.071358000000,0.685660000000,0.082248000000>,<0.029278000000,0.608110000000,0.109180000000>},//515 +{<0.063270000000,0.710000000000,0.078249990000>,<0.117749000000,0.761757000000,0.060709000000>,<0.063791000000,0.710000000000,0.076585000000>},//520 +{<0.109600000000,0.793200000000,0.057250010000>,<0.172953000000,0.823330000000,0.043050000000>,<0.110810000000,0.795100000000,0.056227000000>},//525 +{<0.165500000000,0.862000000000,0.042160000000>,<0.236491000000,0.875211000000,0.030451000000>,<0.166920000000,0.862000000000,0.041366000000>},//530 +{<0.225749900000,0.914850100000,0.029840000000>,<0.304213000000,0.923810000000,0.020584000000>,<0.227680000000,0.915050000000,0.029353000000>},//535 +{<0.290400000000,0.954000000000,0.020300000000>,<0.376772000000,0.961988000000,0.013676000000>,<0.292690000000,0.954000000000,0.020042000000>},//540 +{<0.359700000000,0.980300000000,0.013400000000>,<0.451584000000,0.982200000000,0.007918000000>,<0.362250000000,0.980040000000,0.013312000000>},//545 +{<0.433449900000,0.994950100000,0.008749999000>,<0.529826000000,0.991761000000,0.003988000000>,<0.436350000000,0.994950000000,0.008782300000>},//550 +{<0.512050100000,1.000000000000,0.005749999000>,<0.616053000000,0.999110000000,0.001091000000>,<0.515130000000,1.000100000000,0.005857300000>},//555 +{<0.594500000000,0.995000000000,0.003900000000>,<0.705224000000,0.997340000000,0.000000000000>,<0.597480000000,0.995000000000,0.004049300000>},//560 +{<0.678400000000,0.978600000000,0.002749999000>,<0.793832000000,0.982380000000,0.000000000000>,<0.681210000000,0.978750000000,0.002921700000>},//565 +{<0.762100000000,0.952000000000,0.002100000000>,<0.878655000000,0.955552000000,0.000000000000>,<0.764250000000,0.952000000000,0.002277100000>},//570 +{<0.842500000000,0.915400000000,0.001800000000>,<0.951162000000,0.915175000000,0.000000000000>,<0.843940000000,0.915580000000,0.001970600000>},//575 +{<0.916300000000,0.870000000000,0.001650001000>,<1.014160000000,0.868934000000,0.000000000000>,<0.916350000000,0.870000000000,0.001806600000>},//580 +{<0.978600000000,0.816300000000,0.001400000000>,<1.074300000000,0.825623000000,0.000000000000>,<0.977030000000,0.816230000000,0.001544900000>},//585 +{<1.026300000000,0.757000000000,0.001100000000>,<1.118520000000,0.777405000000,0.000000000000>,<1.023000000000,0.757000000000,0.001234800000>},//590 +{<1.056700000000,0.694900000000,0.001000000000>,<1.134300000000,0.720353000000,0.000000000000>,<1.051300000000,0.694830000000,0.001117700000>},//595 +{<1.062200000000,0.631000000000,0.000800000000>,<1.123990000000,0.658341000000,0.000000000000>,<1.055000000000,0.631000000000,0.000905640000>},//600 +{<1.045600000000,0.566800000000,0.000600000000>,<1.089100000000,0.593878000000,0.000000000000>,<1.036200000000,0.566540000000,0.000694670000>},//605 +{<1.002600000000,0.503000000000,0.000340000000>,<1.030480000000,0.527963000000,0.000000000000>,<0.992390000000,0.503000000000,0.000428850000>},//610 +{<0.938400000000,0.441200000000,0.000240000000>,<0.950740000000,0.461834000000,0.000000000000>,<0.928610000000,0.441720000000,0.000318170000>},//615 +{<0.854449900000,0.381000000000,0.000190000000>,<0.856297000000,0.398057000000,0.000000000000>,<0.843460000000,0.381000000000,0.000255980000>},//620 +{<0.751400000000,0.321000000000,0.000100000000>,<0.754930000000,0.339554000000,0.000000000000>,<0.739830000000,0.320520000000,0.000156790000>},//625 +{<0.642400000000,0.265000000000,0.000049999990>,<0.647467000000,0.283493000000,0.000000000000>,<0.632890000000,0.265000000000,0.000097694000>},//630 +{<0.541900000000,0.217000000000,0.000030000000>,<0.535110000000,0.228254000000,0.000000000000>,<0.533510000000,0.217020000000,0.000068944000>},//635 +{<0.447900000000,0.175000000000,0.000020000000>,<0.431567000000,0.179828000000,0.000000000000>,<0.440620000000,0.175000000000,0.000051165000>},//640 +{<0.360800000000,0.138200000000,0.000010000000>,<0.343690000000,0.140211000000,0.000000000000>,<0.354530000000,0.138120000000,0.000036016000>},//645 +{<0.283500000000,0.107000000000,0.000000000000>,<0.268329000000,0.107633000000,0.000000000000>,<0.278620000000,0.107000000000,0.000024238000>},//650 +{<0.218700000000,0.081600000000,0.000000000000>,<0.204300000000,0.081187000000,0.000000000000>,<0.214850000000,0.081652000000,0.000016915000>},//655 +{<0.164900000000,0.061000000000,0.000000000000>,<0.152568000000,0.060281000000,0.000000000000>,<0.161610000000,0.061000000000,0.000011906000>},//660 +{<0.121200000000,0.044580000000,0.000000000000>,<0.112210000000,0.044096000000,0.000000000000>,<0.118200000000,0.044327000000,0.000008148900>},//665 +{<0.087400000000,0.032000000000,0.000000000000>,<0.081260600000,0.031800400000,0.000000000000>,<0.085753000000,0.032000000000,0.000005600600>},//670 +{<0.063600000000,0.023200000000,0.000000000000>,<0.057930000000,0.022601700000,0.000000000000>,<0.063077000000,0.023454000000,0.000003954400>},//675 +{<0.046770000000,0.017000000000,0.000000000000>,<0.040850800000,0.015905100000,0.000000000000>,<0.045834000000,0.017000000000,0.000002791200>},//680 +{<0.032900000000,0.011920000000,0.000000000000>,<0.028623000000,0.011130300000,0.000000000000>,<0.032057000000,0.011872000000,0.000001917600>},//685 +{<0.022700000000,0.008210000000,0.000000000000>,<0.019941300000,0.007748800000,0.000000000000>,<0.022187000000,0.008210000000,0.000001313500>},//690 +{<0.015840000000,0.005723000000,0.000000000000>,<0.013842000000,0.005375100000,0.000000000000>,<0.015612000000,0.005772300000,0.000000915190>},//695 +{<0.011359160000,0.004102000000,0.000000000000>,<0.009576880000,0.003717740000,0.000000000000>,<0.011098000000,0.004102000000,0.000000647670>},//700 +{<0.008110916000,0.002929000000,0.000000000000>,<0.006605200000,0.002564560000,0.000000000000>,<0.007923300000,0.002929100000,0.000000463520>},//705 +{<0.005790346000,0.002091000000,0.000000000000>,<0.004552630000,0.001768470000,0.000000000000>,<0.005653100000,0.002091000000,0.000000333040>},//710 +{<0.004106457000,0.001484000000,0.000000000000>,<0.003144700000,0.001222390000,0.000000000000>,<0.004003900000,0.001482200000,0.000000238230>},//715 +{<0.002899327000,0.001047000000,0.000000000000>,<0.002174960000,0.000846190000,0.000000000000>,<0.002825300000,0.001047000000,0.000000170260>},//720 +{<0.002049190000,0.000740000000,0.000000000000>,<0.001505700000,0.000586440000,0.000000000000>,<0.001994700000,0.000740150000,0.000000122070>},//725 +{<0.001439971000,0.000520000000,0.000000000000>,<0.001044760000,0.000407410000,0.000000000000>,<0.001399400000,0.000520000000,0.000000087107>},//730 +{<0.000999949300,0.000361100000,0.000000000000>,<0.000727450000,0.000284041000,0.000000000000>,<0.000969800000,0.000360930000,0.000000061455>},//735 +{<0.000690078600,0.000249200000,0.000000000000>,<0.000508258000,0.000198730000,0.000000000000>,<0.000668470000,0.000249200000,0.000000043162>},//740 +{<0.000476021300,0.000171900000,0.000000000000>,<0.000356380000,0.000139550000,0.000000000000>,<0.000461410000,0.000172310000,0.000000030379>},//745 +{<0.000332301100,0.000120000000,0.000000000000>,<0.000250969000,0.000098428000,0.000000000000>,<0.000320730000,0.000120000000,0.000000021554>},//750 +{<0.000234826100,0.000084800000,0.000000000000>,<0.000177730000,0.000069819000,0.000000000000>,<0.000225730000,0.000084620000,0.000000015493>},//755 +{<0.000166150500,0.000060000000,0.000000000000>,<0.000126390000,0.000049737000,0.000000000000>,<0.000159730000,0.000060000000,0.000000011204>},//760 +{<0.000117413000,0.000042400000,0.000000000000>,<0.000090151000,0.000035540500,0.000000000000>,<0.000112750000,0.000042446000,0.000000008087>},//765 +{<0.000083075270,0.000030000000,0.000000000000>,<0.000064525800,0.000025486000,0.000000000000>,<0.000079513000,0.000030000000,0.000000005834>},//770 +{<0.000058706520,0.000021200000,0.000000000000>,<0.000046339000,0.000018338400,0.000000000000>,<0.000056087000,0.000021210000,0.000000004211>},//775 +{<0.000041509940,0.000014990000,0.000000000000>,<0.000033411700,0.000013249000,0.000000000000>,<0.000039541000,0.000014989000,0.000000003038>},//780 +{<0.000029353260,0.000010600000,0.000000000000>,<0.000024209000,0.000009619600,0.000000000000>,<0.000027852000,0.000010584000,0.000000002191>},//785 +{<0.000020673830,0.000007465700,0.000000000000>,<0.000017611500,0.000007012800,0.000000000000>,<0.000019597000,0.000007465600,0.000000001578>},//790 +{<0.000014559770,0.000005257800,0.000000000000>,<0.000012855000,0.000005129800,0.000000000000>,<0.000013770000,0.000005259200,0.000000001135>},//795 +{<0.000010253980,0.000003702900,0.000000000000>,<0.000009413630,0.000003764730,0.000000000000>,<0.000009670000,0.000003702800,0.000000000816>},//800 +{<0.000007221456,0.000002607800,0.000000000000>,<0.000006913000,0.000002770810,0.000000000000>,<0.000006791800,0.000002607600,0.000000000586>},//805 +{<0.000005085868,0.000001836600,0.000000000000>,<0.000005093470,0.000002046130,0.000000000000>,<0.000004770600,0.000001836500,0.000000000421>},//810 +{<0.000003581652,0.000001293400,0.000000000000>,<0.000003767100,0.000001516770,0.000000000000>,<0.000003355000,0.000001295000,0.000000000303>},//815 +{<0.000002522525,0.000000910930,0.000000000000>,<0.000002795310,0.000001128090,0.000000000000>,<0.000002353400,0.000000910920,0.000000000218>},//820 +{<0.000001776509,0.000000641530,0.000000000000>,<0.000002082000,0.000000842160,0.000000000000>,<0.000001637700,0.000000635640,0.000000000155>} //825 +} +#end // if MultiObserver + +/* CIE observer color matching function + * initialized for the 1931 2° standard observer. + * This spline is automatical reinitialized if + * any other CMF is selected. + * See the macro CIE_Observer for more details. + */ +#declare CMF_xyz = spline { cubic_spline + 375, <0,0,0> + 380, <0.001368000000, 0.000039000000, 0.006450001000> + 385, <0.002236000000, 0.000064000000, 0.010549990000> + 390, <0.004243000000, 0.000120000000, 0.020050010000> + 395, <0.007650000000, 0.000217000000, 0.036210000000> + 400, <0.014310000000, 0.000396000000, 0.067850010000> + 405, <0.023190000000, 0.000640000000, 0.110200000000> + 410, <0.043510000000, 0.001210000000, 0.207400000000> + 415, <0.077630000000, 0.002180000000, 0.371300000000> + 420, <0.134380000000, 0.004000000000, 0.645600000000> + 425, <0.214770000000, 0.007300000000, 1.039050100000> + 430, <0.283900000000, 0.011600000000, 1.385600000000> + 435, <0.328500000000, 0.016840000000, 1.622960000000> + 440, <0.348280000000, 0.023000000000, 1.747060000000> + 445, <0.348060000000, 0.029800000000, 1.782600000000> + 450, <0.336200000000, 0.038000000000, 1.772110000000> + 455, <0.318700000000, 0.048000000000, 1.744100000000> + 460, <0.290800000000, 0.060000000000, 1.669200000000> + 465, <0.251100000000, 0.073900000000, 1.528100000000> + 470, <0.195360000000, 0.090980000000, 1.287640000000> + 475, <0.142100000000, 0.112600000000, 1.041900000000> + 480, <0.095640000000, 0.139020000000, 0.812950100000> + 485, <0.057950010000, 0.169300000000, 0.616200000000> + 490, <0.032010000000, 0.208020000000, 0.465180000000> + 495, <0.014700000000, 0.258600000000, 0.353300000000> + 500, <0.004900000000, 0.323000000000, 0.272000000000> + 505, <0.002400000000, 0.407300000000, 0.212300000000> + 510, <0.009300000000, 0.503000000000, 0.158200000000> + 515, <0.029100000000, 0.608200000000, 0.111700000000> + 520, <0.063270000000, 0.710000000000, 0.078249990000> + 525, <0.109600000000, 0.793200000000, 0.057250010000> + 530, <0.165500000000, 0.862000000000, 0.042160000000> + 535, <0.225749900000, 0.914850100000, 0.029840000000> + 540, <0.290400000000, 0.954000000000, 0.020300000000> + 545, <0.359700000000, 0.980300000000, 0.013400000000> + 550, <0.433449900000, 0.994950100000, 0.008749999000> + 555, <0.512050100000, 1.000000000000, 0.005749999000> + 560, <0.594500000000, 0.995000000000, 0.003900000000> + 565, <0.678400000000, 0.978600000000, 0.002749999000> + 570, <0.762100000000, 0.952000000000, 0.002100000000> + 575, <0.842500000000, 0.915400000000, 0.001800000000> + 580, <0.916300000000, 0.870000000000, 0.001650001000> + 585, <0.978600000000, 0.816300000000, 0.001400000000> + 590, <1.026300000000, 0.757000000000, 0.001100000000> + 595, <1.056700000000, 0.694900000000, 0.001000000000> + 600, <1.062200000000, 0.631000000000, 0.000800000000> + 605, <1.045600000000, 0.566800000000, 0.000600000000> + 610, <1.002600000000, 0.503000000000, 0.000340000000> + 615, <0.938400000000, 0.441200000000, 0.000240000000> + 620, <0.854449900000, 0.381000000000, 0.000190000000> + 625, <0.751400000000, 0.321000000000, 0.000100000000> + 630, <0.642400000000, 0.265000000000, 0.000049999990> + 635, <0.541900000000, 0.217000000000, 0.000030000000> + 640, <0.447900000000, 0.175000000000, 0.000020000000> + 645, <0.360800000000, 0.138200000000, 0.000010000000> + 650, <0.283500000000, 0.107000000000, 0.000000000000> + 655, <0.218700000000, 0.081600000000, 0.000000000000> + 660, <0.164900000000, 0.061000000000, 0.000000000000> + 665, <0.121200000000, 0.044580000000, 0.000000000000> + 670, <0.087400000000, 0.032000000000, 0.000000000000> + 675, <0.063600000000, 0.023200000000, 0.000000000000> + 680, <0.046770000000, 0.017000000000, 0.000000000000> + 685, <0.032900000000, 0.011920000000, 0.000000000000> + 690, <0.022700000000, 0.008210000000, 0.000000000000> + 695, <0.015840000000, 0.005723000000, 0.000000000000> + 700, <0.011359160000, 0.004102000000, 0.000000000000> + 705, <0.008110916000, 0.002929000000, 0.000000000000> + 710, <0.005790346000, 0.002091000000, 0.000000000000> + 715, <0.004106457000, 0.001484000000, 0.000000000000> + 720, <0.002899327000, 0.001047000000, 0.000000000000> + 725, <0.002049190000, 0.000740000000, 0.000000000000> + 730, <0.001439971000, 0.000520000000, 0.000000000000> + 735, <0.000999949300, 0.000361100000, 0.000000000000> + 740, <0.000690078600, 0.000249200000, 0.000000000000> + 745, <0.000476021300, 0.000171900000, 0.000000000000> + 750, <0.000332301100, 0.000120000000, 0.000000000000> + 755, <0.000234826100, 0.000084800000, 0.000000000000> + 760, <0.000166150500, 0.000060000000, 0.000000000000> + 765, <0.000117413000, 0.000042400000, 0.000000000000> + 770, <0.000083075270, 0.000030000000, 0.000000000000> + 775, <0.000058706520, 0.000021200000, 0.000000000000> + 780, <0.000041509940, 0.000014990000, 0.000000000000> + 785, <0.000029353260, 0.000010600000, 0.000000000000> + 790, <0.000020673830, 0.000007465700, 0.000000000000> + 795, <0.000014559770, 0.000005257800, 0.000000000000> + 800, <0.000010253980, 0.000003702900, 0.000000000000> + 805, <0.000007221456, 0.000002607800, 0.000000000000> + 810, <0.000005085868, 0.000001836600, 0.000000000000> + 815, <0.000003581652, 0.000001293400, 0.000000000000> + 820, <0.000002522525, 0.000000910930, 0.000000000000> + 825, <0.000001776509, 0.000000641530, 0.000000000000> + 830, <0,0,0> +} + +/* Lookup table containing S0, S1, S2 to calculate the spectra for the + * CIE D standard illuminants (D50, D55, D65, D75) and also custum D + * illuminants for color temperatures between 4000K and 25000K. + * See the macro Daylight for the formula and more details. + */ +#declare DS012 = array[90][3] { + { 63.40, 38.50, 3.00},// 380 + { 64.60, 36.75, 2.10},// 385 + { 65.80, 35.00, 1.20},// 390 + { 80.30, 39.20, 0.05},// 395 + { 94.80, 43.40, -1.10},// 400 + { 99.80, 44.85, -0.80},// 405 + {104.80, 46.30, -0.50},// 410 + {105.35, 45.10, -0.60},// 415 + {105.90, 43.90, -0.70},// 420 + {101.35, 40.50, -0.95},// 425 + { 96.80, 37.10, -1.20},// 430 + {105.35, 36.90, -1.90},// 435 + {113.90, 36.70, -2.60},// 440 + {119.75, 36.30, -2.75},// 445 + {125.60, 35.90, -2.90},// 450 + {125.55, 34.25, -2.85},// 455 + {125.50, 32.60, -2.80},// 460 + {123.40, 30.25, -2.70},// 465 + {121.30, 27.90, -2.60},// 470 + {121.30, 26.10, -2.60},// 475 + {121.30, 24.30, -2.60},// 480 + {117.40, 22.20, -2.20},// 485 + {113.50, 20.10, -1.80},// 490 + {113.30, 18.15, -1.65},// 495 + {113.10, 16.20, -1.50},// 500 + {111.95, 14.70, -1.40},// 505 + {110.80, 13.20, -1.30},// 510 + {108.65, 10.90, -1.25},// 515 + {106.50, 8.60, -1.20},// 520 + {107.65, 7.35, -1.10},// 525 + {108.80, 6.10, -1.00},// 530 + {107.05, 5.15, -0.75},// 535 + {105.30, 4.20, -0.50},// 540 + {104.85, 3.05, -0.40},// 545 + {104.40, 1.90, -0.30},// 550 + {102.20, 0.95, -0.15},// 555 + {100.00, 0.00, 0.00},// 560 + { 98.00, -0.80, 0.10},// 565 + { 96.00, -1.60, 0.20},// 570 + { 95.55, -2.55, 0.35},// 575 + { 95.10, -3.50, 0.50},// 580 + { 92.10, -3.50, 1.30},// 585 + { 89.10, -3.50, 2.10},// 590 + { 89.80, -4.65, 2.65},// 595 + { 90.50, -5.80, 3.20},// 600 + { 90.40, -6.50, 3.65},// 605 + { 90.30, -7.20, 4.10},// 610 + { 89.35, -7.90, 4.40},// 615 + { 88.40, -8.60, 4.70},// 620 + { 86.20, -9.05, 4.90},// 625 + { 84.00, -9.50, 5.10},// 630 + { 84.55,-10.20, 5.90},// 635 + { 85.10,-10.90, 6.70},// 640 + { 83.50,-10.80, 7.00},// 645 + { 81.90,-10.70, 7.30},// 650 + { 82.25,-11.35, 7.95},// 655 + { 82.60,-12.00, 8.60},// 660 + { 83.75,-13.00, 9.20},// 665 + { 84.90,-14.00, 9.80},// 670 + { 83.10,-13.80, 10.00},// 675 + { 81.30,-13.60, 10.20},// 680 + { 76.60,-12.80, 9.25},// 685 + { 71.90,-12.00, 8.30},// 690 + { 73.10,-12.65, 8.95},// 695 + { 74.30,-13.30, 9.60},// 700 + { 75.35,-13.10, 9.05},// 705 + { 76.40,-12.90, 8.50},// 710 + { 69.85,-11.75, 7.75},// 715 + { 63.30,-10.60, 7.00},// 720 + { 67.50,-11.10, 7.30},// 725 + { 71.70,-11.60, 7.60},// 730 + { 74.35,-11.90, 7.80},// 735 + { 77.00,-12.20, 8.00},// 740 + { 71.10,-11.20, 7.35},// 745 + { 65.20,-10.20, 6.70},// 750 + { 56.45, -9.00, 5.95},// 755 + { 47.70, -7.80, 5.20},// 760 + { 58.15, -9.50, 6.30},// 765 + { 68.60,-11.20, 7.40},// 770 + { 66.80,-10.80, 7.10},// 775 + { 65.00,-10.40, 6.80},// 780 + { 65.50,-10.50, 6.90},// 785 + { 66.00,-10.60, 7.00},// 790 + { 63.50,-10.15, 6.70},// 795 + { 61.00, -9.70, 6.40},// 800 + { 57.15, -9.00, 5.95},// 805 + { 53.30, -8.30, 5.50},// 810 + { 56.10, -8.80, 5.80},// 815 + { 58.90, -9.30, 6.10},// 820 + { 60.40, -9.55, 6.30},// 825 +} + +/* RefWhiteSP is initialized to D50 and recalculated if + * any other D illuminant or the A illuminant is requested. + * In every other case it is set equal to the the CIE standard + * illuminants as stored in the file "espd_cie_standard.inc". + */ +#declare RefWhiteSP = spline{ linear_spline + 380, 0.244992 + 385, 0.271905 + 390, 0.298818 + 395, 0.396023 + 400, 0.493228 + 405, 0.529255 + 410, 0.565283 + 415, 0.582884 + 420, 0.600485 + 425, 0.589394 + 430, 0.578302 + 435, 0.663340 + 440, 0.748379 + 445, 0.810490 + 450, 0.872601 + 455, 0.889420 + 460, 0.906239 + 465, 0.910011 + 470, 0.913782 + 475, 0.932478 + 480, 0.951174 + 485, 0.935437 + 490, 0.919700 + 495, 0.938498 + 500, 0.957296 + 505, 0.961738 + 510, 0.966181 + 515, 0.968752 + 520, 0.971323 + 525, 0.996169 + 530, 1.021015 + 535, 1.014289 + 540, 1.007563 + 545, 1.015370 + 550, 1.023177 + 555, 1.011589 + 560, 1.000000 + 565, 0.988672 + 570, 0.977344 + 575, 0.983255 + 580, 0.989167 + 585, 0.962068 + 590, 0.934969 + 595, 0.955909 + 600, 0.976848 + 605, 0.984751 + 610, 0.992653 + 615, 0.991512 + 620, 0.990371 + 625, 0.973770 + 630, 0.957169 + 635, 0.972841 + 640, 0.988513 + 645, 0.972562 + 650, 0.956612 + 655, 0.969220 + 660, 0.981829 + 665, 1.005892 + 670, 1.029954 + 675, 1.010602 + 680, 0.991250 + 685, 0.932496 + 690, 0.873741 + 695, 0.894850 + 700, 0.915958 + 705, 0.922386 + 710, 0.928814 + 715, 0.848650 + 720, 0.768485 + 725, 0.816766 + 730, 0.865048 + 735, 0.895389 + 740, 0.925730 + 745, 0.853986 + 750, 0.782242 + 755, 0.679558 + 760, 0.576875 +} + + +/* xy reference values for perfect diffuse reflection used as + * predefined whitepoints for the 2° and the 10° observer. + * Whitepoint format: + * (x-white, y-white) for the 1931 2° observers + * (x-white, y-white) for the 1964 10° observer + * (x-white, y-white) for the Judd/Vos 2° observer + * You can also use kelvin temperatures to create custom-whitepoints + * by using the Blackbody2Whitepoint or Daylight2Whitepoint macros. + * + * Due to a revision of the Boltzmann constant we have the correlated + * Kelvin temperature for the daylight illuminants: (1.4388/1.4380)*D(K) + * D50 - 5002.78 K + * D55 - 5503.06 K + * D65 - 6503.62 K + * D75 - 7504.17 K + */ +#if (CIE_MultiObserver) +#declare Illuminant_A = array[3][2] { // blackbody 2856 K + {0.44753, 0.40744}, // 1931 2°observer + {0.45113, 0.40593}, // 1964 10°observer + {0.44927, 0.41273} // 1978 2°observer +} +#declare Illuminant_B = array[3][2] { // ca. blackbody 4871 K + {0.34849, 0.35173}, // 1931 2°observer + {0.34990, 0.35279}, // 1964 10°observer + {0.35189, 0.35853} // 1978 2°observer +} +#declare Illuminant_C = array[3][2] { // ca. blackbody 6774 K + {0.31006, 0.31616}, // 1931 2°observer + {0.31038, 0.31905}, // 1964 10°observer + {0.31373, 0.32291} // 1978 2°observer +} +#declare Illuminant_D50 = array[3][2] { // daylight 5002.78 K + {0.34566, 0.35850}, // 1931 2°observer + {0.34771, 0.35951}, // 1964 10°observer + {0.34919, 0.36560} // 1978 2°observer +} +#declare Illuminant_D55 = array[3][2] { // daylight 5503.06 K + {0.33242, 0.34744}, // 1931 2°observer + {0.33411, 0.34876}, // 1964 10°observer + {0.33587, 0.35417} // 1978 2°observer +} +#declare Illuminant_D65 = array[3][2] { // daylight 6503.62 K + {0.31271, 0.32902}, // 1931 2°observer + {0.31379, 0.33096}, // 1964 10°observer + {0.31598, 0.33502} // 1978 2°observer +} +#declare Illuminant_D75 = array[3][2] { // daylight 7504.17 K + {0.29903, 0.31487}, // 1931 2°observer + {0.29967, 0.31739}, // 1964 10°observer + {0.30216, 0.32027} // 1978 2°observer +} +#declare Illuminant_E = array[3][2] { // equal energy 5469 K + {1/3, 1/3}, // 1931 2°observer + {1/3, 1/3} // 1964 10°observer + {1/3, 1/3} // 1978 2°observer +} +#declare Illuminant_F1 = array[3][2] { // fluorescent 6430 K + {0.31306, 0.33711}, // 2°observer + {0.31810, 0.33549}, // 10°observer + {0.31690, 0.34431} // 2°observer +} +#declare Illuminant_F2 = array[3][2] { // fluorescent 4230 K + {0.37207, 0.37512}, // 2°observer + {0.37927, 0.36723}, // 10°observer + {0.37463, 0.38025} // 2°observer +} +#declare Illuminant_F3 = array[3][2] { // fluorescent 3450 K + {0.40909, 0.39412}, // 2°observer + {0.41764, 0.38312}, // 10°observer + {0.41055, 0.39782} // 2°observer +} +#declare Illuminant_F4 = array[3][2] { // fluorescent 2940 K + {0.43987, 0.40314}, // 2°observer + {0.44895, 0.39064}, // 10°observer + {0.44035, 0.40579} // 2°observer +} +#declare Illuminant_F5 = array[3][2] { // fluorescent 6350 K + {0.31376, 0.34516}, // 2°observer + {0.31974, 0.34236}, // 10°observer + {0.31749, 0.35215} // 2°observer +} +#declare Illuminant_F6 = array[3][2] { // fluorescent 4150 K + {0.37788, 0.38819}, // 2°observer + {0.38662, 0.37837}, // 10°observer + {0.38016, 0.39285} // 2°observer +} +#declare Illuminant_F7 = array[3][2] { // broad band fluorescent 6500 K + {0.31285, 0.32917}, // 2°observer + {0.31564, 0.32951}, // 10°observer + {0.31646, 0.33629} // 2°observer +} +#declare Illuminant_F8 = array[3][2] { // broad band fluorescent 5000 K + {0.34581, 0.35862}, // 2°observer + {0.34896, 0.35931}, // 10°observer + {0.34975, 0.36697} // 2°observer +} +#declare Illuminant_F9 = array[3][2] { // broad band fluorescent 4150 K + {0.37410, 0.37267}, // 2°observer + {0.37826, 0.37037}, // 10°observer + {0.37738, 0.37978} // 2°observer +} +#declare Illuminant_F10 = array[3][2] { // narrow band fluorescent 5000 K + {0.34579, 0.35876}, // 2°observer + {0.35061, 0.35430}, // 10°observer + {0.35014, 0.36779} // 2°observer +} +#declare Illuminant_F11 = array[3][2] { // narrow band fluorescent 4000 K + {0.38054, 0.37692}, // 2°observer + {0.38543, 0.37109}, // 10°observer + {0.38363, 0.38392} // 2°observer +} +#declare Illuminant_F12 = array[3][2] { // narrow band fluorescent 3000 K + {0.43702, 0.40421}, // 2°observer + {0.44265, 0.39706}, // 10°observer + {0.43752, 0.40780} // 2°observer +} + +#else + +#declare Illuminant_A = array[2] {0.44753,0.40744} // blackbody 2856 K +#declare Illuminant_B = array[2] {0.34849,0.35173} // ca. blackbody 4871 K +#declare Illuminant_C = array[2] {0.31006,0.31616} // ca. blackbody 6774 K +#declare Illuminant_D50 = array[2] {0.34566,0.35850} // daylight 5002.78 K +#declare Illuminant_D55 = array[2] {0.33242,0.34744} // daylight 5503.06 K +#declare Illuminant_D65 = array[2] {0.31271,0.32902} // daylight 6503.62 K +#declare Illuminant_D75 = array[2] {0.29903,0.31487} // daylight 7504.17 K +#declare Illuminant_E = array[2] {1/3, 1/3} // equal energy 5469 K +#declare Illuminant_F1 = array[2] {0.31306,0.33711} // fluorescent 6430 K +#declare Illuminant_F2 = array[2] {0.37207,0.37512} // fluorescent 4230 K +#declare Illuminant_F3 = array[2] {0.40909,0.39412} // fluorescent 3450 K +#declare Illuminant_F4 = array[2] {0.43987,0.40314} // fluorescent 2940 K +#declare Illuminant_F5 = array[2] {0.31376,0.34516} // fluorescent 6350 K +#declare Illuminant_F6 = array[2] {0.37788,0.38819} // fluorescent 4150 K +#declare Illuminant_F7 = array[2] {0.31285,0.32917} // broad band fluorescent 6500 K +#declare Illuminant_F8 = array[2] {0.34581,0.35862} // broad band fluorescent 5000 K +#declare Illuminant_F9 = array[2] {0.37410,0.37267} // broad band fluorescent 4150 K +#declare Illuminant_F10 = array[2] {0.34579,0.35876} // narrow band fluorescent 5000 K +#declare Illuminant_F11 = array[2] {0.38054,0.37692} // narrow band fluorescent 4000 K +#declare Illuminant_F12 = array[2] {0.43702,0.40421} // narrow band fluorescent 3000 K + +#end + + +/* Color System xy coordinates and whitepoints + * sRGB: CCIR Recommendation 709 (used by HP, Microsoft) + * CIE: CIE 'ideal' gamut where the corners are on the contour of the horseshoe + * ITU: CCIR Report 476-1 (YUV color order, Pal Secam, european tv) + * NTSC: CCIR Recommendation 601-1 (YIQ color order, american tv) + * SMPTE: CIE D65 + * Adobe: Adobe (Photoshop ICM) + * Match: Adobe ColorMatch (Photoshop ICM) + * Apple: Apple Monitor (Photoshop ICM) + * Beta: RGB working space created by Bruce Lindbloom + http://www.brucelindbloom.com/BetaRGB.html + * Dell phosphors: Dell data sheet + * Short-persistence phosphors: [Foley96, p.583] + * Long-persistence phosphors: [Foley96, p.583] + * HOT: Hydrogen, Oxygen, Thermal color space uses primaries found in deep space + * see http://www.nightscapes.net/techniques/HOTcolors/HOTColorSpace.html + * + * Color System format: + * (x-red, y-red), + * (x-green, y-green), + * (x-blue, y-blue), + * (x-white, y-white), whitepoint for 1931 2°observer + * (x-white, y-white), whitepoint for 1964 10°observer + * (x-white, y-white) whitepoint for 1978 2°observer (Judd/Vos) + */ +#if (CIE_MultiObserver) + +#declare sRGB_ColSys = array[6][2] { // <- initialized as default + {0.640, 0.330}, // red + {0.300, 0.600}, // green + {0.150, 0.060}, // blue + {0.31271,0.32902},// Illuminant D65 1931 observer + {0.31379,0.33096},// Illuminant D65 1964 + {0.31598,0.33502} // Illuminant D65 1978 +} +#declare CIE_ColSys = array[6][2] { + {0.7347, 0.2653}, // red + {0.2738, 0.7174}, // green + {0.1666, 0.0088}, // blue + {1/3, 1/3}, // Illuminant E 1931 observer + {1/3, 1/3}, // Illuminant E 1964 + {1/3, 1/3} // Illuminant E 1978 +} +#declare ITU_ColSys = array[6][2] { + {0.640, 0.330}, // red + {0.290, 0.600}, // green + {0.150, 0.060}, // blue + {0.31271,0.32902},// Illuminant D65 1931 observer + {0.31379,0.33096},// Illuminant D65 1964 + {0.31598,0.33502} // Illuminant D65 1978 +} +#declare NTSC_ColSys = array[6][2] { + {0.670, 0.330}, // red + {0.210, 0.710}, // green + {0.140, 0.080}, // blue + {0.31006,0.31616},// Illuminant C 1931 observer + {0.31038,0.31905},// Illuminant C 1964 + {0.31373,0.32291} // Illuminant C 1978 +} +#declare SMPTE_ColSys = array[6][2] { + {0.630, 0.340}, // red + {0.310, 0.595}, // green + {0.155, 0.070}, // blue + {0.31271,0.32902},// Illuminant D65 1931 observer + {0.31379,0.33096},// Illuminant D65 1964 + {0.31598,0.33502} // Illuminant D65 1978 +} +#declare Adobe_ColSys = array[6][2] { + {0.640, 0.330}, // red + {0.210, 0.710}, // green + {0.150, 0.060}, // blue + {0.31271,0.32902},// Illuminant D65 1931 observer + {0.31379,0.33096},// Illuminant D65 1964 + {0.31598,0.33502} // Illuminant D65 1978 +} +#declare Match_ColSys = array[6][2] { + {0.630, 0.340}, // red + {0.290, 0.610}, // green + {0.150, 0.075}, // blue + {0.34566,0.35850},// Illuminant D50 1931 observer + {0.34771,0.35951},// Illuminant D50 1964 + {0.34919,0.36560} // Illuminant D50 1978 +} +#declare Apple_ColSys = array[6][2] { + {0.630, 0.340}, // red + {0.280, 0.600}, // green + {0.160, 0.070}, // blue + {0.31271,0.32902},// Illuminant D65 1931 observer + {0.31379,0.33096},// Illuminant D65 1964 + {0.31598,0.33502} // Illuminant D65 1978 +} +#declare Beta_ColSys = array[6][2] { + {0.6888, 0.3112}, // red + {0.1986, 0.7551}, // green + {0.1265, 0.0352}, // blue + {0.34566,0.35850},// Illuminant D50 1931 observer + {0.34771,0.35951},// Illuminant D50 1964 + {0.34919,0.36560} // Illuminant D50 1978 +} +#declare Dell_ColSys = array[6][2] { + {0.625, 0.340}, // red + {0.275, 0.605}, // green + {0.150, 0.065}, // blue + {0.31271,0.32902},// Illuminant D65 1931 observer + {0.31379,0.33096},// Illuminant D65 1964 + {0.31598,0.33502} // Illuminant D65 1978 +} +#declare ShortPersistence_ColSys = array[6][2] { + {0.610, 0.350}, // red + {0.290, 0.590}, // green + {0.150, 0.063}, // blue + {0.31006,0.31616},// Illuminant C 1931 observer + {0.31038,0.31905},// Illuminant C 1964 + {0.31373,0.32291} // Illuminant C 1978 +} +#declare LongPersistence_ColSys = array[6][2] { + {0.620, 0.330}, // red + {0.210, 0.685}, // green + {0.150, 0.063}, // blue + {0.31006,0.31616},// Illuminant C 1931 observer + {0.31038,0.31905},// Illuminant C 1964 + {0.31373,0.32291} // Illuminant C 1978 +} +#declare HOT_ColSys = array[6][2] { + {0.7287, 0.2713}, // red + {0.0082, 0.5384}, // green + {0.1491, 0.0544}, // blue + {0.23991,0.23414},// infinite temperature 1931 observer + {0.23855,0.23873},// infinite temperature 1964 + {0.24141,0.23253} // infinite temperature 1978 +} + +#else //no MultiObserver + +/* Simplified version without the possibility to change the observer + * Color System format: + * (x-red, y-red), + * (x-green, y-green), + * (x-blue, y-blue), + * (x-white, y-white) whitepoint for 1931 2°observer + */ +#declare sRGB_ColSys = array[4][2] { // <- initialized as default + {0.640, 0.330}, // red + {0.300, 0.600}, // green + {0.150, 0.060}, // blue + {0.31271,0.32902} // Illuminant D65 +} +#declare CIE_ColSys = array[4][2] { + {0.7347, 0.2653}, // red + {0.2738, 0.7174}, // green + {0.1666, 0.0088}, // blue + {1/3, 1/3} // Illuminant E +} +#declare ITU_ColSys = array[4][2] { + {0.640, 0.330}, // red + {0.290, 0.600}, // green + {0.150, 0.060}, // blue + {0.31271,0.32902} // Illuminant D65 +} +#declare NTSC_ColSys = array[4][2] { + {0.670, 0.330}, // red + {0.210, 0.710}, // green + {0.140, 0.080}, // blue + {0.31006,0.31616} // Illuminant C +} +#declare SMPTE_ColSys = array[4][2] { + {0.630, 0.340}, // red + {0.310, 0.595}, // green + {0.155, 0.070}, // blue + {0.31271,0.32902} // Illuminant D65 +} +#declare Adobe_ColSys = array[4][2] { + {0.640, 0.330}, // red + {0.210, 0.710}, // green + {0.150, 0.060}, // blue + {0.31271,0.32902} // Illuminant D65 +} +#declare Match_ColSys = array[4][2] { + {0.630, 0.340}, // red + {0.290, 0.610}, // green + {0.150, 0.075}, // blue + {0.34566,0.35850} // Illuminant D50 +} +#declare Apple_ColSys = array[4][2] { + {0.630, 0.340}, // red + {0.280, 0.600}, // green + {0.160, 0.070}, // blue + {0.31271,0.32902} // Illuminant D65 +} +#declare Beta_ColSys = array[4][2] { + {0.6888, 0.3112}, // red + {0.1986, 0.7551}, // green + {0.1265, 0.0352}, // blue + {0.34566,0.35850} // Illuminant D50 +} +#declare Dell_ColSys = array[4][2] { + {0.625, 0.340}, // red + {0.275, 0.605}, // green + {0.150, 0.065}, // blue + {0.31271,0.32902} // Illuminant D65 +} +#declare ShortPersistence_ColSys = array[4][2] { + {0.610, 0.350}, // red + {0.290, 0.590}, // green + {0.150, 0.063}, // blue + {0.31006,0.31616} // Illuminant C +} +#declare LongPersistence_ColSys = array[4][2] { + {0.620, 0.330}, // red + {0.210, 0.685}, // green + {0.150, 0.063}, // blue + {0.31096,0.31616} // Illuminant C +} +#declare HOT_ColSys = array[4][2] { + {0.7287, 0.2713}, // red + {0.0082, 0.5384}, // green + {0.1491, 0.0544}, // blue + {0.23991,0.23414} // infinite temperature +} +#end //if MultiObserver + + +/* Chroma adaption matrices + * Scaling + * Von Kries + * Bradford + */ +#declare Scaling_MM = array[3][3] { // XYZ Scaling Chroma Match + {1.0, 0.0, 0.0}, + {0.0, 1.0, 0.0}, + {0.0, 0.0, 1.0} +} +#declare VonKries_MM = array[3][3] { // Von Kries Chroma Match + { 0.40024, 0.70760, -0.08081}, + {-0.22630, 1.16532, 0.04570}, + { 0.00000, 0.00000, 0.91822} +} +#declare Bradford_MM = array[3][3] { // Bradford Chroma Match + { 0.8951, 0.2664, -0.1614}, + {-0.7502, 1.7135, 0.0367}, + { 0.0389, -0.0685, 1.0296} +} + + +//===================================================================== +// CIE color system default settings +//===================================================================== + +/* definition for the color matching functions CMF + */ +#ifdef (CIE_MultiObserver) + #declare CIE_1931 = 0; + #declare CIE_1964 = 1; + #declare CIE_1978 = 2; +#end + +/* definition for chromatic adaption functions + */ +#declare Scaling_ChromaMatch = 1; +#declare VonKries_ChromaMatch = 2; +#declare Bradford_ChromaMatch = 3; + +/* hard coded and precalculated values + * these values are *local* so do not change them, if necessary they are + * automatical recalculated by using the appropriate macros + */ +#declare CIE_Spectrum = 0; // 1931 2° Observer +#declare xy_ColSys = sRGB_ColSys; // Color system +#declare ReferenceWhiteXY = Illuminant_D50; // reference white +#declare ReferenceWhiteXYZ = <0.96418, 1.0, 0.82522>;// XYZ for D50 CMF 1931 2° observer +#declare ChromaMatchFunction = Bradford_ChromaMatch; // chroma adaption function +#declare GamutMapFunction = 1; // clipping + +/* Color system dependent matrix for rgb->xyz and xyz->rgb + * conversion. Hard coded and pre-calculated for the sRGB + * color system, illuminant D65 and CIE 1931 2°standard + * observer (the default setting). + * CCIR recommendation 709 + */ +#declare csMatXYZ = array[3][3] { + { 0.48499, 0.34891, 0.13029}, + { 0.25007, 0.69781, 0.05211}, + { 0.02273, 0.11630, 0.68618} +} +#declare csMatRGB = array[3][3] { + { 3.24102,-1.53740,-0.49862}, + {-0.96922, 1.87593, 0.04155}, + { 0.05564,-0.20401, 1.05714} +} + +/* Adaption function dependent matrix for chroma matching + * Hard coded and pre-calculated for the Bradford match, + * reference white D50, 2° observer and sRGB color system + * with D65 + */ +#declare ChromaMatS = array[3][3] { + { 0.955565, -0.023045, 0.063180}, + {-0.028296, 1.009942, 0.021013}, + { 0.012301, -0.020488, 1.329995} +} +#declare ChromaMatD = array[3][3] { + { 1.047825, 0.022892, -0.050137}, + { 0.029550, 0.990484, -0.017053}, + {-0.009236, 0.015047, 0.752084} +} + + +//===================================================================== +// internal helper macros +//===================================================================== + +// convert a color component from the active color system to xyz +// where: z = 1 - x - y +// as the whitepoint depends on the CIE observer, it is also +// checked for the requested illuminant +#macro ColSys2xyz(Idx) + #if ((Idx>3)|(Idx<0)) #error "CIE.inc: Invalid ColSys index" #end + #if (CIE_MultiObserver & (Idx=3)) + #local Idx=Idx+CIE_Spectrum; + #end + #local X = xy_ColSys[Idx][0]; + #local Y = xy_ColSys[Idx][1]; + () +#end + + +// chroma match matrix calculation: M * [Xd/Xs Yd/Ys Zd/Zs] * Mi +#macro ApplyMatchMat(M, Vd, Vs) + #local V = ApplyMat(M,Vd)/ApplyMat(M,Vs); + #local D = array[3][3] { + {V.x, 0, 0}, + {0, V.y, 0}, + {0, 0, V.z}} + MultMat33(InvertMat33(M), MultMat33(D,M)) +#end + +#macro CreateChromaMat() + #local S = ReferenceWhiteXYZ; + #local D = xyz2XYZ(ColSys2xyz(3)); + + #switch (ChromaMatchFunction) + #case (Scaling_ChromaMatch) + #declare ChromaMatS = ApplyMatchMat(Scaling_MM, D,S); + #declare ChromaMatD = InvertMat33(ChromaMatS); + #break + #case (VonKries_ChromaMatch) + #declare ChromaMatS = ApplyMatchMat(VonKries_MM, D,S); + #declare ChromaMatD = InvertMat33(ChromaMatS); + #break + #case (Bradford_ChromaMatch) + #declare ChromaMatS = ApplyMatchMat(Bradford_MM, D,S); + #declare ChromaMatD = InvertMat33(ChromaMatS); + #break + #else + #declare ChromaMatS = Scaling_MM; + #declare ChromaMatD = Scaling_MM; + #end + + #if (CIE_Debug) + #debug "\n" + #debug "Source White\n" + #debug concat(str(S.x,2,5),", ",str(S.y,2,5),", ",str(S.z,2,5),"\n") + #debug "Destination White\n" + #debug concat(str(D.x,2,5),", ",str(D.y,2,5),", ",str(D.z,2,5),"\n") + #debug "\n" + #debug "Chroma Source Matrix\n" + #debug concat(str(ChromaMatS[0][0],2,6),", ",str(ChromaMatS[0][1],2,6),", ",str(ChromaMatS[0][2],2,6),"\n") + #debug concat(str(ChromaMatS[1][0],2,6),", ",str(ChromaMatS[1][1],2,6),", ",str(ChromaMatS[1][2],2,6),"\n") + #debug concat(str(ChromaMatS[2][0],2,6),", ",str(ChromaMatS[2][1],2,6),", ",str(ChromaMatS[2][2],2,6),"\n") + #debug "\n" + #debug "Chroma Destination Matrix\n" + #debug concat(str(ChromaMatD[0][0],2,6),", ",str(ChromaMatD[0][1],2,6),", ",str(ChromaMatD[0][2],2,6),"\n") + #debug concat(str(ChromaMatD[1][0],2,6),", ",str(ChromaMatD[1][1],2,6),", ",str(ChromaMatD[1][2],2,6),"\n") + #debug concat(str(ChromaMatD[2][0],2,6),", ",str(ChromaMatD[2][1],2,6),", ",str(ChromaMatD[2][2],2,6),"\n") + #end +#end + +#macro ChromaMatchSource(XYZ) + < ChromaMatS[0][0]*XYZ.x + ChromaMatS[0][1]*XYZ.y + ChromaMatS[0][2]*XYZ.z, + ChromaMatS[1][0]*XYZ.x + ChromaMatS[1][1]*XYZ.y + ChromaMatS[1][2]*XYZ.z, + ChromaMatS[2][0]*XYZ.x + ChromaMatS[2][1]*XYZ.y + ChromaMatS[2][2]*XYZ.z > +#end + +#macro ChromaMatchDest(XYZ) + < ChromaMatD[0][0]*XYZ.x + ChromaMatD[0][1]*XYZ.y + ChromaMatD[0][2]*XYZ.z, + ChromaMatD[1][0]*XYZ.x + ChromaMatD[1][1]*XYZ.y + ChromaMatD[1][2]*XYZ.z, + ChromaMatD[2][0]*XYZ.x + ChromaMatD[2][1]*XYZ.y + ChromaMatD[2][2]*XYZ.z > +#end + +//===================================================================== +// internal matrix helper macros +//===================================================================== +#macro ApplyMat(Mat,XYZ) // apply matrix transformation to 3d vector + < Mat[0][0]*XYZ.x + Mat[0][1]*XYZ.y + Mat[0][2]*XYZ.z, + Mat[1][0]*XYZ.x + Mat[1][1]*XYZ.y + Mat[1][2]*XYZ.z, + Mat[2][0]*XYZ.x + Mat[2][1]*XYZ.y + Mat[2][2]*XYZ.z > +#end + +#macro MultMat33(M1,M2) // multiply 2 3x3 matrices + #local I=0; + #local Mat = array[3][3]; + #while (I<3) + #local J=0; + #while (J<3) + #declare Mat[I][J] = 0; + #local K = 0; + #while (K<3) + #declare Mat[I][J] = Mat[I][J] + M1[I][K] * M2[K][J]; + #local K=K+1; + #end + #local J=J+1; + #end + #local I=I+1; + #end + Mat +#end + +#macro InvertMat33(M) // invert a 3x3 matrix + #local vX = ; + #local vY = ; + #local vZ = ; + #local Det = vdot(vX, vcross(vY, vZ)); + #local v0 = vcross(vY, vZ)/Det; + #local v1 = -vcross(vX, vZ)/Det; + #local v2 = vcross(vX, vY)/Det; + array[3][3] { + { v0.x, v1.x, v2.x } + { v0.y, v1.y, v2.y } + { v0.z, v1.z, v2.z } + } +#end + + +//===================================================================== +// Select the CIE observer. +// possible values are +// CIE_1931 (2° observer) +// CIE_1964 (10° observer) +// CIE_1978 (2° observer modified by Judd/Vos) +//===================================================================== +#if (CIE_MultiObserver) +#macro CIE_Observer(S) + #if (S!=CIE_Spectrum) // need for recalculation + #if ((S<0)|(S>2)) #error "CIE.inc: invalid observer selected" #end + #declare CIE_Spectrum = S; + #declare CMF_xyz = spline { cubic_spline + 375, <0,0,0> + #local I=0; + #while (I<90) 380+I*5, CMF_table[I][S] #local I=I+1; #end + 830, <0,0,0> + } + CIE_ReferenceWhite(ReferenceWhiteXY) // also ReferenceWhite has changed + #end // this forces the recalculation of +#end // the chroma matrices +#end // if MultiObserver + + +//===================================================================== +// Change the reference whitepoint for the CIE observer. +// Usually there is no need to do this because all common applications +// color management systems and spectrometer do work with D50 which is +// also here the default setting. +// AND DO NOT CONFUSE THIS WITH THE COLOR SYSTEM WHITEPOINT! +//===================================================================== + +#macro CIE_ReferenceWhite(RW) + + #if (CIE_MultiObserver) + #macro IlluID(I) + I[0][0]+I[0][1] + #end + #else + #macro IlluID(I) + I[0]+I[1] + #end + #end + + #macro CreateRefWhite_D(K) + #local M1=0; #local M2=0; + DaylightM1M2((1.4388/1.4380)*K,M1,M2) + #declare RefWhiteSP = spline{ linear_spline + #local I=0; + #while (I<77) + 380+I*5, (DS012[I][0]+M1*DS012[I][1]+M2*DS012[I][2])/100 + #local I=I+1; + #end + } + #end + + #macro CreateRefWhite_A() + #local D=PlanckBlackBody(560*1e-9, 2856); + #declare RefWhiteSP = spline{ linear_spline + #local I=0; + #while (I<77) + #local WL = 380+I*5; + WL, PlanckBlackBody(WL*1e-9, 2856)/D + #local I=I+1; + #end + } + #end + + #switch (IlluID(RW)) + #case (IlluID(Illuminant_A)) + CreateRefWhite_A() + #break + #case (IlluID(Illuminant_B)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_B; + #break + #case (IlluID(Illuminant_C)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_C; + #break + #case (IlluID(Illuminant_D50)) + CreateRefWhite_D(5000) + #break + #case (IlluID(Illuminant_D55)) + CreateRefWhite_D(5500) + #break + #case (IlluID(Illuminant_D65)) + CreateRefWhite_D(6500) + #break + #case (IlluID(Illuminant_D75)) + CreateRefWhite_D(7500) + #break + #case (IlluID(Illuminant_E)) + #declare RefWhiteSP = spline{linear_spline 360, 1.0 830, 1.0} + #break + #case (IlluID(Illuminant_F1)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F1; + #break + #case (IlluID(Illuminant_F2)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F2; + #break + #case (IlluID(Illuminant_F3)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F3; + #break + #case (IlluID(Illuminant_F4)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F4; + #break + #case (IlluID(Illuminant_F5)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F5; + #break + #case (IlluID(Illuminant_F6)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F6; + #break + #case (IlluID(Illuminant_F7)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F7; + #break + #case (IlluID(Illuminant_F8)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F8; + #break + #case (IlluID(Illuminant_F9)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F9; + #break + #case (IlluID(Illuminant_F10)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F10; + #break + #case (IlluID(Illuminant_F11)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F11; + #break + #case (IlluID(Illuminant_F12)) + #include "espd_cie_standard.inc" + #declare RefWhiteSP = ES_Illuminant_F12; + #break + #else + #error "CIE.inc: Invalid CIE reference white selected" + #end + #if (CIE_MultiObserver) + #local X = RW[CIE_Spectrum][0]; + #local Y = RW[CIE_Spectrum][1]; + #else + #local X = RW[0]; + #local Y = RW[1]; + #end + #declare ReferenceWhiteXY = RW; + #declare ReferenceWhiteXYZ = ; + CreateChromaMat() // update the chromatic adaption matrices + CIE_ColorSystem(xy_ColSys) // we need also a new rgb->xyz transformation matrix +#end + + +//===================================================================== +// select the chroma matching function +// possible values are +// Scaling_ChromaMatch +// VonKries_ChromaMatch +// Bradford_ChromaMatch +// or false/off/0 to switch it completely off +//===================================================================== +#macro CIE_ChromaticAdaption(Match) + #if (Match!=ChromaMatchFunction) + #if (ChromaMatchFunction>3) + #error "CIE.inc: Invalid chromatic adaption selected" + #end + #declare ChromaMatchFunction = Match; + CreateChromaMat() + #end +#end + + +//===================================================================== +// select the gamut mapping function for xyz->rgb conversion +// 0/off/false: no mapping +// 1: clipping +// 2: triangle intersection in rgb space +//===================================================================== +#macro CIE_GamutMapping(GM) + #declare GamutMapFunction = GM; +#end + + +//===================================================================== +// Select a color/device system and create the required transformation +// matrix +//===================================================================== +#macro CIE_ColorSystem(CS) +// first check if a recalculation of the chroma matrices is required + #local Idx=3+CIE_Spectrum; + #if ((xy_ColSys[Idx][0]!=CS[Idx][0]) | (xy_ColSys[Idx][1]!=CS[Idx][1])) + #declare xy_ColSys = CS; // set new color system + CreateChromaMat() // calculate chroma matrices + #else + #declare xy_ColSys = CS; // just set the active new color system + #end +// copy into local vars + #local XR = CS[0][0]; #local YR = CS[0][1]; #local ZR = 1-(XR+YR); + #local XG = CS[1][0]; #local YG = CS[1][1]; #local ZG = 1-(XG+YG); + #local XB = CS[2][0]; #local YB = CS[2][1]; #local ZB = 1-(XB+YB); + #local XW = CS[Idx][0]; #local YW = CS[Idx][1]; +// UV-W coordinates + #local D = (XR-XB)*(YG-YB)-(YR-YB)*(XG-XB); + #local U = (XW-XB)*(YG-YB)-(YW-YB)*(XG-XB); + #local V = (XR-XB)*(YW-YB)-(YR-YB)*(XW-XB); + #local U = U/D; #local V = V/D; #local W = 1-(U+V); + #local U = U/YW; #local V = V/YW; #local W = W/YW; +// rgb->xyz matrix + #declare csMatXYZ[0][0]=U*XR; #declare csMatXYZ[0][1]=V*XG; #declare csMatXYZ[0][2]=W*XB; + #declare csMatXYZ[1][0]=U*YR; #declare csMatXYZ[1][1]=V*YG; #declare csMatXYZ[1][2]=W*YB; + #declare csMatXYZ[2][0]=U*ZR; #declare csMatXYZ[2][1]=V*ZG; #declare csMatXYZ[2][2]=W*ZB; +// the xyz-rgb matrix is the invert of the rgb-xyz matrix + #declare csMatRGB = InvertMat33(csMatXYZ) + +// the special matrix for rgb->rgb conversion + #if (CIE_MultiObserver) + #local XW = ReferenceWhiteXY[CIE_Spectrum][0]; + #local YW = ReferenceWhiteXY[CIE_Spectrum][1]; + #else + #local XW = ReferenceWhiteXY[0]; + #local YW = ReferenceWhiteXY[1]; + #end + #if ((XW!=CS[Idx][0]) & (YW!=CS[Idx][1])) + #local U = (XW-XB)*(YG-YB)-(YW-YB)*(XG-XB); + #local V = (XR-XB)*(YW-YB)-(YR-YB)*(XW-XB); + #local U = U/D; #local V = V/D; #local W = 1-(U+V); + #local U = U/YW; #local V = V/YW; #local W = W/YW; +// new rgb->xyz matrix + #declare csMatXYZ[0][0]=U*XR; #declare csMatXYZ[0][1]=V*XG; #declare csMatXYZ[0][2]=W*XB; + #declare csMatXYZ[1][0]=U*YR; #declare csMatXYZ[1][1]=V*YG; #declare csMatXYZ[1][2]=W*YB; + #declare csMatXYZ[2][0]=U*ZR; #declare csMatXYZ[2][1]=V*ZG; #declare csMatXYZ[2][2]=W*ZB; + #end + + #if (CIE_Debug) + #debug "\n" + #if (CIE_MultiObserver) + #switch (CIE_Spectrum) + #case (CIE_1931) #debug "CIE 1931 2 degree observer\n" #break + #case (CIE_1964) #debug "CIE 1964 10 degree observer\n" #break + #case (CIE_1978) #debug "CIE 1931 2 degree observer (mod. Judd/Vos 1978)\n" #break + #end + #else + #debug "CIE 1931 2 degree observer\n" + #end + #debug "\n" + #debug "color system\n" + #debug " x y\n" + #debug concat("red ",str(xy_ColSys[0][0],1,4)," ",str(xy_ColSys[0][1],1,4),"\n") + #debug concat("green ",str(xy_ColSys[1][0],1,4)," ",str(xy_ColSys[1][1],1,4),"\n") + #debug concat("blue ",str(xy_ColSys[2][0],1,4)," ",str(xy_ColSys[2][1],1,4),"\n") + #debug concat("white ",str(xy_ColSys[3+CIE_Spectrum][0],1,5)," ",str(xy_ColSys[3+CIE_Spectrum][1],1,5)) + #debug "\n\n" + #debug "rgb-xyz conversion matrix\n" + #debug concat(str(csMatXYZ[0][0],2,5),", ",str(csMatXYZ[0][1],2,5),", ",str(csMatXYZ[0][2],2,5),"\n") + #debug concat(str(csMatXYZ[1][0],2,5),", ",str(csMatXYZ[1][1],2,5),", ",str(csMatXYZ[1][2],2,5),"\n") + #debug concat(str(csMatXYZ[2][0],2,5),", ",str(csMatXYZ[2][1],2,5),", ",str(csMatXYZ[2][2],2,5),"\n") + #debug "\n" + #debug "xyz-rgb conversion matrix\n" + #debug concat(str(csMatRGB[0][0],2,5),", ",str(csMatRGB[0][1],2,5),", ",str(csMatRGB[0][2],2,5),"\n") + #debug concat(str(csMatRGB[1][0],2,5),", ",str(csMatRGB[1][1],2,5),", ",str(csMatRGB[1][2],2,5),"\n") + #debug concat(str(csMatRGB[2][0],2,5),", ",str(csMatRGB[2][1],2,5),", ",str(csMatRGB[2][2],2,5),"\n") + #end // if debug +#end + + +//===================================================================== +// Select a color/device system but change also the whitepoint to any +// non default value. +// The color system with the new illuminant is also activated! +//===================================================================== +#if (CIE_MultiObserver) + +#macro CIE_ColorSystemWhitepoint(CS,WP) + #declare NewCS = CS; // do not overwrite the original one + #declare NewCS[3][0] = WP[0][0]; + #declare NewCS[3][1] = WP[0][1]; + #declare NewCS[4][0] = WP[1][0]; + #declare NewCS[4][1] = WP[1][1]; + #declare NewCS[5][0] = WP[2][0]; + #declare NewCS[5][1] = WP[2][1]; + CIE_ColorSystem(NewCS) // activate +#end + +#else + +#macro CIE_ColorSystemWhitepoint(CS,WP) + #declare NewCS = CS; // do not overwrite the original one + #declare NewCS[3][0] = WP[0]; + #declare NewCS[3][1] = WP[1]; + CIE_ColorSystem(NewCS) // activate +#end + +#end + + +//========================================================= +// xyz <-> XYZ conversion +//========================================================= + +#macro xyz2XYZ(XYZ) + +#end + +#macro XYZ2xyz(XYZ) + #local Y = 1/(XYZ.x+XYZ.z+1); + +#end + + +//========================================================= +// xyz <-> xyY conversion +//========================================================= + +#macro xyz2xyY(XYZ) + #local Sum = XYZ.x + XYZ.y + XYZ.z; +// note to myself: +// if Sum=0 then x and y should correspondent +// to the color system whitepoint! +// Is this possible for (synthetical) colors? +// Maybe I should check this here and set x/y in the correct +// way to avoid the division by 0 ??? + +#end + +#macro xyY2xyz(xyY) // xyY.z = Y !!! + #local Yy = xyY.z/xyY.y; + +#end + + +//========================================================= +// xyz <-> rgb conversion +// Note: +// xyz->rgb transformation uses reference white +// rgb->xyz transformation uses color system whitepoint +//========================================================= +// convert RGB to xyz by using the pre calculated transformation +// matrix csMatXYZ. +#macro RGB2xyz(RGB) + < csMatXYZ[0][0]*RGB.red + csMatXYZ[0][1]*RGB.green + csMatXYZ[0][2]*RGB.blue, + csMatXYZ[1][0]*RGB.red + csMatXYZ[1][1]*RGB.green + csMatXYZ[1][2]*RGB.blue, + csMatXYZ[2][0]*RGB.red + csMatXYZ[2][1]*RGB.green + csMatXYZ[2][2]*RGB.blue > +#end + +// convert xyz to RGB by using the pre calculated transformation +// matrix csMatRGB. +// note that the resulting RGB components can be negative if they are +// not within the gamut as defined by the current color system +#macro xyz2RGB(XYZ) + < csMatRGB[0][0]*XYZ.x + csMatRGB[0][1]*XYZ.y + csMatRGB[0][2]*XYZ.z, + csMatRGB[1][0]*XYZ.x + csMatRGB[1][1]*XYZ.y + csMatRGB[1][2]*XYZ.z, + csMatRGB[2][0]*XYZ.x + csMatRGB[2][1]*XYZ.y + csMatRGB[2][2]*XYZ.z > +#end + + +// gray mapping feature +// input from: +// 0.0 - full rgb colors to 1.0 - grayscale +#macro CIE_Saturation(S) + #undef xyz2RGB + #switch (S) + #case (1) + #macro xyz2RGB(XYZ) + < csMatRGB[0][0]*XYZ.x + csMatRGB[0][1]*XYZ.y + csMatRGB[0][2]*XYZ.z, + csMatRGB[1][0]*XYZ.x + csMatRGB[1][1]*XYZ.y + csMatRGB[1][2]*XYZ.z, + csMatRGB[2][0]*XYZ.x + csMatRGB[2][1]*XYZ.y + csMatRGB[2][2]*XYZ.z > + #end #break + #case (0) + #macro xyz2RGB(XYZ) + < XYZ.y, XYZ.y, XYZ.y > + #end #break + #else + #if ((S>1)|(S<0)) #error "CIE.inc: saturation range is 0.0 .. 1.0" #end + #declare CIE_SaturationValue = S; + #macro xyz2RGB(XYZ) + (< csMatRGB[0][0]*XYZ.x + csMatRGB[0][1]*XYZ.y + csMatRGB[0][2]*XYZ.z, + csMatRGB[1][0]*XYZ.x + csMatRGB[1][1]*XYZ.y + csMatRGB[1][2]*XYZ.z, + csMatRGB[2][0]*XYZ.x + csMatRGB[2][1]*XYZ.y + csMatRGB[2][2]*XYZ.z >*(CIE_SaturationValue) + + < XYZ.y, XYZ.y, XYZ.y >*(1-CIE_SaturationValue) ) + #end + #end +#end + +//========================================================= +// rgb->xyz->rgb conversion +// even if this sounds strange this macro can be used to +// transform a rgb color in the same way as reflective +// spectra. The input value can be seen as reference rgb +// and is illuminated by reference white and the output +// rgb is modified in case the color system whitepoint +// is different. +//========================================================= +#macro ReferenceRGB(RGB) + MapGamut(xyz2RGB(ChromaMatchSource(RGB2xyz(RGB)))) +#end + +#macro ReferenceRGB2RGB(RGB) + xyz2RGB(ChromaMatchSource(RGB2xyz(RGB))) +#end + + +//========================================================= +// xyY <-> rgb conversion +//========================================================= +#macro RGB2xyY(RGB) + xyz2xyY(RGB2xyz(RGB)) +#end + +#macro xyY2RGB(xyY) + xyz2RGB(xyY2xyz(xyY)) +#end + + +//========================================================= +// Lab/Lch<->xyz<->rgb conversion +// The luminance mapping is composed of two functions but +// shows a discontinuity at the junction point. +// So there is a new (April 2003) draft from the CIE to use +// e = 216/24389 instead of 0.008856 +// k = 24389/27 instead of 903.3 +//========================================================= +#macro xyz2Lab(XYZ) + #local E = 216/24389; + #local J = 16/116; + #local C = ChromaMatchDest(XYZ)/ReferenceWhiteXYZ; + #if (C.y > E) + #local F = pow(C.y,1/3); + #local L = 116*F-16; + #else + #local F = 7.787*C.y+J; + #local L = (24389/27)*C.y; + #end + < L, + 500*((C.x>E ? pow(C.x,1/3) : 7.787*C.x+J) - F), + 200*(F - (C.z>E ? pow(C.z,1/3) : 7.787*C.z+J)) > +#end + +#macro Lab2xyz(Lab) + #local E = 216/24389; + #local J = 16/116; + #local Y = (Lab.x +16) / 116; + #local X = Lab.y/500 + Y; + #local Z = Y - Lab.z/200; + #local powX = pow(X,3); + #local powY = pow(Y,3); + #local powZ = pow(Z,3); + #local X = (powX>E ? powX : (X-J) / 7.787); + #local Y = (powY>E ? powY : (Y-J) / 7.787); + #local Z = (powZ>E ? powZ : (Z-J) / 7.787); + (ChromaMatchSource(*ReferenceWhiteXYZ)) +#end + +#macro Lab2Lch(Lab) + ), (#if (abs(Lab.z)<1e-9) 0 #else atan2(Lab.z, Lab.y) #end) > +#end + +#macro Lch2Lab(Lch) + +#end + +#macro xyz2Lch(XYZ) + Lab2Lch(xyz2Lab(XYZ)) +#end + +#macro Lch2xyz(Lch) + Lab2xyz(Lch2Lab(Lch)) +#end + +#macro RGB2Lab(RGB) + xyz2Lab(RGB2xyz(RGB)) +#end + +#macro Lab2RGB(Lab) + xyz2RGB(Lab2xyz(Lab)) +#end + +#macro RGB2Lch(RGB) + Lab2Lch(RGB2Lab(RGB)) +#end + +#macro Lch2RGB(Lch) + Lab2RGB(Lch2Lab(Lch)) +#end + + +//===================================================================== +// Gamut mapping is a kind of science for itself but here it's +// done in a quite simple way. +// In some cases method 2 gives better results but in some others it is +// even less accurate than just clipping the negative rgb color values. +//===================================================================== +#macro MapGamut(RGB_Input) + #local RGB = RGB_Input; + #if (min(RGB.red, RGB.green, RGB.blue) < 0.0) + // Outside of the gamut, a little more work to do! + #switch (GamutMapFunction) + // 0 and any other: do not map + #case (1) + // clip the negative values + #if (RGB.red<0) #local RGB = <0, RGB.green, RGB.blue>; #end + #if (RGB.green<0) #local RGB = ; #end + #if (RGB.blue<0) #local RGB = ; #end + #break + #case (2) + // We need the RGB value for the whitepoint (and this point has to + // be inside) and calculate the intersection with the edge of the + // maxwell triangle (the gamut as set by the active color system) + // by a (fictive) line defined by our RGB value and the location + // of the whitepoint. + #local W = xyz2RGB(ColSys2xyz(3)); // RGB for the colsys whitepoint + #if ((RGB.red < RGB.green) & (RGB.red < RGB.blue)) + #local P = W.red / (W.red - RGB.red); + #else + #if ((RGB.green < RGB.red) & (RGB.green < RGB.blue)) + #local P = W.green / (W.green - RGB.green); + #else + #local P = W.blue / (W.blue - RGB.blue); + #end + #end + // finally calculate the desaturated gamut-constrained RGB weights + #local RGB = ; + #break + #case (3) + // another try on gamut mapping by just desaturating the RGB color + #local W = -min(0,RGB.red,RGB.green,RGB.blue); + #local RGB = /(1+W); + #break + #end // switch + #end + (RGB) +#end + +#macro MapGamutNorm(RGB_Input) + #local RGB = MapGamut(RGB_Input); + (RGB/max(RGB.red, RGB.green, RGB.blue)) +#end + + +//===================================================================== +// Wavelength conversion +// Wavelength to xyz color space aproximation by using the cubic interpolated +// CMF as lookup table where the "border" of the *visible* color space is +// defined in xy coordinates. +//===================================================================== +#macro Wavelength2xyz(W) + CMF_xyz(min(825,max(380,W))) +#end + +#macro Wavelength(W) + #if ((W<380)|(W>825)) // Outside of the spectral data range + #local RGB = <0,0,0>; + #else + #local RGB = MapGamutNorm(xyz2RGB(CMF_xyz(W))); + #end + (RGB) +#end + +#macro Wavelength2RGB(W) + #if ((W<380)|(W>825)) + #local RGB = <0,0,0>; + #else + #local RGB = xyz2RGB(CMF_xyz(W)); + #end + (RGB) +#end + +#macro Wavelength2Lab(W) + #if ((W<380)|(W>825)) + #local Lab = <0,0,0>; + #else + #local Lab = xyz2Lab(CMF_xyz(W)); + #end + (Lab) +#end + +#macro Wavelength2Lch(W) + #if ((W<380)|(W>825)) + #local Lch = <0,0,0>; + #else + #local Lch = xyz2Lch(CMF_xyz(W)); + #end + (Lch) +#end + + +//===================================================================== +// Reflective spectrum calculation +//===================================================================== +// converts a given reflectance spectrum to xyz +// this is the basic function and should not be +// used directly because no chroma match is applied +#macro ReflectanceXYZ(S) + // calculations based on spreadsheet available at: + // http://www.digitalcolour.org/understanding/ + #local W=380; + #local XYZ=<0,0,0>; + #local CMy=0; + #while (W<=760) + #local CM = CMF_xyz(W); + #local RW = RefWhiteSP(W).y; + #local CMy = CMy + CM.y*RW; + #local XYZ = XYZ + CM*S(W).y*RW; + #local W=W+CIE_IntegralStep; + #end + (XYZ/CMy) +#end + +// reflectance spectrum to xyz +#macro Reflective2xyz(S) + ChromaMatchSource(ReflectanceXYZ(S)) +#end + +// converts to gamut mapped RGB +#macro ReflectiveSpectrum(S) + MapGamut(xyz2RGB(ChromaMatchSource(ReflectanceXYZ(S)))) +#end + +// converts to RGB +#macro Reflective2RGB(S) + xyz2RGB(ChromaMatchSource(ReflectanceXYZ(S))) +#end + +// no chroma mapping for Lab and Lch ! +// converts to Lab +#macro Reflective2Lab(S) + #local C = ReflectanceXYZ(S)/ReferenceWhiteXYZ; + #local E = 216/24389; + #local J = 16/116; + #if (C.y > E) + #local F = pow(C.y,1/3); + #local L = 116*F-16; + #else + #local F = 7.787*C.y+J; + #local L = (24389/27)*C.y; + #end + < L, + 500*((C.x>E ? pow(C.x,1/3) : 7.787*C.x+J) - F), // a + 200*(F - (C.z>E ? pow(C.z,1/3) : 7.787*C.z+J)) > // b +#end + +// converts to Lch +#macro Reflective2Lch(S) + Lab2Lch(Reflective2Lab(S)) +#end + + +//===================================================================== +// Emissive spectrum calculation +//===================================================================== +#macro Emissive2xyz(S) + #local W=380; + #local XYZ=<0,0,0>; + #while (W<=760) // integrate over spectrum data + #local XYZ = XYZ + CMF_xyz(W)*S(W).y; + #local W=W+CIE_IntegralStep; + #end + (XYZ/(XYZ.x+XYZ.y+XYZ.z)) +#end + +// converts a given spectrum to gamut mapped RGB +#macro EmissiveSpectrum(S) + MapGamutNorm(xyz2RGB(Emissive2xyz(S))) +#end + +// converts a given spectrum to RGB +#macro Emissive2RGB(S) + xyz2RGB(Emissive2xyz(S)) +#end + +// converts a given spectrum to Lab +#macro Emissive2Lab(S) + xyz2Lab(Emissive2xyz(S)) +#end + +// converts a given spectrum to Lch +#macro Emissive2Lch(S) + xyz2Lch(Emissive2xyz(S)) +#end + + +//===================================================================== +// Line spectrum calculation +//===================================================================== +#macro LineSpectrum2xyz(LS, Ion) + #local N = dimension_size(LS,1); + #local K = 0; + #local CMy = 0; + #local XYZ = <0,0,0>; + #while (K < N) + #if (LS[K][2]<=(Ion)) // check for ionization + #local CMy = CMy+CMF_xyz(LS[K][0]).y; + #local XYZ = XYZ + CMF_xyz(LS[K][0])*(LS[K][1]/1000); + #end + #local K=K+1; + #end + (XYZ/CMy) +#end + +#macro LineSpectrum(LS, Ion) + MapGamutNorm(xyz2RGB(LineSpectrum2xyz(LS,Ion))) +#end + +#macro LineSpectrum2RGB(LS, Ion) + xyz2RGB(LineSpectrum2xyz(LS,Ion)) +#end + +#macro LineSpectrum2Lab(LS, Ion) + xyz2Lab(LineSpectrum2xyz(LS,Ion)) +#end + +#macro LineSpectrum2Lch(LS, Ion) + xyz2Lch(LineSpectrum2xyz(LS,Ion)) +#end + +//===================================================================== +// Combine two or more line spectra +//===================================================================== +/* + EXAMPLE: + + #declare Lspd_Mix = array[4] { + LS_Neon, + LS_Neon, + LS_Argon, + LS_Xenon + } + #declare F_Mix = array[4][2] { + {0.80, 2}, // 80% Neon two electrons lost + {0.15, 1}, // 15% Neon one electron lost + {0.04, 2}, // 4% Argon + {0.01, 2} // 1% Xenon + } + #declare GasColor = LineSpectrumMix(Lspd_Mix, F_Mix); +*/ + +#macro LineSpectrumMix2xyz(LS,LF) + #local NE = dimension_size(LS,1); + #local E = 0; + #local XYZ = <0,0,0>; + #while (E; + #while (W<=760) + #local XYZ = XYZ + CMF_xyz(W)*PlanckBlackBody(W*1e-9, K); + #local W=W+5; + #end + (XYZ/(XYZ.x+XYZ.y+XYZ.z)) +#end + +#macro Blackbody(K) + MapGamutNorm(xyz2RGB(Blackbody2xyz(K))) +#end + +#macro Blackbody2RGB(K) + xyz2RGB(Blackbody2xyz(K)) +#end + +#macro Blackbody2Lab(K) + xyz2Lab(Blackbody2xyz(K)) +#end + +#macro Blackbody2Lch(K) + xyz2Lch(Blackbody2xyz(K)) +#end + +//===================================================================== +// Illuminant D daylight conversion using S0, S1, S2 (implemented as +// DS012 lookup table) to calculate (ideal) daylight spectra and then +// integrate in the same way as any other emissive spectrum. +//===================================================================== +#macro DaylightM1M2(K,M1,M2) + #if ((K<4000)|(K>25000)) + #error "CIE.inc: K is limited to the range of 4000-25000 Kelvin (use Blackbody instead)" + #end + #if (K<=7000) + #local X = -4.6070e9/pow(K,3) + 2.9678e6/pow(K,2) + 0.09911e3/K + 0.244063; + #else + #local X = -2.0064e9/pow(K,3) + 1.9018e6/pow(K,2) + 0.24748e3/K + 0.237040; + #end + #local Y = -3.0*(X*X) + 2.87*X - 0.275; + #local I = (0.0241 + 0.2562*X - 0.7341*Y); + #local M1 = (-1.3515 - 1.7703*X + 5.9114*Y) / I; + #local M2 = ( 0.03 -31.4424*X +30.0717*Y) / I; +#end + +#macro Daylight2xyz(K) + #local M1=0; #local M2=0; + DaylightM1M2(K,M1,M2) + #local I=0; + #local W=380; + #local XYZ = <0,0,0>; + #while (W<=760) + #local XYZ = XYZ + CMF_xyz(W)*(DS012[I][0]+M1*DS012[I][1]+M2*DS012[I][2]); + #local W=W+5; + #local I=I+1; + #end + (XYZ/(XYZ.x+XYZ.y+XYZ.z)) +#end + +#macro Daylight(K) + MapGamutNorm(xyz2RGB(Daylight2xyz(K))) +#end + +#macro Daylight2RGB(K) + xyz2RGB(Daylight2xyz(K)) +#end + +#macro Daylight2Lab(K) + xyz2Lab(Daylight2xyz(K)) +#end + +#macro Daylight2Lch(K) + xyz2Lch(Daylight2xyz(K)) +#end + + +//===================================================================== +// Custom whitepoint calculation based on blackbody temperature +//===================================================================== +#if (CIE_MultiObserver) + +#macro Blackbody2Whitepoint(K) +//calculate for all observer + #local W=380; + #local I=0; + #local XYZ31=<0,0,0>; + #local XYZ64=<0,0,0>; + #local XYZ78=<0,0,0>; + #while (W<=760) + #local BB = PlanckBlackBody(W*1e-9, K); + #local XYZ31 = XYZ31 + (CMF_table[I][0]*BB); + #local XYZ64 = XYZ64 + (CMF_table[I][1]*BB); + #local XYZ78 = XYZ78 + (CMF_table[I][2]*BB); + #local I=I+1; + #local W=W+5; + #end + #local XYZ31 = xyz2xyY(XYZ31); + #local XYZ64 = xyz2xyY(XYZ64); + #local XYZ78 = xyz2xyY(XYZ78); +// the result + array[3][2] { + {XYZ31.x, XYZ31.y} + {XYZ64.x, XYZ64.y} + {XYZ78.x, XYZ78.y} + } +#end + +#else //no MultiObserver + +#macro Blackbody2Whitepoint(K) + #local W=380; + #local XYZ=<0,0,0>; + #while (W<=760) + #local XYZ = XYZ + (CMF_xyz(W)*PlanckBlackBody(W*1e-9, K)); + #local W=W+5; + #end + #local XYZ = xyz2xyY(XYZ); +// the result + array[2] {XYZ.x, XYZ.y} +#end + +#end //if MultiObserver + + +//===================================================================== +// Custom whitepoint calculation based on D illuminant recommendation +//===================================================================== + +#if (CIE_MultiObserver) + +#macro Daylight2Whitepoint(K) + #local M1=0; #local M2=0; DaylightM1M2(K,M1,M2) + #local I=0; + #local XYZ31=<0,0,0>; + #local XYZ64=<0,0,0>; + #local XYZ78=<0,0,0>; + #while (I<90) + #local S = DS012[I][0] + M1*DS012[I][1] + M2*DS012[I][2]; + #local XYZ31 = XYZ31 + (CMF_table[I][0]*S); + #local XYZ64 = XYZ64 + (CMF_table[I][1]*S); + #local XYZ78 = XYZ78 + (CMF_table[I][2]*S); + #local I=I+1; + #end + #local XYZ31 = xyz2xyY(XYZ31); + #local XYZ64 = xyz2xyY(XYZ64); + #local XYZ78 = xyz2xyY(XYZ78); +// the result + array[3][2] { + {XYZ31.x, XYZ31.y} + {XYZ64.x, XYZ64.y} + {XYZ78.x, XYZ78.y} + } +#end + +#else //no MultiObserver + +#macro Daylight2Whitepoint(K) + #local M1=0; #local M2=0; DaylightM1M2(K,M1,M2) + #local I=0; + #local XYZ=<0,0,0>; + #while (I<90) + #local XYZ = XYZ + (CMF_xyz(380+I*5)*(DS012[I][0] + M1*DS012[I][1] + M2*DS012[I][2])); + #local I=I+1; + #end + #local XYZ = xyz2xyY(XYZ); +// the result + array[2] {XYZ.x, XYZ.y} +#end + +#end //if MultiObserver + + +//===================================================================== +// This one is only added to precalculate the whitepoints from the +// spectra in espd_cie_standard.inc +//===================================================================== + +#if (CIE_MultiObserver) + +#macro Illuminant2Whitepoint(ES) + #local I=0; + #local XYZ31=<0,0,0>; + #local XYZ64=<0,0,0>; + #local XYZ78=<0,0,0>; + #while (I<77) + #local S = ES(380+I*5).y; + #local XYZ31 = XYZ31 + CMF_table[I][0]*S; + #local XYZ64 = XYZ64 + CMF_table[I][1]*S; + #local XYZ78 = XYZ78 + CMF_table[I][2]*S; + #local I=I+1; + #end + #local XYZ31 = xyz2xyY(XYZ31); + #local XYZ64 = xyz2xyY(XYZ64); + #local XYZ78 = xyz2xyY(XYZ78); + array[3][2] { + {XYZ31.x, XYZ31.y} + {XYZ64.x, XYZ64.y} + {XYZ78.x, XYZ78.y} + } +#end + +#else + +#macro Illuminant2Whitepoint(ES) + #local I=0; + #local XYZ=<0,0,0>; + #while (I<77) + #local XYZ = XYZ + CMF_xyz(380+I*5)*ES(380+I*5).y; + #local I=I+1; + #end + #local XYZ = xyz2xyY(XYZ); + array[2] {XYZ.x, XYZ.y} +#end + +#end + + +//===================================================================== +// Find the correlated blackbody color temperature for a given point +// in CIE XYZ space. +// This implementation uses the method of A.R.Robertson as described in +// "Color Science: Concepts and Methods, Quantitative Data and Formulae" +// by G. Wyszecki and W.S. Stiles. +//===================================================================== + +#macro XYZ2K(XYZ) + + #local LowerLimit = 1.0e-20; // prevent possible division by 0 + + // reciprocal temperatures (K) + #local ReciprocalTmp = array[31] { + LowerLimit, + 10.0e-6, + 20.0e-6, + 30.0e-6, + 40.0e-6, + 50.0e-6, + 60.0e-6, + 70.0e-6, + 80.0e-6, + 90.0e-6, + 100.0e-6, + 125.0e-6, + 150.0e-6, + 175.0e-6, + 200.0e-6, + 225.0e-6, + 250.0e-6, + 275.0e-6, + 300.0e-6, + 325.0e-6, + 350.0e-6, + 375.0e-6, + 400.0e-6, + 425.0e-6, + 450.0e-6, + 475.0e-6, + 500.0e-6, + 525.0e-6, + 550.0e-6, + 575.0e-6, + 600.0e-6 + }; + + // correlated UV coordinates + #local UVT = array[31][3] { + {0.18006, 0.26352, -0.24341}, + {0.18066, 0.26589, -0.25479}, + {0.18133, 0.26846, -0.26876}, + {0.18208, 0.27119, -0.28539}, + {0.18293, 0.27407, -0.30470}, + {0.18388, 0.27709, -0.32675}, + {0.18494, 0.28021, -0.35156}, + {0.18611, 0.28342, -0.37915}, + {0.18740, 0.28668, -0.40955}, + {0.18880, 0.28997, -0.44278}, + {0.19032, 0.29326, -0.47888}, + {0.19462, 0.30141, -0.58204}, + {0.19962, 0.30921, -0.70471}, + {0.20525, 0.31647, -0.84901}, + {0.21142, 0.32312, -1.0182}, + {0.21807, 0.32909, -1.2168}, + {0.22511, 0.33439, -1.4512}, + {0.23247, 0.33904, -1.7298}, + {0.24010, 0.34308, -2.0637}, + {0.24792, 0.34655, -2.4681}, + {0.25591, 0.34951, -2.9641}, + {0.26400, 0.35200, -3.5814}, + {0.27218, 0.35407, -4.3633}, + {0.28039, 0.35577, -5.3762}, + {0.28863, 0.35714, -6.7262}, + {0.29685, 0.35823, -8.5955}, + {0.30505, 0.35907, -11.324}, + {0.31320, 0.35968, -15.628}, + {0.32129, 0.36011, -23.325}, + {0.32931, 0.36038, -40.770}, + {0.33724, 0.36051, -116.45} + }; + + // just to make the indexing into the UVT lookup table more readable + #local U_lut = 0; + #local V_lut = 1; + #local T_lut = 2; + + #if ( (XYZ.x < LowerLimit) & (XYZ.y < LowerLimit) & (XYZ.z < LowerLimit) ) + #error("CIE.inc: Error in macro XYZ2K() - invalid input with possible devide by zero error as result") + #end + + // transpose CIE XYZ to UV coordinates + #local U = (4.0 * XYZ.x) / (XYZ.x + 15.0 * XYZ.y + 3.0 * XYZ.z); + #local V = (6.0 * XYZ.y) / (XYZ.x + 15.0 * XYZ.y + 3.0 * XYZ.z); + + #local DM = 0.0; + + #local I = 0; + #while (I < 31) + #local DI = (V - UVT[I][V_lut]) - UVT[I][T_lut] * (U - UVT[I][U_lut]); + #if ((I > 0) & (((DI < 0.0) & (DM >= 0.0)) | ((DI >= 0.0) & (DM < 0.0)))) + #break; // found UV bounding lines + #else + #local DM = DI; + #local I = I+1; + #if (I = 31) + #error("CIE.inc: Error in macro XYZ2K() - invalid input, color temperature would be less than minimum of 1666.7° or way too blue") + #end + #end + #end + + #local DI = DI / sqrt(1.0 + UVT[I][T_lut] * UVT[I][T_lut]); + #local DM = DM / sqrt(1.0 + UVT[I-1][T_lut] * UVT[I-1][T_lut]); + #local K = DM / (DM - DI); + + // linear interpolation from the found bounding lines to the blackbody curve + #local K = 1.0 / ((ReciprocalTmp[I] - ReciprocalTmp[I-1]) * K + ReciprocalTmp[I-1]); + + // finally return the color temperature + (K) + +#end + + + +//===================================================================== +// Mixing of 2 reflective SPD's +// S1: first SPD +// S2: second SPD +// F1,F2: factor to mix them +//===================================================================== +#macro ReflectiveMixXYZ(S1,S2,F1,F2) + #local W=380; + #local XYZ=<0,0,0>; + #local CMy=0; + #local P1 = F1/(F1+F2); + #local P2 = 1.0-P1; + #while (W<=760) + #local CM = CMF_xyz(W); + #local RW = RefWhiteSP(W).y; + #local CMy = CMy + CM.y*RW; + #local XYZ = XYZ + (S1(W).y*P1+S2(W).y*P2)*CM*RW; + #local W=W+CIE_IntegralStep; + #end + (XYZ/CMy) +#end + +// reflectance mix spectrum to xyz +#macro ReflectiveMix2xyz(S1,S2,F1,F2) + ChromaMatchSource(ReflectiveMixXYZ(S1,S2,F1,F2)) +#end + +// converts to gamut mapped RGB +#macro ReflectiveMix(S1,S2,F1,F2) + MapGamut(xyz2RGB(ChromaMatchSource(ReflectiveMixXYZ(S1,S2,F1,F2)))) +#end + +// converts to RGB +#macro ReflectiveMix2RGB(S1,S2,F1,F2) + xyz2RGB(ChromaMatchSource(ReflectiveMixXYZ(S1,S2,F1,F2))) +#end + +// converts to Lab +#macro ReflectiveMix2Lab(S1,S2,F1,F2) + #local C = ReflectiveMixXYZ(S1,S2,F1,F2)/ReferenceWhiteXYZ; + #if (C.y > 0.008856) + #local F = pow(C.y,1/3); + #local L = 116*F-16; + #else + #local F = 7.787*C.y+16/116; + #local L = 903.3*C.y; + #end + < L, + 500*((C.x>0.008856 ? pow(C.x,1/3) : 7.787*C.x+16/116) - F), + 200*(F - (C.z>0.008856 ? pow(C.z,1/3) : 7.787*C.z+16/116)) > +#end + +// converts to Lch +#macro ReflectiveMix2Lch(S1,S2,F1,F2) + Lab2Lch(ReflectiveMix2Lab(S1,S2,F1,F2)) +#end + + +//===================================================================== +// public utilities and helper macros +//===================================================================== + +// normalization +#macro NormRGB(RGB) + (RGB/max(RGB.red,RGB.green,RGB.blue)) +#end + +// Kelvin correction due the revised Boltzmann constant +#declare BoltzmannCorrect = function(K) {(1.4388/1.4380)*K} + +//===================================================================== +// Free allocated memory +// +//===================================================================== + +#macro CIE_ReleaseMemory() + #if (CIE_MultiObserver) + #undef CMF_table + #undef CIE_1931 + #undef CIE_1964 + #undef CIE_1978 + #end + + #undef Illuminant_A + #undef Illuminant_B + #undef Illuminant_C + #undef Illuminant_D50 + #undef Illuminant_D55 + #undef Illuminant_D65 + #undef Illuminant_D75 + #undef Illuminant_E + #undef Illuminant_F1 + #undef Illuminant_F2 + #undef Illuminant_F3 + #undef Illuminant_F4 + #undef Illuminant_F5 + #undef Illuminant_F6 + #undef Illuminant_F7 + #undef Illuminant_F8 + #undef Illuminant_F9 + #undef Illuminant_F10 + #undef Illuminant_F11 + #undef Illuminant_F12 + + #undef sRGB_ColSys + #undef CIE_ColSys + #undef ITU_ColSys + #undef NTSC_ColSys + #undef SMPTE_ColSys + #undef Adobe_ColSys + #undef Match_ColSys + #undef Apple_ColSys + #undef Beta_ColSys + #undef Dell_ColSys + #undef ShortPersistence_ColSys + #undef LongPersistence_ColSys + #undef HOT_ColSys + + #undef ColSys2xyz + #undef ApplyMatchMat + #undef CreateChromaMat + #undef ApplyMat + #undef MultMat33 + #undef InvertMat33 + #undef CIE_ReferenceWhite + #undef CIE_ChromaticAdaption + #undef CIE_GamutMapping + #undef CIE_ColorSystem + #undef CIE_ColorSystemWhitepoint + #undef Blackbody2Whitepoint + #undef Daylight2Whitepoint + #undef Illuminant2Whitepoint + + #undef CMF_xyz + #undef DS012 + #undef RefWhiteSP + #undef Scaling_MM + #undef VonKries_MM + #undef Bradford_MM + #undef Scaling_ChromaMatch + #undef VonKries_ChromaMatch + #undef Bradford_ChromaMatch + #undef CIE_Spectrum + #undef xy_ColSys + #undef ReferenceWhiteXY + #undef ReferenceWhiteXYZ + #undef ChromaMatchFunction + #undef GamutMapFunction + #undef csMatXYZ + #undef csMatRGB + #undef ChromaMatS + #undef ChromaMatD + #undef CIE_IntegralStep + #undef CIE_MultiObserver + #undef ChromaMatchSource + #undef ChromaMatchDest + + #undef BoltzmannCorrect + #undef PlanckBlackBody + + #undef xyz2XYZ + #undef XYZ2xyz + #undef xyz2xyY + #undef xyY2xyz + #undef RGB2xyz + #undef xyz2RGB + #undef ReferenceRGB + #undef ReferenceRGB2RGB + #undef RGB2xyY + #undef xyY2RGB + #undef xyz2Lab + #undef Lab2xyz + #undef Lab2Lch + #undef Lch2Lab + #undef xyz2Lch + #undef Lch2xyz + #undef RGB2Lab + #undef Lab2RGB + #undef RGB2Lch + #undef Lch2RGB + #undef MapGamut + #undef MapGamutNorm + #undef Wavelength2xyz + #undef Wavelength + #undef Wavelength2RGB + #undef Wavelength2Lab + #undef Wavelength2Lch + #undef ReflectanceXYZ + #undef Reflective2xyz + #undef ReflectiveSpectrum + #undef Reflective2RGB + #undef Reflective2Lab + #undef Reflective2Lch + #undef Emissive2xyz + #undef EmissiveSpectrum + #undef Emissive2RGB + #undef Emissive2Lab + #undef Emissive2Lch + #undef LineSpectrum2xyz + #undef LineSpectrum + #undef LineSpectrum2RGB + #undef LineSpectrum2Lab + #undef LineSpectrum2Lch + #undef LineSpectrumMix2xyz + #undef LineSpectrumMix + #undef LineSpectrumMix2RGB + #undef LineSpectrumMix2Lab + #undef LineSpectrumMix2Lch + #undef Blackbody2xyz + #undef Blackbody + #undef Blackbody2RGB + #undef Blackbody2Lab + #undef Blackbody2Lch + #undef DaylightM1M2 + #undef Daylight2xyz + #undef Daylight + #undef Daylight2RGB + #undef Daylight2Lab + #undef Daylight2Lch + #undef ReflectiveMixXYZ + #undef ReflectiveMix2xyz + #undef ReflectiveMix + #undef ReflectiveMix2RGB + #undef ReflectiveMix2Lab + #undef ReflectiveMix2Lch + #undef GammaRGB + #undef GammaCorrectXYZ2RGB + #undef GammaXYZ2RGB + #undef GammaCorrectRGB2XYZ + #undef GammaRGB2XYZ + #undef NormRGB + + #undef CIE_Observer_String + #undef CIE_ColorSystem_String + #undef CIE_Whitepoint_String + #undef CIE_ReferenceWhite_String + #undef CIE_ChromaticAdaption_String + + #ifdef (espd_cie_standard_Inc_Temp) espd_cie_standard_Release() #end + #ifdef (espd_lightsys_Inc_Temp) espd_lightsys_Release() #end + #ifdef (espd_sun_Inc_Temp) espd_sun_Release() #end + #ifdef (lspd_elements_Inc_Temp) lspd_elements_Release() #end + #ifdef (rspd_jvp_Inc_Temp) rspd_jvp_Release() #end + #ifdef (rspd_aster_Inc_Temp) rspd_aster_Release() #end + #ifdef (rspd_lunar_Inc_Temp) rspd_lunar_Release() #end + #ifdef (rspd_pantone_coated_Inc_Temp) rspd_pantone_coated_Release() #end + #ifdef (rspd_pantone_uncoated_Inc_Temp) rspd_pantone_uncoated_Release() #end + #ifdef (rspd_pantone_matte_Inc_Temp) rspd_pantone_matte_Release() #end +#end + +//===================================================================== +// Some utilities for text information +//===================================================================== + +#macro CIE_csID(CS) + (CS[0][0]+CS[1][0]+CS[2][0]+CS[2][1]) +#end + +#if (CIE_MultiObserver) + #macro CIE_iID(I) + I[CIE_Spectrum][0]+I[CIE_Spectrum][1] + #end +#else + #macro CIE_iID(I) + I[0]+I[1] + #end +#end + +#macro CIE_Observer_String(S) + concat(S, + #if (CIE_MultiObserver) + #switch (CIE_Spectrum) + #case(CIE_1931) "CIE 1931 2 degree" #break + #case(CIE_1964) "CIE 1964 10 degree" #break + #case(CIE_1978) "CIE 1978 2 degree (Judd/Vos)" #break + #end + #else + "CIE 1931 2 degree" + #end + ) +#end + +#macro CIE_ColorSystem_String(S) + concat(S, + #switch (CIE_csID(xy_ColSys)) + #case(CIE_csID(sRGB_ColSys)) "sRGB" #break + #case(CIE_csID(CIE_ColSys)) "CIE RGB" #break + #case(CIE_csID(NTSC_ColSys)) "NTSC" #break + #case(CIE_csID(ITU_ColSys)) "ITU (Pal Secam)" #break + #case(CIE_csID(SMPTE_ColSys)) "SMPTE" #break + #case(CIE_csID(Match_ColSys)) "Color Match RGB" #break + #case(CIE_csID(Adobe_ColSys)) "Adobe RGB" #break + #case(CIE_csID(Apple_ColSys)) "Apple RGB" #break + #case(CIE_csID(Beta_ColSys)) "Beta RGB" #break + #case(CIE_csID(Dell_ColSys)) "Dell Phosphors" #break + #case(CIE_csID(ShortPersistence_ColSys))"Short Persistence Phosphors"#break + #case(CIE_csID(LongPersistence_ColSys)) "Long Persistence Phosphors" #break + #case(CIE_csID(HOT_ColSys)) "Hydrogen-Oxygen-Thermal" #break + #else "unknown" + #end + ) +#end + +#macro CIE_Whitepoint_String(S) + concat(S, + #local X=xy_ColSys[3+CIE_Spectrum][0]; + #local Y=xy_ColSys[3+CIE_Spectrum][1]; + #switch (X+Y) + #case(CIE_iID(Illuminant_A)) "Illuminant_A", #break + #case(CIE_iID(Illuminant_B)) "Illuminant_B", #break + #case(CIE_iID(Illuminant_C)) "Illuminant_C", #break + #case(CIE_iID(Illuminant_D50)) "Illuminant_D50", #break + #case(CIE_iID(Illuminant_D55)) "Illuminant_D55", #break + #case(CIE_iID(Illuminant_D65)) "Illuminant_D65", #break + #case(CIE_iID(Illuminant_D75)) "Illuminant_D75", #break + #case(CIE_iID(Illuminant_E)) "Illuminant_E", #break + #case(CIE_iID(Illuminant_F1)) "Illuminant_F1", #break + #case(CIE_iID(Illuminant_F2)) "Illuminant_F2", #break + #case(CIE_iID(Illuminant_F3)) "Illuminant_F3", #break + #case(CIE_iID(Illuminant_F4)) "Illuminant_F4", #break + #case(CIE_iID(Illuminant_F5)) "Illuminant_F5", #break + #case(CIE_iID(Illuminant_F6)) "Illuminant_F6", #break + #case(CIE_iID(Illuminant_F7)) "Illuminant_F7", #break + #case(CIE_iID(Illuminant_F8)) "Illuminant_F8", #break + #case(CIE_iID(Illuminant_F9)) "Illuminant_F9", #break + #case(CIE_iID(Illuminant_F10)) "Illuminant_F10", #break + #case(CIE_iID(Illuminant_F11)) "Illuminant_F11", #break + #case(CIE_iID(Illuminant_F12)) "Illuminant_F12", #break + #else "user defined", + #end + " (",str(X,1,4),", ",str(Y,1,4),")" + ) +#end + +#macro CIE_ReferenceWhite_String(S) + concat(S, + #switch (CIE_iID(ReferenceWhiteXY)) + #case(CIE_iID(Illuminant_A)) "Illuminant_A" #break + #case(CIE_iID(Illuminant_B)) "Illuminant_B" #break + #case(CIE_iID(Illuminant_C)) "Illuminant_C" #break + #case(CIE_iID(Illuminant_D50)) "Illuminant_D50" #break + #case(CIE_iID(Illuminant_D55)) "Illuminant_D55" #break + #case(CIE_iID(Illuminant_D65)) "Illuminant_D65" #break + #case(CIE_iID(Illuminant_D75)) "Illuminant_D75" #break + #case(CIE_iID(Illuminant_E)) "Illuminant_E" #break + #case(CIE_iID(Illuminant_F1)) "Illuminant_F1" #break + #case(CIE_iID(Illuminant_F2)) "Illuminant_F2" #break + #case(CIE_iID(Illuminant_F3)) "Illuminant_F3" #break + #case(CIE_iID(Illuminant_F4)) "Illuminant_F4" #break + #case(CIE_iID(Illuminant_F5)) "Illuminant_F5" #break + #case(CIE_iID(Illuminant_F6)) "Illuminant_F6" #break + #case(CIE_iID(Illuminant_F7)) "Illuminant_F7" #break + #case(CIE_iID(Illuminant_F8)) "Illuminant_F8" #break + #case(CIE_iID(Illuminant_F9)) "Illuminant_F9" #break + #case(CIE_iID(Illuminant_F10)) "Illuminant_F10" #break + #case(CIE_iID(Illuminant_F11)) "Illuminant_F11" #break + #case(CIE_iID(Illuminant_F12)) "Illuminant_F12" #break + #else "unknown" + #end + ) +#end + +#macro CIE_ChromaticAdaption_String(S) + concat(S, + #switch (ChromaMatchFunction) + #case(off) "None" #break + #case(Scaling_ChromaMatch) "Scaling" #break + #case(VonKries_ChromaMatch) "Von Kries" #break + #case(Bradford_ChromaMatch) "Bradford" #break + #else "unknown" + #end + ) +#end + +//===================================================================== + +// EOF +#version CIE_Inc_Temp; +#end + diff --git a/Tools/povray/espd_lightsys.inc b/Tools/povray/espd_lightsys.inc new file mode 100644 index 00000000..974a5728 --- /dev/null +++ b/Tools/povray/espd_lightsys.inc @@ -0,0 +1,929 @@ +// ------------------------------------------------------------------ +// Persistence of Vision Ray Tracer Include File +// Emissive Spectral Data library for PoV-Ray +// ------------------------------------------------------------------ +// Mixed sources originally compiled by Jaime Vives Piqueres for the +// lightsys macros, converted to splines by Ive. +// +// Added Mitsubishi spectra sampled by Ive +// +// ------------------------------------------------------------------ +/* + Content: + ------- + + ES_GE_SW_Incandescent_60w - GE Soft White incandescent 60 watt + ES_GE_SW_Incandescent_100w - GE Soft White incandescent 100 watt + ES_Nikon_SB16_XenonFlash - Nikon SB-16 xenon flash + ES_GTE_341_Warm - warm white fluorescent tube + ES_GTE_341_Cool - cool white fluorescent tube + + ES_Phillips_PLS_11w - Phillips PL-S compact white fluorescent 11 watt + ES_Phillips_Mastercolor_3K - Phillips Mastercolor + ES_Phillips_HPS - Phillips High Pressure Sodium + + ES_Osram_CoolBeam_20w - Osram Halogen 20 watt + ES_Osram_CoolFluor_36w - Osram Fluor 36 watt + + ES_Solux_Halog4700K - Solux Halogen 47 VOR + ES_Cornell_Box_Light - Cornell box light (tungsten flood light with UV filter and diffusing glass plate) + ES_Sunlight - Sunlight (terrestrial - filtered by the atmosphere) + ES_Extraterrestrial_Sun - Sunlight (outer space - non filtered) + ES_Daylight_Fluor - Daylight fluorescent + + ES_Tungsten_Incandescent3K - Tungsten 3000k + + ES_Mitsubishi_Metal_Halide - ca. 4274K + ES_Mitsubishi_Daylight_Fluorescent - ca. 6245K + ES_Mitsubishi_Moon_Fluorescent - ca. 4939K + ES_Mitsubishi_Standard_Fluorescent - ca. 4091K + + +*/ + +// Standard include file beginning stuff +#ifndef (espd_lightsys_Inc_Temp) +#declare espd_lightsys_Inc_Temp = version; + +#ifdef(View_POV_Include_Stack) + #debug "Including espd_lightsys.inc\n" +#end + +//============================================================= + +// Other light SPDs from graphics at the Cornell Univ: +// - GE Soft White incandescent - +#declare ES_GE_SW_Incandescent_60w = spline{ linear_spline + 350, 0 + 400, 0.02 + 450, 0.09 + 500, 0.17 + 550, 0.27 + 600, 0.40 + 650, 0.52 + 700, 0.64 + 750, 0.75 + 800, 0.85 +} +#declare ES_GE_SW_Incandescent_100w = spline{ linear_spline + 350, 0 + 400, 0.05 + 450, 0.13 + 500, 0.26 + 550, 0.41 + 600, 0.60 + 650, 0.79 + 700, 0.96 + 750, 1.15 + 800, 1.3 +} +// - Nikon SB-16 xenon flash - +#declare ES_Nikon_SB16_XenonFlash = spline{ linear_spline + 380, 0.04 + 390, 0.05 + 400, 0.04 + 410, 0.08 + 420, 0.54 + 430, 0.77 + 440, 0.84 + 450, 0.92 + 460, 0.94 + 470, 0.98 + 480, 0.95 + 490, 0.90 + 500, 0.84 + 510, 0.83 + 520, 0.82 + 530, 0.84 + 540, 0.83 + 550, 0.80 + 560, 0.79 + 570, 0.77 + 580, 0.76 + 590, 0.75 + 600, 0.74 + 610, 0.73 + 620, 0.72 + 630, 0.71 + 640, 0.68 + 650, 0.68 + 660, 0.66 + 670, 0.65 + 680, 0.64 + 690, 0.66 + 700, 0.63 + 710, 0.60 + 800, 0 +} +// GTE Fluorescents: +// - warm white fluorescent tube - +#declare ES_GTE_341_Warm = spline{ linear_spline + 380, 0.2 + 390, 0.3 + 400, 2.7 + 410, 2.7 + 420, 0.5 + 430, 7.5 + 440, 7.5 + 450, 1.1 + 460, 1.2 + 470, 1.3 + 480, 1.2 + 490, 1.1 + 500, 1.0 + 510, 0.9 + 520, 1.0 + 530, 1.3 + 540, 6.0 + 550, 6.0 + 560, 5.0 + 570, 6.5 + 580, 7.6 + 590, 7.0 + 600, 6.2 + 610, 4.9 + 620, 3.5 + 630, 2.8 + 640, 2.1 + 650, 1.7 + 660, 1.2 + 670, 0.9 + 680, 0.5 + 690, 0.2 + 700, 0.1 + 800, 0.0 +} +// - cool white fluorescent tube - +#declare ES_GTE_341_Cool = spline{ linear_spline + 380, 0.5 + 390, 0.7 + 400, 3.8 + 410, 3.8 + 420, 1.5 + 430, 1.8 + 440, 8.0 + 450, 2.6 + 460, 2.7 + 470, 2.8 + 480, 2.7 + 490, 2.6 + 500, 2.5 + 510, 2.4 + 520, 2.5 + 530, 2.6 + 540, 6.6 + 550, 4.8 + 560, 5.2 + 570, 6.0 + 580, 6.7 + 590, 5.8 + 600, 4.9 + 610, 3.8 + 620, 2.8 + 630, 2.1 + 640, 1.6 + 650, 1.3 + 660, 1.0 + 670, 0.8 + 680, 0.5 + 690, 0.4 + 700, 0.3 + 800, 0.0 +} +// Several Phillips bulbs and tubes, extrated from data sheets at phillips.com: +// - compact white fluorescent Phillips PL-S 11W - +#declare ES_Phillips_PLS_11w = spline{ linear_spline + 350, 0.0 + 400, 0.001 + 406, 0.600 + 412, 0.001 + 425, 0.001 + 436, 1.600 + 450, 0.001 + 462, 0.001 + 475, 0.001 + 488, 0.700 + 500, 0.100 + 525, 0.001 + 546, 4.300 + 550, 2.500 + 562, 0.100 + 575, 0.400 + 587, 1.200 + 600, 0.900 + 612, 6.800 + 625, 1.100 + 650, 0.300 + 662, 0.200 + 675, 0.100 + 687, 0.150 + 700, 0.010 + 710, 0.800 + 725, 0.001 + 800, 0.0 +} +// - Mastercolor 3K - +#declare ES_Phillips_Mastercolor_3K = spline{ linear_spline + 350, 0.0 + 400, 0.080 + 405, 0.160 + 410, 0.170 + 415, 0.110 + 420, 0.200 + 425, 0.120 + 430, 0.100 + 435, 0.250 + 440, 0.110 + 445, 0.100 + 450, 0.090 + 455, 0.090 + 460, 0.110 + 465, 0.080 + 470, 0.100 + 475, 0.090 + 480, 0.080 + 485, 0.075 + 490, 0.070 + 495, 0.085 + 500, 0.100 + 505, 0.090 + 510, 0.080 + 515, 0.090 + 520, 0.110 + 525, 0.100 + 530, 0.140 + 537, 0.980 + 540, 0.800 + 546, 0.450 + 550, 0.120 + 555, 0.100 + 560, 0.090 + 565, 0.140 + 570, 0.290 + 575, 0.120 + 580, 0.190 + 588, 0.520 + 590, 0.260 + 595, 0.740 + 600, 0.600 + 605, 0.500 + 610, 0.380 + 615, 0.310 + 620, 0.250 + 625, 0.240 + 630, 0.190 + 635, 0.180 + 640, 0.160 + 645, 0.150 + 650, 0.140 + 655, 0.170 + 660, 0.170 + 665, 0.120 + 670, 0.130 + 675, 0.120 + 680, 0.100 + 685, 0.120 + 690, 0.080 + 695, 0.090 + 700, 0.070 + 800, 0.0 +} + +// High Pressure Sodium +#declare ES_Phillips_HPS = spline{ linear_spline + 350, 0.0 + 400, 0.005, + 405, 0.0075 + 410, 0.0100 + 415, 0.0125 + 420, 0.0150 + 425, 0.0175 + 430, 0.0200 + 435, 0.0250 + 440, 0.0250 + 445, 0.0100 + 450, 0.0300 + 455, 0.0200 + 460, 0.0100 + 465, 0.0700 + 470, 0.0300 + 475, 0.0250 + 480, 0.0010 + 485, 0.0050 + 490, 0.0100 + 495, 0.0200 + 498, 0.2300 + 505, 0.0100 + 510, 0.0100 + 515, 0.0600 + 520, 0.0100 + 525, 0.0100 + 530, 0.0100 + 535, 0.0100 + 540, 0.0100 + 545, 0.0250 + 550, 0.0200 + 555, 0.0300 + 560, 0.0500 + 565, 0.1100 + 569, 0.9300 + 575, 0.1200 + 580, 0.2100 + 585, 0.6700 + 590, 0.1200 + 593, 0.6900 + 600, 0.3700 + 605, 0.2300 + 610, 0.1800 + 616, 0.3600 + 620, 0.0900 + 625, 0.0700 + 630, 0.0600 + 635, 0.0550 + 640, 0.0500 + 645, 0.0475 + 650, 0.0450 + 655, 0.0450 + 660, 0.0400 + 665, 0.0350 + 670, 0.0400 + 675, 0.0450 + 680, 0.0350 + 685, 0.0250 + 690, 0.0200 + 695, 0.0150 + 700, 0.0100 + 800, 0.0 +} +// Osram lamps: +// - Tungsten Halogen - +#declare ES_Osram_CoolBeam_20w = spline{ linear_spline + 375, 0.05 + 400, 0.10 + 425, 0.20 + 450, 0.35 + 475, 0.50 + 500, 0.75 + 525, 1.00 + 550, 1.30 + 575, 1.70 + 600, 1.90 + 625, 2.30 + 650, 2.55 + 675, 2.90 + 702, 3.20 + 725, 2.80 + 750, 2.30 + 775, 1.75 +} +// - Cool_White Fluorescent - +#declare ES_Osram_CoolFluor_36w = spline{ linear_spline + 300, 0.0 + 406, 0.23 + 425, 0.08 + 436, 0.65 + 475, 0.12 + 500, 0.15 + 525, 0.17 + 546, 0.78 + 578, 0.56 + 600, 0.40 + 625, 0.29 + 650, 0.19 + 675, 0.11 + 700, 0.08 + 725, 0.06 + 750, 0.02 + 800, 0.0 +} +// Solux lamps: +// - Halogen 47 VOR - +#declare ES_Solux_Halog4700K = spline{ linear_spline + 380, 0.900 + 400, 1.350 + 420, 1.700 + 440, 2.100 + 460, 2.300 + 480, 2.500 + 500, 2.550 + 520, 2.600 + 540, 2.650 + 560, 2.675 + 580, 2.700 + 600, 2.725 + 620, 2.850 + 640, 2.875 + 660, 2.900 + 680, 2.850 + 700, 2.725 + 720, 2.650 + 740, 2.625 + 760, 2.600 +} +// - cornell box light (tungsten flood light with UV filter and diffusing glass plate) - +#declare ES_Cornell_Box_Light = spline{ linear_spline + 375, 0.40 + 400, 0.35 + 425, 0.50 + 450, 0.85 + 475, 1.30 + 500, 1.75 + 525, 2.20 + 550, 2.60 + 575, 3.45 + 600, 4.00 + 625, 4.40 + 650, 4.75 + 675, 4.85 + 700, 4.30 + 725, 3.60 + 750, 2.90 + 775, 2.50 +} +// Pedro J. Aphalo: +// - sunlight - +#declare ES_Sunlight = spline{ linear_spline + 375, 1.2 + 387, 1.5 + 400, 2.0 + 412, 3.0 + 425, 3.1 + 437, 3.5 + 450, 3.5 + 462, 4.8 + 475, 5.4 + 487, 5.2 + 500, 5.6 + 512, 5.7 + 525, 5.8 + 537, 6.0 + 550, 6.2 + 562, 6.2 + 575, 6.2 + 587, 6.5 + 600, 6.5 + 612, 6.5 + 625, 6.5 + 637, 6.7 + 650, 6.7 + 662, 7.0 + 675, 7.1 + 687, 6.1 + 700, 6.7 + 712, 7.0 + 725, 6.1 + 737, 6.8 + 750, 7.0 + 762, 3.6 +} + +#declare ES_Extraterrestrial_Sun = spline{ linear_spline + 375.0, 1.400 + 380.5, 1.289 + 385.5, 1.000 + 390.5, 1.223 + 395.5, 1.378 + 400.5, 1.649 + 405.5, 1.672 + 410.5, 1.502 + 415.5, 1.736 + 420.5, 1.760 + 425.5, 1.697 + 430.5, 1.470 + 435.5, 1.725 + 440.5, 1.715 + 445.5, 1.823 + 450.5, 2.146 + 455.5, 2.036 + 460.5, 2.042 + 465.5, 2.044 + 470.5, 1.879 + 475.5, 2.018 + 480.5, 2.037 + 485.5, 1.920 + 490.5, 1.694 + 495.5, 1.928 + 500.5, 1.859 + 505.5, 1.995 + 510.5, 1.949 + 515.5, 1.902 + 520.5, 1.625 + 525.5, 1.920 + 530.5, 1.780 + 535.5, 1.900 + 540.5, 1.772 + 545.5, 1.903 + 550.5, 1.864 + 555.5, 1.899 + 560.5, 1.845 + 565.5, 1.800 + 570.5, 1.772 + 575.5, 1.832 + 580.5, 1.840 + 585.5, 1.786 + 590.5, 1.710 + 595.5, 1.785 + 600.5, 1.748 + 605.5, 1.766 + 610.5, 1.705 + 615.5, 1.715 + 620.5, 1.736 + 625.5, 1.634 + 631.0, 1.641 + 641.0, 1.616 + 651.0, 1.408 + 661.0, 1.573 + 671.0, 1.518 + 681.0, 1.494 + 691.0, 1.450 + 701.0, 1.388 + 711.0, 1.387 + 721.0, 1.332 + 731.0, 1.327 + 741.0, 1.259 + 751.0, 1.263 + 761.0, 1.238 +} + +// - Daylight Fluorescent - +#declare ES_Daylight_Fluor = spline{ linear_spline + 380, 0.15 + 390, 0.24 + 400, 0.29 + 410, 0.39 + 420, 0.50 + 430, 0.61 + 440, 0.74 + 450, 0.81 + 460, 0.85 + 470, 0.89 + 480, 0.87 + 490, 0.87 + 500, 0.82 + 510, 0.75 + 520, 0.74 + 530, 0.75 + 540, 0.81 + 550, 0.91 + 560, 1.00 + 570, 1.08 + 580, 1.15 + 590, 1.00 + 600, 0.88 + 610, 0.72 + 620, 0.57 + 630, 0.46 + 640, 0.36 + 650, 0.29 + 660, 0.20 + 670, 0.14 + 680, 0.08 + 690, 0.03 + 700, 0.02 + 760, 0.01 +} + +// Mitsubishi fluorescent lamps +#declare ES_Mitsubishi_Metal_Halide = spline {linear_spline + 380, 0.05537 + 385, 0.06442 + 390, 0.06739 + 395, 0.07781 + 400, 0.08670 + 405, 0.09800 + 410, 0.10126 + 415, 0.15310 + 420, 0.25617 + 425, 0.15692 + 430, 0.13052 + 435, 0.13058 + 440, 0.10770 + 445, 0.11281 + 450, 0.13211 + 455, 0.14657 + 460, 0.17680 + 465, 0.14886 + 470, 0.15378 + 475, 0.17005 + 480, 0.20368 + 485, 0.15713 + 490, 0.20226 + 495, 0.16863 + 500, 0.18168 + 505, 0.22725 + 510, 0.21829 + 515, 0.22002 + 520, 0.17948 + 525, 0.20085 + 530, 0.22348 + 535, 1.00000 + 540, 0.44727 + 545, 0.26827 + 550, 0.17853 + 555, 0.19613 + 560, 0.17633 + 565, 0.23762 + 570, 0.23794 + 575, 0.26481 + 580, 0.24187 + 585, 0.23008 + 590, 0.23668 + 595, 0.29373 + 600, 0.37231 + 605, 0.29687 + 610, 0.37294 + 615, 0.32956 + 620, 0.26214 + 625, 0.33428 + 630, 0.25318 + 635, 0.27188 + 640, 0.26686 + 645, 0.26418 + 650, 0.25428 + 655, 0.30646 + 660, 0.27298 + 665, 0.28917 + 670, 0.24344 + 675, 0.28037 + 680, 0.25381 + 685, 0.36634 + 690, 0.25617 + 695, 0.23700 + 700, 0.26057 + 705, 0.21279 + 710, 0.16392 + 715, 0.15480 + 720, 0.13659 +} + +#declare ES_Mitsubishi_Daylight_Fluorescent = spline {linear_spline + 380, 0.03800 + 385, 0.04914 + 390, 0.06142 + 395, 0.07214 + 400, 0.08608 + 405, 0.40442 + 410, 0.12744 + 415, 0.13014 + 420, 0.14677 + 425, 0.16333 + 430, 0.18058 + 435, 1.00000 + 440, 0.21268 + 445, 0.22404 + 450, 0.24385 + 455, 0.25627 + 460, 0.26363 + 465, 0.26432 + 470, 0.26478 + 475, 0.26662 + 480, 0.26731 + 485, 0.27099 + 490, 0.27260 + 495, 0.26593 + 500, 0.26064 + 505, 0.25282 + 510, 0.24707 + 515, 0.24109 + 520, 0.23856 + 525, 0.23626 + 530, 0.23787 + 535, 0.24454 + 540, 0.25903 + 545, 0.69611 + 550, 0.28756 + 555, 0.30297 + 560, 0.31861 + 565, 0.33241 + 570, 0.34208 + 575, 0.39361 + 580, 0.41592 + 585, 0.33678 + 590, 0.32183 + 595, 0.30320 + 600, 0.28226 + 605, 0.25903 + 610, 0.24017 + 615, 0.21452 + 620, 0.19013 + 625, 0.16846 + 630, 0.14925 + 635, 0.12938 + 640, 0.11300 + 645, 0.09922 + 650, 0.08707 + 655, 0.07525 + 660, 0.06616 + 665, 0.05848 + 670, 0.05188 + 675, 0.04585 + 680, 0.04049 + 685, 0.03653 + 690, 0.03366 + 695, 0.02998 + 700, 0.02733 + 705, 0.02448 + 710, 0.02416 + 715, 0.02019 + 720, 0.01911 +} + +#declare ES_Mitsubishi_Moon_Fluorescent = spline {linear_spline + 380, 0.02951 + 385, 0.03851 + 390, 0.04821 + 395, 0.05574 + 400, 0.06740 + 405, 0.36860 + 410, 0.10009 + 415, 0.10201 + 420, 0.11446 + 425, 0.12822 + 430, 0.14304 + 435, 1.00000 + 440, 0.16901 + 445, 0.17798 + 450, 0.19317 + 455, 0.20469 + 460, 0.21135 + 465, 0.21383 + 470, 0.21442 + 475, 0.21748 + 480, 0.22084 + 485, 0.22166 + 490, 0.22450 + 495, 0.21852 + 500, 0.21412 + 505, 0.21022 + 510, 0.20451 + 515, 0.20162 + 520, 0.19957 + 525, 0.19869 + 530, 0.20372 + 535, 0.21254 + 540, 0.22829 + 545, 0.66885 + 550, 0.27115 + 555, 0.29686 + 560, 0.32393 + 565, 0.35055 + 570, 0.36973 + 575, 0.43537 + 580, 0.45861 + 585, 0.38890 + 590, 0.37875 + 595, 0.36612 + 600, 0.34108 + 605, 0.31423 + 610, 0.28987 + 615, 0.26619 + 620, 0.24340 + 625, 0.20609 + 630, 0.18101 + 635, 0.15782 + 640, 0.13772 + 645, 0.11999 + 650, 0.10453 + 655, 0.09071 + 660, 0.07868 + 665, 0.06740 + 670, 0.05946 + 675, 0.05258 + 680, 0.04597 + 685, 0.04094 + 690, 0.03727 + 695, 0.03287 + 700, 0.03325 + 705, 0.02822 + 710, 0.02466 + 715, 0.02100 + 720, 0.01952 +} + +#declare ES_Mitsubishi_Standard_Fluorescent = spline {linear_spline + 380, 0.02713 + 385, 0.03494 + 390, 0.04322 + 395, 0.04965 + 400, 0.05946 + 405, 0.39188 + 410, 0.09092 + 415, 0.08761 + 420, 0.09899 + 425, 0.10964 + 430, 0.12315 + 435, 1.00000 + 440, 0.14402 + 445, 0.15086 + 450, 0.16245 + 455, 0.17122 + 460, 0.17499 + 465, 0.17661 + 470, 0.17731 + 475, 0.17838 + 480, 0.18118 + 485, 0.18135 + 490, 0.18270 + 495, 0.17816 + 500, 0.17536 + 505, 0.17289 + 510, 0.17045 + 515, 0.17272 + 520, 0.17867 + 525, 0.19043 + 530, 0.20901 + 535, 0.23566 + 540, 0.27253 + 545, 0.77821 + 550, 0.35637 + 555, 0.40227 + 560, 0.44890 + 565, 0.48659 + 570, 0.51631 + 575, 0.59386 + 580, 0.60860 + 585, 0.52331 + 590, 0.50616 + 595, 0.47693 + 600, 0.44383 + 605, 0.40565 + 610, 0.36458 + 615, 0.32568 + 620, 0.28751 + 625, 0.25054 + 630, 0.21730 + 635, 0.18756 + 640, 0.16175 + 645, 0.13861 + 650, 0.11918 + 655, 0.10135 + 660, 0.08623 + 665, 0.07345 + 670, 0.06349 + 675, 0.05431 + 680, 0.04721 + 685, 0.04088 + 690, 0.03581 + 695, 0.03105 + 700, 0.02742 + 705, 0.02355 + 710, 0.02242 + 715, 0.01858 + 720, 0.01644 +} + +#declare ES_Tungsten_Incandescent3K = spline {linear_spline + 360, 0.10804 + 404, 0.16814 + 410, 0.17633 + 444, 0.22277 + 449, 0.22960 + 485, 0.27877 + 490, 0.28560 + 533, 0.34433 + 539, 0.35253 + 582, 0.41126 + 588, 0.41946 + 631, 0.47819 + 637, 0.48639 + 680, 0.54512 + 686, 0.55331 + 720, 0.59975 + 725, 0.60658 + 761, 0.65575 + 766, 0.66258 + 801, 0.71039 + 806, 0.71722 + 830, 0.75000 +} + + +//============================================================= + +#macro espd_lightsys_Release() + #undef ES_GE_SW_Incandescent_60w + #undef ES_GE_SW_Incandescent_100w + #undef ES_Nikon_SB16_XenonFlash + #undef ES_GTE_341_Warm + #undef ES_GTE_341_Cool + #undef ES_Phillips_PLS_11w + #undef ES_Phillips_Mastercolor_3K + #undef ES_Phillips_HPS + #undef ES_Osram_CoolBeam_20w + #undef ES_Osram_CoolFluor_36w + #undef ES_Solux_Halog4700K + #undef ES_Cornell_Box_Light + #undef ES_Sunlight + #undef ES_Extraterrestrial_Sun + #undef ES_Daylight_Fluor + #undef ES_Mitsubishi_Metal_Halide + #undef ES_Mitsubishi_Daylight_Fluorescent + #undef ES_Mitsubishi_Moon_Fluorescent + #undef ES_Mitsubishi_Standard_Fluorescent + #undef espd_lightsys_Inc_Temp +#end + +//============================================================= + +#version espd_lightsys_Inc_Temp; +#end // eof diff --git a/Tools/povray/pr.png b/Tools/povray/pr.png new file mode 100644 index 00000000..0028bc4e Binary files /dev/null and b/Tools/povray/pr.png differ diff --git a/Tools/povray/pr.pov b/Tools/povray/pr.pov new file mode 100644 index 00000000..2fc67a51 --- /dev/null +++ b/Tools/povray/pr.pov @@ -0,0 +1,216 @@ +///////////////////////////////////////////// +// +// ~~ [ Strange Crystal ] ~~ +// version 4 out of 4 +// +// by Michael Scharrer +// https://mscharrer.net +// +// CC-BY-4.0 license +// https://creativecommons.org/licenses/by/4.0/ +// +///////////////////////////////////////////// + +#version 3.7; +#include "spectral.inc" + +#declare s = seed(44); +#declare box_count = 40; + +global_settings { + assumed_gamma 1 + max_trace_level 16 + adc_bailout 0.006 + photons { + count 10000000 + autostop 0 + jitter .4 + max_trace_level 7 + adc_bailout 0.02 + } +} + +background { + rgb 0.03 +} + +camera { + right x*image_width/image_height + location <3,5,-2> + look_at <-2, 1, 0> +} + +#macro sublight(col, pos) + light_source { + <-5.7,4.5,11.5> + pos + <1,.9,.7> * col + area_light <0.83, 0, 0>, <0, 0, 0.83>, 2, 2 + adaptive 0.01 + jitter + } +#end + +//reddish light +sublight(<.50, .25, .25>, 0.11*y) + +//bluish light +sublight(<.25, .50, .25>, 0.00*y) + +//greenish light +sublight(<.25, .25, .50>, -0.11*y) + + +//whole crystal +#declare crystal_base = merge { + #declare i = 0; + #while (i < box_count) + box { + -1 + 1 + + rotate 360* + } + #declare i = i + 1; + #end +} + +//the cut through the crystal +#declare crystal_separator = blob { + sphere { <-2,0,0> 4 2.9 } + cylinder { <1,-4,0> <1,4,0> 1.5 (-2.2) } + sphere { <.2,.7,-.8> 0.5 (-1) } + scale 1.3 +} + +//the actual crystal +difference { + union { + + //left piece + intersection { + object { crystal_base } + object { crystal_separator } + + rotate 10*z + translate -.25*x + } + + sphere {<0.5,-0,-6.5>, 1 + M_Spectral_Filter( D_Average(D_CC_A4, 1, Value_1, 1), IOR_CrownGlass_SK5,15) + } + + //right piece + difference { + + union { + object { crystal_base } + box { <-0.7,-0.8,-1.5>,<-0.5,-0.2,-1.4> + rotate <17,-56,43> + texture { pigment { colour <255,0,0,0,0> }} + } + } + + object { crystal_separator } + + rotate -10*z + translate .25*x + } + + //small shard + intersection { + object { crystal_base } + sphere { 0 3 translate -4*x } + + rotate -90*z + rotate 90*y + translate -3.0*y + scale 0.5 + translate <-3.5, 0, 1> + } + + rotate -30*y + translate <-3.5,1,5.5> + + } + + //cut off at the bottom + plane { + y + 0.01 + } + + pigment { + rgbt <0.5, 1.0, 0.5, 0.9> + } + finish { + ambient 0 + diffuse 0 + reflection <0.65, 0.55, 0.48> + } + interior { + ior 1.8 + } + photons{ + target + reflection on + refraction on + collect off + } +} + +//floor +plane { + y + 0 + + hollow + no_reflection + + #declare inner_pigm = pigment { + bozo + color_map { + [0 rgb 0.6] + [1 rgb 1.0] + } + scale 0.2 + } + + pigment { + crackle + pigment_map { + [0.000 rgb .2] + [0.015 inner_pigm] + } + turbulence 0.1 + scale 0.06 + } + finish { + ambient <0.032,0.032,0.038> + } + photons { + collect on + } +} + +//fake floor reflector +plane { + y + (-1) + + hollow + no_image + no_shadow + + pigment { + rgb 0.2 + } + finish { + diffuse 0 + ambient 1 + reflection 0.2 + } + photons{ + collect off + } +} + diff --git a/Tools/povray/spectral.inc b/Tools/povray/spectral.inc new file mode 100644 index 00000000..7861ba08 --- /dev/null +++ b/Tools/povray/spectral.inc @@ -0,0 +1,63 @@ +//================================================================================ +// POV-Ray spectral rendering main include file V0.22 +//================================================================================ +// +// Notes: +// +// If no animation is used (i.e. the value of "clock" is zero) the system will +// switch to rgb preview mode without spectral rendering. +// +// But if in this case "SpectralWavelength" is declared before this file is +// included, the *one* file for the specified wavelength will be rendered. +// +// - Ive, April 2014 +// +//================================================================================ + + +#ifdef (SpectralWavelength) + + #if ((SpectralWavelength < 380) | (SpectralWavelength > 730)) + #error "\nSpectral rendering: Wavelength out of range [380-730]\n" + #end + #declare WavelengthIndex = (SpectralWavelength -380) / 10; + +#else + + #declare WavelengthIndex = clock - 1; + +#end + + + +#if (WavelengthIndex >= 0) + + #declare SpectralMode = on; + + #debug "\nSpectral rendering: wavelength " + #debug concat(str(380 + WavelengthIndex*10,3,0), "nm\n\n") + +#else + + #declare SpectralMode = off; + #declare WavelengthIndex = 17; // 550nm for the preview mode + + #debug "\nRGB preview rendering.\n\n" + +#end + + +//================================================================================ + + +#include "CIE.inc" +#include "espd_lightsys.inc" + +#include "spectral_materials.inc" +#include "spectral_lights.inc" +#include "spectral_glasses.inc" +#include "spectral_metals.inc" +#include "spectral_minerals.inc" + + +//================================================================================ diff --git a/Tools/povray/spectral_glasses.inc b/Tools/povray/spectral_glasses.inc new file mode 100644 index 00000000..352b1803 --- /dev/null +++ b/Tools/povray/spectral_glasses.inc @@ -0,0 +1,256 @@ +//================================================================================ +// POV-Ray spectral render materials V0.21 +// +// Glasses +// ******* +// +// Ive, April 2014 +// +//================================================================================ + +#ifndef (spectral_glasses_inc) #declare spectral_glasses_inc = 1; + +//================================================================================ + + +#declare Schott_TiK1 = 1; +#declare Schott_FK5 = 2; +#declare Schott_TiF1 = 3; +#declare Schott_BK7 = 4; +#declare Schott_PK2 = 5; +#declare Schott_K5 = 6; +#declare Schott_KF9 = 7; +#declare Schott_BaLK1 = 8; +#declare Schott_KzF6 = 9; +#declare Schott_ZK1 = 10; +#declare Schott_LLF1 = 11; +#declare Schott_Ultran30 = 12; +#declare Schott_PSK3 = 13; +#declare Schott_BaK1 = 14; +#declare Schott_BaLF4 = 15; +#declare Schott_LF5 = 16; +#declare Schott_LgSK2 = 17; +#declare Schott_FF5 = 18; +#declare Schott_SK4 = 19; +#declare Schott_KzFSN4 = 20; +#declare Schott_SSK4 = 21; +#declare Schott_F2 = 22; +#declare Schott_BaSF10 = 23; +#declare Schott_BaF10 = 24; +#declare Schott_LaK10 = 25; +#declare Schott_TaC2 = 26; +#declare Schott_NbF1 = 27; +#declare Schott_LaF2 = 28; +#declare Schott_SF6 = 29; +#declare Schott_TaFD5 = 30; +#declare Schott_HTF1 = 31; + + +#declare Schott_Param = array[31][6] { + { 2.157397800000E+00, -8.400418900000E-03, 1.045758200000E-02, 2.182259300000E-04, -5.506364000000E-06, 5.446906000000E-07 }, + { 2.188762100000E+00, -9.557200700000E-03, 8.991523200000E-03, 1.456051600000E-04, -5.284306700000E-06, 3.458801000000E-07 }, + { 2.247312400000E+00, -8.904405800000E-03, 1.249352500000E-02, 4.265063800000E-04, -2.156480900000E-06, 2.636406500000E-06 }, + { 2.271892900000E+00, -1.010807700000E-02, 1.059250900000E-02, 2.081696500000E-04, -7.647253800000E-06, 4.924099100000E-07 }, + { 2.277053300000E+00, -1.053201000000E-02, 1.018835400000E-02, 2.900156400000E-04, -1.960285600000E-05, 1.096771800000E-06 }, + { 2.285029900000E+00, -8.601072500000E-03, 1.180678300000E-02, 2.076565700000E-04, -2.131491300000E-06, 3.213123400000E-07 }, + { 2.282439600000E+00, -8.596014400000E-03, 1.344264500000E-02, 2.780353500000E-04, -4.999896000000E-07, 7.710591100000E-07 }, + { 2.296692300000E+00, -8.297554900000E-03, 1.190723400000E-02, 1.990830500000E-04, -2.030683800000E-06, 3.142970300000E-07 }, + { 2.293404400000E+00, -1.034612200000E-02, 1.331986300000E-02, 3.483322600000E-04, -9.935409000000E-06, 1.122790500000E-06 }, + { 2.315795100000E+00, -8.749390500000E-03, 1.232964500000E-02, 2.631111200000E-04, -8.285420100000E-06, 7.373580100000E-07 }, + { 2.350516200000E+00, -8.530645100000E-03, 1.575085300000E-02, 4.281138800000E-04, -6.987571800000E-06, 1.717551700000E-06 }, + { 2.367794200000E+00, -6.081890600000E-03, 1.050956800000E-02, 1.310557500000E-04, -4.985438000000E-07, 1.047365200000E-07 }, + { 2.376819300000E+00, -1.014651400000E-02, 1.216714800000E-02, 1.191660600000E-04, 6.425062700000E-06, -1.747870600000E-07 }, + { 2.433300700000E+00, -8.493135300000E-03, 1.389351200000E-02, 2.679826800000E-04, -6.194610100000E-06, 6.220900500000E-07 }, + { 2.452836600000E+00, -9.204767800000E-03, 1.455279400000E-02, 4.304668800000E-04, -2.048983600000E-05, 1.592441500000E-06 }, + { 2.444176000000E+00, -8.305969500000E-03, 1.900069700000E-02, 5.412969700000E-04, -4.197315500000E-06, 2.374289700000E-06 }, + { 2.475076000000E+00, -5.430452800000E-03, 1.389321000000E-02, 2.299056000000E-04, -1.686847400000E-06, 4.395970300000E-07 }, + { 2.474332400000E+00, -1.095533800000E-02, 1.929380100000E-02, 1.449773200000E-03, -1.103874400000E-04, 1.113600800000E-05 }, + { 2.558522800000E+00, -9.882495100000E-03, 1.515182000000E-02, 2.113447800000E-04, -3.413013000000E-06, 1.267335500000E-07 }, + { 2.529344600000E+00, -1.323458600000E-02, 1.858616500000E-02, 5.475965500000E-04, -1.171798700000E-05, 2.004290500000E-06 }, + { 2.570784900000E+00, -9.257776400000E-03, 1.617075100000E-02, 8.692497200000E-04, -2.401170400000E-05, 4.536516900000E-06 }, + { 2.555406300000E+00, -8.874615000000E-03, 2.249478700000E-02, 8.692497200000E-04, -2.400117040000E-05, 4.536516900000E-06 }, + { 2.653125000000E+00, -8.138855300000E-03, 2.299564300000E-02, 7.353595700000E-04, -1.340739000000E-05, 3.696232500000E-06 }, + { 2.732246210000E+00, -1.249046000000E-02, 1.856233400000E-02, 9.999053600000E-04, -6.838855200000E-05, 4.925793100000E-06 }, + { 2.898461400000E+00, -1.485703900000E-02, 2.098503700000E-02, 5.450692100000E-04, -1.729731400000E-05, 1.799360100000E-06 }, + { 2.971713700000E+00, -1.495259300000E-02, 2.016286800000E-02, 9.407228300000E-04, -8.861410400000E-05, 5.319124200000E-06 }, + { 2.975349100000E+00, -1.461347000000E-02, 2.109638300000E-02, 1.198038000000E-03, -1.188738800000E-04, 7.344435000000E-06 }, + { 2.967378700000E+00, -1.097876700000E-02, 2.508860700000E-02, 6.317159600000E-04, -7.564541700000E-06, 2.320221300000E-06 }, + { 3.119500700000E+00, -1.090258000000E-02, 4.133065100000E-02, 3.180021400000E-03, -2.195318400000E-04, 2.667101400000E-05 }, + { 3.272909800000E+00, -1.288825700000E-02, 3.345136300000E-02, 6.822138100000E-05, 1.121542700000E-04, -4.048565900000E-06 }, + { 2.063303400000E+00, -3.290634500000E-03, 7.176516000000E-03, -1.911055900000E-04, 3.812344100000E-05, -2.066850100000E-06 } +} + + +#macro ParamIOR_Glass_Schott(K,W) + sqrt( Schott_Param[K][0] + + Schott_Param[K][1] * pow(W, 2 ) + + Schott_Param[K][2] * pow(W, -2 ) + + Schott_Param[K][3] * pow(W, -4 ) + + Schott_Param[K][4] * pow(W, -6 ) + + Schott_Param[K][5] * pow(W, -8 ) + ) +#end + + +// optical glass N-BAF10 (Schott) +// IOR (550nm) = 1.67306 input: W^2 +#declare ParamIOR_Glass_BAF10 = function(x) { + sqrt( 1 + 1.5851495*x/(x-0.00926681282) + 0.143559385*x/(x-0.0424489805) + 1.08521269*x/(x-105.613573) ) +} + +// optical glass N-BAK1 (Schott) +// IOR (550nm) = 1.57462 input: W^2 +#declare ParamIOR_Glass_BAK1 = function(x) { + sqrt( 1 + 1.12365662*x/(x-0.00644742752) + 0.309276848*x/(x-0.0222284402) + 0.881511957*x/(x-107.297751) ) +} + +// optical glass N-BK7 (Schott) +// IOR (550nm) = 1.51852 input: W^2 +#declare ParamIOR_Glass_BK7 = function(x) { + sqrt( 1 + 1.03961212*x/(x-0.00600069867) + 0.231792344*x/(x-0.0200179144) + 1.01046945*x/(x-103.560653) ) +} + +// flint glass F2 (Schott) +// IOR (550nm) = 1.62366 input: W^2 +#declare ParamIOR_FlintGlass_F2 = function(x) { + sqrt( 1 + 1.34533359*x/(x-0.00997743871) + 0.209073176*x/(x-0.0470450767) + 0.937357162*x/(x-111.886764) ) +} + +// flint glass F5 (Schott) +// IOR (550nm) = 1.60679 input: W^2 +#declare ParamIOR_FlintGlass_F5 = function(x) { + sqrt( 1 + 1.3104463 *x/(x-0.00958633048) + 0.19603426 *x/(x-0.0457627627) + 0.96612977*x/(x-115.011883) ) +} + +// dense flint glass N-SF2 (Schott) +// IOR (550nm) = 1.65176 input: W^2 +#declare ParamIOR_FlintGlass_SF2 = function(x) { + sqrt( 1 + 1.47343127*x/(x-0.0109019098) + 0.163681849*x/(x-0.0585683687) + 1.36920899*x/(x-127.404933) ) +} + +// crown glass K7 (Schott) +// IOR (550nm) = 1.51293 input: W^2 +#declare ParamIOR_CrownGlass_K7 = function(x) { + sqrt( 1 + 1.1273555*x/(x-0.00720341707) + 0.124412303*x/(x-0.0269835916) + 0.827100531*x/(x-100.384588) ) +} + +// crown glass K10 (Schott) +// IOR (550nm) = 1.50327 input: W^2 +#declare ParamIOR_CrownGlass_K10 = function(x) { + sqrt( 1 + 1.15687082*x/(x-0.00809424251) + 0.0642625444*x/(x-0.0386051284) + 0.872376139*x/(x-104.74773) ) +} + +// dense crown glass SK5 (Schott) +// IOR (550nm) = 1.59119 input: W^2 +#declare ParamIOR_CrownGlass_SK5 = function(x) { + sqrt( 1 + 0.991463823*x/(x-0.00522730467) + 0.495982121*x/(x-0.0172733646) + 0.987393925*x/(x-98.3594579) ) +} + + +// PMMA acrylic glass +// IOR (550nm) = 1.49363 input: W +#declare ParamIOR_Acryl = function(x) { + sqrt( 2.399964 - 8.308636e-2*pow(x,2) - 1.919569e-1*pow(x,-2) + 8.720608e-2*pow(x,-4) - 1.666411e-2*pow(x,-6) + 1.169519e-3*pow(x,-8) ) +} + + + +#if (SpectralMode) + +//================================================================================ +// SPECTRAL MODE +//================================================================================ + +// glasses - taken from Schott (a German glass manufacturer) data sheets +// optical glass +#declare IOR_Glass_BAF10 = array[36]; +#declare IOR_Glass_BAK1 = array[36]; +#declare IOR_Glass_BK7 = array[36]; +// flint glass +#declare IOR_FlintGlass_F2 = array[36]; +#declare IOR_FlintGlass_F5 = array[36]; +#declare IOR_FlintGlass_SF2 = array[36]; +// crown glass +#declare IOR_CrownGlass_K7 = array[36]; +#declare IOR_CrownGlass_K10 = array[36]; +#declare IOR_CrownGlass_SK5 = array[36]; + +#declare IOR_Acryl = array[36]; + + +// fill the arrays +#for (I, 0, 35) + #local W = 0.38 + I*0.01; + #local W2 = pow(W,2); + + #declare IOR_Water[I] = ParamIOR_Water(W2); + + #declare IOR_Glass_BAF10[I] = ParamIOR_Glass_BAF10(W2); + #declare IOR_Glass_BAK1[I] = ParamIOR_Glass_BAK1(W2); + #declare IOR_Glass_BK7[I] = ParamIOR_Glass_BK7(W2); + #declare IOR_FlintGlass_F2[I] = ParamIOR_FlintGlass_F2(W2); + #declare IOR_FlintGlass_F5[I] = ParamIOR_FlintGlass_F5(W2); + #declare IOR_FlintGlass_SF2[I] = ParamIOR_FlintGlass_SF2(W2); + #declare IOR_CrownGlass_K7[I] = ParamIOR_CrownGlass_K7(W2); + #declare IOR_CrownGlass_K10[I] = ParamIOR_CrownGlass_K10(W2); + #declare IOR_CrownGlass_SK5[I] = ParamIOR_CrownGlass_SK5(W2); + + #declare IOR_Acryl[I] = ParamIOR_Acryl(W); +#end + + +//================================================================================ + +#else // !SpectralMode + +//================================================================================ +// PREVIEW MODE +//================================================================================ + +#local W = WavelengthFromIndex(WavelengthIndex) / 1000; +#local W2 = pow(W,2); + +#declare IOR_Glass_BAF10 = ParamIOR_Glass_BAF10(W2); +#declare IOR_Glass_BAK1 = ParamIOR_Glass_BAK1(W2); +#declare IOR_Glass_BK7 = ParamIOR_Glass_BK7(W2); +#declare IOR_FlintGlass_F2 = ParamIOR_FlintGlass_F2(W2); +#declare IOR_FlintGlass_F5 = ParamIOR_FlintGlass_F5(W2); +#declare IOR_FlintGlass_SF2 = ParamIOR_FlintGlass_SF2(W2); +#declare IOR_CrownGlass_K7 = ParamIOR_CrownGlass_K7(W2); +#declare IOR_CrownGlass_K10 = ParamIOR_CrownGlass_K10(W2); +#declare IOR_CrownGlass_SK5 = ParamIOR_CrownGlass_SK5(W2); + +#declare IOR_Acryl = ParamIOR_Acryl(W); + + +#end // !SpectralMode + + +//================================================================================ + + +#macro IOR_SpectralParam(M) + ior ParamIOR_Glass_Schott( M-1, WavelengthFromIndex(WavelengthIndex) / 1000) +#end + + +#macro M_Glass_Schott (M, D, FadeDist) + material { + texture { + P_Spectral_Filter (D, Value_1) + finish { + ambient 0 emission 0 diffuse 0 + reflection {0 1 fresnel on} conserve_energy + } + } + interior { + IOR_SpectralParam(M) + fade_power 1001 + fade_distance FadeDist + FadeColor_Spectral (D) + } + } +#end + + +#end // #ifndef (spectral_glasses_inc) \ No newline at end of file diff --git a/Tools/povray/spectral_lights.inc b/Tools/povray/spectral_lights.inc new file mode 100644 index 00000000..019194fb --- /dev/null +++ b/Tools/povray/spectral_lights.inc @@ -0,0 +1,193 @@ +//================================================================================ +// POV-Ray spectral emission data V0.21 +// +// format for all specular definitions: +// 36 columns for the wavelengths of 380nm to 730nm in 10nm steps +// converted from lightsysIV "espd_lightsys.inc" +// +// All "#declares" and "#macros" prefixed "E_" can be used directly as spectral +// data for light sources and emitting objects. +// +// - Ive, April 2014 +// +//================================================================================ + +#ifndef (spectral_lights_inc) #declare spectral_lights_inc = 1; + + +#if (SpectralMode) + +//================================================================================ +// SPECTRAL MODE +//================================================================================ +// ready made stuff: use any of these declares and macros + + +// Lamps +#declare E_GE_SW_Incandescent_60w = array[36]; // GE Soft White incandescent 60 watt +#declare E_GE_SW_Incandescent_100w = array[36]; // GE Soft White incandescent 100 watt +#declare E_Nikon_SB16_XenonFlash = array[36]; // Nikon SB-16 xenon flash +#declare E_GTE_341_Warm = array[36]; // warm white fluorescent tube +#declare E_GTE_341_Cool = array[36]; // cool white fluorescent tube + +#declare E_Osram_CoolBeam_20w = array[36]; // Osram Halogen 20 watt +#declare E_Osram_CoolFluor_36w = array[36]; // Osram Fluor 36 watt + +#declare E_Phillips_PLS_11w = array[36]; // Phillips PL-S compact white fluorescent 11 watt +#declare E_Phillips_Mastercolor_3K = array[36]; // Phillips Mastercolor 3000 +#declare E_Phillips_HPS = array[36]; // Phillips High Pressure Sodium + +#declare E_Mitsubishi_Metal_Halide = array[36]; // ca. 4274K +#declare E_Mitsubishi_Daylight_Fluorescent = array[36]; // ca. 6245K +#declare E_Mitsubishi_Moon_Fluorescent = array[36]; // ca. 4939K +#declare E_Mitsubishi_Standard_Fluorescent = array[36]; // ca. 4091K + +#declare E_Solux_Halog4700K = array[36]; // Solux Halogen 47 VOR +#declare E_Cornell_Box_Light = array[36]; // tungsten flood light with UV filter and diffusing glass plate + +#declare E_Sunlight = array[36]; // sunlight (terrestrial - filtered by the atmosphere) +#declare E_Extraterrestrial_Sun = array[36]; // sunlight (outer space - non filtered) + + +//================================================================================ + +// CIE D +#macro E_Daylight(K) // K = temperature in Kelvin (4000° - 25000°) + #local M1 = 0; + #local M2 = 0; + DaylightM1M2(K, M1, M2) + + #local Tmp = array[36]; + #for (I, 0, 35) + #declare Tmp[I] = (DS012[I*2][0] + M1*DS012[I*2][1] + M2*DS012[I*2][2]); + #end + SpectralNormalize(Tmp) + Tmp +#end + + +// CIE B +#macro E_Blackbody(K) // K = temperature in Kelvin + + #local Tmp = array[36]; + #for (I, 0, 35) + #local W = 380 + I*10; + #declare Tmp[I] = PlanckBlackBody(W*1e-9, K); + #end + SpectralNormalize(Tmp) + Tmp +#end + + +// some CIE standard illuminants +#declare E_D50 = E_Daylight(5003); // CIE D50 overcast sky with reflected sunlight +#declare E_D65 = E_Daylight(6504); // CIE D65 overcast sky (neutral) +#declare E_D75 = E_Daylight(7500); // CIE D75 blue overcast sky +#declare E_D93 = E_Daylight(9300); // CIE D93 clear deep blue sky + + +#macro SpectralEmission(S) + rgb S[WavelengthIndex] +#end + + +//================================================================================ +// internal stuff: fill the arrays from the espd_lightsys splines + +#for (I, 0, 35) + + #local W = 380 + I*10; + + #declare E_GE_SW_Incandescent_60w[I] = ES_GE_SW_Incandescent_60w(W).y; + #declare E_GE_SW_Incandescent_100w[I] = ES_GE_SW_Incandescent_100w(W).y; + #declare E_Nikon_SB16_XenonFlash[I] = ES_Nikon_SB16_XenonFlash(W).y; + #declare E_GTE_341_Warm[I] = ES_GTE_341_Warm(W).y; + #declare E_GTE_341_Cool[I] = ES_GTE_341_Cool(W).y; + + #declare E_Osram_CoolBeam_20w[I] = ES_Osram_CoolBeam_20w(W).y; + #declare E_Osram_CoolFluor_36w[I] = ES_Osram_CoolFluor_36w(W).y; + +// NOTE: I'm cheating a bit with the Phillips lamps as they have sometimes +// significant peaks in between the 10nm steps and as those peaks are the +// most interesting part for specular rendering I won't miss them. + #declare E_Phillips_PLS_11w[I] = max(ES_Phillips_PLS_11w(W).y, ES_Phillips_PLS_11w(W+5).y); + #declare E_Phillips_Mastercolor_3K[I] = max(ES_Phillips_Mastercolor_3K(W).y, ES_Phillips_Mastercolor_3K(W+5).y); + #declare E_Phillips_HPS[I] = max(ES_Phillips_HPS(W).y, ES_Phillips_HPS(W+5).y); + + #declare E_Mitsubishi_Metal_Halide[I] = ES_Mitsubishi_Metal_Halide(W).y; + #declare E_Mitsubishi_Daylight_Fluorescent[I] = ES_Mitsubishi_Daylight_Fluorescent(W).y; + #declare E_Mitsubishi_Moon_Fluorescent[I] = ES_Mitsubishi_Moon_Fluorescent(W).y; + #declare E_Mitsubishi_Standard_Fluorescent[I] = ES_Mitsubishi_Standard_Fluorescent(W).y; + + #declare E_Solux_Halog4700K[I] = ES_Solux_Halog4700K(W).y; + #declare E_Cornell_Box_Light[I] = ES_Cornell_Box_Light(W).y; + + #declare E_Sunlight[I] = ES_Sunlight(W).y; + #declare E_Extraterrestrial_Sun[I] = ES_Extraterrestrial_Sun(W).y; + +#end + +SpectralNormalize (E_Cornell_Box_Light) +SpectralNormalize (E_Sunlight) +SpectralNormalize (E_Extraterrestrial_Sun) + + +//================================================================================ + +#else // !SpectralMode - the preview functions simply call the CIE.inc counterparts + +//================================================================================ +// PREVIEW MODE +//================================================================================ + +#declare E_GE_SW_Incandescent_60w = Emissive2RGB(ES_GE_SW_Incandescent_60w); +#declare E_GE_SW_Incandescent_100w = Emissive2RGB(ES_GE_SW_Incandescent_100w); +#declare E_Nikon_SB16_XenonFlash = Emissive2RGB(ES_Nikon_SB16_XenonFlash); +#declare E_GTE_341_Warm = Emissive2RGB(ES_GTE_341_Warm); +#declare E_GTE_341_Cool = Emissive2RGB(ES_GTE_341_Cool); + +#declare E_Osram_CoolBeam_20w = Emissive2RGB(ES_Osram_CoolBeam_20w); +#declare E_Osram_CoolFluor_36w = Emissive2RGB(ES_Osram_CoolFluor_36w); + +#declare E_Phillips_PLS_11w = Emissive2RGB(ES_Phillips_PLS_11w); +#declare E_Phillips_Mastercolor_3K = Emissive2RGB(ES_Phillips_Mastercolor_3K); +#declare E_Phillips_HPS = Emissive2RGB(ES_Phillips_HPS); + +#declare E_Mitsubishi_Metal_Halide = Emissive2RGB(ES_Mitsubishi_Metal_Halide); +#declare E_Mitsubishi_Daylight_Fluorescent = Emissive2RGB(ES_Mitsubishi_Daylight_Fluorescent); +#declare E_Mitsubishi_Moon_Fluorescent = Emissive2RGB(ES_Mitsubishi_Moon_Fluorescent); +#declare E_Mitsubishi_Standard_Fluorescent = Emissive2RGB(ES_Mitsubishi_Standard_Fluorescent); + +#declare E_Solux_Halog4700K = Emissive2RGB(ES_Solux_Halog4700K); +#declare E_Cornell_Box_Light = Emissive2RGB(ES_Cornell_Box_Light); + +#declare E_Sunlight = Emissive2RGB(ES_Sunlight); +#declare E_Extraterrestrial_Sun = Emissive2RGB(ES_Extraterrestrial_Sun); + + +#declare E_D50 = Daylight(5003); +#declare E_D65 = Daylight(6504); +#declare E_D75 = Daylight(7500); +#declare E_D93 = Daylight(9300); + + +#macro E_Daylight(K) + Daylight(K) +#end + + +#macro E_Blackbody(K) + Blackbody(K) +#end + + +#macro SpectralEmission(S) + rgb S +#end + + +#end // !SpectralMode + +//================================================================================ + +#end // ifndef spectral_lights_inc \ No newline at end of file diff --git a/Tools/povray/spectral_materials.inc b/Tools/povray/spectral_materials.inc new file mode 100644 index 00000000..b51f1350 --- /dev/null +++ b/Tools/povray/spectral_materials.inc @@ -0,0 +1,484 @@ +//================================================================================ +// POV-Ray spectral render materials V0.21 +// +// format for all specular definitions: +// 36 columns for the wavelebgths of 380nm to 730nm in 10nm steps +// +// Ive, April 2014 +// +//================================================================================ + +#ifndef (spectral_materials_inc) #declare spectral_materials_inc = 1; + +//================================================================================ +// parametric IOR / water, glasses and minerals +// +//================================================================================ + +// water 20°C +// IOR (550nm) = 1.33468 input W^2 +#declare ParamIOR_Water = function(x) { + sqrt( 1 + 5.684027565e-1*x/(x-5.101829712e-3) + 1.726177391e-1*x/(x-1.821153936e-2) + 2.086189578e-2*x/(x-2.620722293e-2) + 1.130748688e-1*x/(x-1.069792721e1) ) +} + +/* +// diamond +// IOR (550nm) = 2.42295 input: W^2 +#declare ParamIOR_Diamond = function(x) { + sqrt( 1 + 4.3356*x/(x-pow(0.1060,2)) + 0.3306*x/(x-pow(0.1750,2)) ) +} +*/ + + +#declare WavelengthFromIndex = function(x) { 380 + x*10 } + + +#macro SpectralNormalize(A) + #local MAX = 0; + #for (I, 0, 35) + #if (A[I] > MAX) #local MAX = A[I]; #end + #end + #for (I, 0, 35) + #declare A[I] = A[I] / MAX; + #end +#end + + +//================================================================================ + +#if (SpectralMode) + +//================================================================================ +// SPECTRAL MODE +//================================================================================ + +//================================================================================ +// Diffuse reflectance for the 24 patches of the "classic" GretagMacbeth +// ColorChecker chart. +// And to be safe: ColorChecker is a Registered Trademark of X-Rite +// and X-Rite is a Trademark and I'm not related with one or the other in any way. +// But here we go: 1-4 rows A-F columns +// +//================================================================================ + +// wavelength nm 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 + +#declare D_CC_A1 = array[36] {0.05475, 0.05833, 0.06116, 0.06238, 0.06231, 0.06207, 0.06183, 0.06159, 0.06154, 0.06162, 0.06203, 0.06296, 0.06518, 0.07027, 0.07640, 0.07949, 0.08128, 0.08429, 0.09058, 0.10290, 0.11905, 0.13426, 0.14320, 0.14688, 0.15077, 0.15810, 0.16819, 0.17890, 0.18755, 0.18964, 0.18577, 0.18149, 0.18161, 0.18721, 0.19605, 0.20949} +#declare D_CC_A2 = array[36] {0.05381, 0.05369, 0.05326, 0.05370, 0.05402, 0.05452, 0.05495, 0.05516, 0.05568, 0.05664, 0.05840, 0.06122, 0.06822, 0.08942, 0.12461, 0.15350, 0.17379, 0.19944, 0.24827, 0.33542, 0.44399, 0.53847, 0.58667, 0.59484, 0.59059, 0.58662, 0.58417, 0.58386, 0.58975, 0.60251, 0.62039, 0.63880, 0.65481, 0.66255, 0.66255, 0.66681} +#declare D_CC_A3 = array[36] {0.06624, 0.07864, 0.10159, 0.14554, 0.19951, 0.24440, 0.28250, 0.30936, 0.30759, 0.27781, 0.23087, 0.17754, 0.12971, 0.09428, 0.06954, 0.05399, 0.04582, 0.04167, 0.03944, 0.03831, 0.03775, 0.03775, 0.03797, 0.03852, 0.03925, 0.03987, 0.04080, 0.04232, 0.04418, 0.04547, 0.04584, 0.04642, 0.04837, 0.05217, 0.05731, 0.06498} +#declare D_CC_A4 = array[36] {0.18936, 0.25464, 0.42260, 0.66021, 0.81098, 0.86212, 0.87658, 0.88417, 0.89104, 0.89566, 0.89932, 0.90370, 0.90718, 0.90908, 0.91091, 0.91005, 0.91122, 0.91402, 0.91343, 0.91602, 0.91548, 0.91584, 0.91433, 0.91547, 0.91764, 0.91863, 0.92101, 0.92291, 0.92386, 0.92199, 0.92242, 0.92477, 0.92749, 0.92977, 0.93041, 0.93329} + +#declare D_CC_B1 = array[36] {0.11713, 0.14345, 0.17453, 0.19093, 0.19560, 0.19900, 0.20423, 0.21318, 0.22842, 0.25127, 0.28005, 0.30878, 0.32945, 0.33336, 0.31460, 0.28628, 0.27349, 0.27646, 0.27720, 0.28930, 0.33938, 0.42022, 0.48779, 0.52511, 0.54574, 0.56156, 0.57788, 0.59497, 0.61180, 0.62475, 0.63810, 0.65596, 0.67822, 0.69958, 0.71709, 0.73382} +#declare D_CC_B2 = array[36] {0.12236, 0.16448, 0.22850, 0.28608, 0.32730, 0.36108, 0.38757, 0.39963, 0.39157, 0.36243, 0.31612, 0.26024, 0.20858, 0.16831, 0.13768, 0.11656, 0.10425, 0.09637, 0.08980, 0.08551, 0.08372, 0.08396, 0.08432, 0.08411, 0.08386, 0.08517, 0.08977, 0.09785, 0.10912, 0.12346, 0.14269, 0.16930, 0.20465, 0.24395, 0.28719, 0.33249} +#declare D_CC_B3 = array[36] {0.05195, 0.05306, 0.05420, 0.05545, 0.05677, 0.05856, 0.06137, 0.06576, 0.07483, 0.09269, 0.12488, 0.17789, 0.24579, 0.30725, 0.33716, 0.33354, 0.31653, 0.29299, 0.26186, 0.22999, 0.19765, 0.16504, 0.13501, 0.11490, 0.10397, 0.09791, 0.09439, 0.09235, 0.09277, 0.09653, 0.10240, 0.10842, 0.11345, 0.11533, 0.11392, 0.11427} +#declare D_CC_B4 = array[36] {0.17085, 0.23206, 0.36507, 0.50656, 0.56749, 0.58270, 0.58770, 0.59009, 0.59099, 0.58977, 0.58841, 0.58843, 0.58898, 0.58948, 0.59059, 0.59002, 0.58990, 0.59030, 0.58929, 0.59094, 0.59031, 0.58971, 0.58713, 0.58515, 0.58304, 0.57996, 0.57779, 0.57595, 0.57440, 0.57221, 0.57061, 0.56922, 0.56828, 0.56797, 0.56648, 0.56631} + +#declare D_CC_C1 = array[36] {0.13036, 0.17707, 0.25101, 0.30625, 0.32392, 0.32993, 0.33283, 0.33097, 0.32342, 0.31134, 0.29823, 0.28533, 0.26943, 0.25037, 0.23144, 0.21426, 0.19942, 0.18451, 0.16938, 0.15729, 0.14911, 0.14482, 0.14186, 0.14057, 0.14067, 0.14109, 0.14257, 0.14654, 0.15184, 0.15351, 0.15009, 0.14395, 0.13639, 0.13235, 0.13496, 0.14673} +#declare D_CC_C2 = array[36] {0.09600, 0.11466, 0.13058, 0.13508, 0.13345, 0.13159, 0.13021, 0.12811, 0.12505, 0.12048, 0.11512, 0.10985, 0.10494, 0.09982, 0.09516, 0.09265, 0.09247, 0.09319, 0.09621, 0.10812, 0.15557, 0.26539, 0.39871, 0.50008, 0.55632, 0.57945, 0.58773, 0.59063, 0.59251, 0.59445, 0.59785, 0.60219, 0.60690, 0.60925, 0.60896, 0.61024} +#declare D_CC_C3 = array[36] {0.04992, 0.04877, 0.04759, 0.04724, 0.04716, 0.04735, 0.04742, 0.04692, 0.04607, 0.04518, 0.04444, 0.04429, 0.04468, 0.04560, 0.04678, 0.04764, 0.04859, 0.05037, 0.05385, 0.05986, 0.07212, 0.10356, 0.17752, 0.31207, 0.46683, 0.58083, 0.64443, 0.67484, 0.69018, 0.69824, 0.70592, 0.71495, 0.72370, 0.73010, 0.73371, 0.73841} +#declare D_CC_C4 = array[36] {0.14421, 0.19246, 0.27184, 0.33081, 0.35042, 0.35692, 0.36123, 0.36326, 0.36297, 0.36081, 0.35874, 0.35811, 0.35846, 0.35919, 0.36041, 0.36046, 0.36056, 0.36083, 0.36043, 0.36185, 0.36175, 0.36133, 0.35932, 0.35753, 0.35543, 0.35241, 0.34990, 0.34764, 0.34547, 0.34272, 0.34017, 0.33760, 0.33531, 0.33383, 0.33180, 0.33054} + +#declare D_CC_D1 = array[36] {0.05124, 0.05423, 0.05599, 0.05704, 0.05786, 0.05895, 0.06030, 0.06131, 0.06228, 0.06325, 0.06478, 0.06738, 0.07531, 0.10120, 0.14536, 0.17826, 0.18394, 0.17011, 0.14938, 0.13274, 0.12186, 0.11517, 0.10948, 0.10536, 0.10434, 0.10599, 0.10891, 0.11189, 0.11406, 0.11395, 0.11240, 0.11215, 0.11482, 0.11977, 0.12459, 0.13030} +#declare D_CC_D2 = array[36] {0.09199, 0.11601, 0.14561, 0.16853, 0.17847, 0.17301, 0.15797, 0.13878, 0.11913, 0.10140, 0.08695, 0.07518, 0.06609, 0.06032, 0.05646, 0.05312, 0.05121, 0.05124, 0.05195, 0.05187, 0.05120, 0.05242, 0.05841, 0.07318, 0.09552, 0.11893, 0.14139, 0.16554, 0.19405, 0.22706, 0.26539, 0.30892, 0.35455, 0.39577, 0.43584, 0.47847} +#declare D_CC_D3 = array[36] {0.05798, 0.05442, 0.05216, 0.05198, 0.05263, 0.05398, 0.05608, 0.05942, 0.06659, 0.08068, 0.10688, 0.15204, 0.22507, 0.33553, 0.46239, 0.55873, 0.61573, 0.64973, 0.67222, 0.69387, 0.70995, 0.72319, 0.73144, 0.73904, 0.74620, 0.75180, 0.75816, 0.76394, 0.76869, 0.77098, 0.77551, 0.78240, 0.79018, 0.79619, 0.79930, 0.80366} +#declare D_CC_D4 = array[36] {0.10519, 0.13133, 0.16260, 0.18017, 0.18592, 0.18953, 0.19286, 0.19423, 0.19378, 0.19233, 0.19106, 0.19085, 0.19125, 0.19158, 0.19205, 0.19210, 0.19217, 0.19231, 0.19206, 0.19263, 0.19238, 0.19193, 0.19059, 0.18939, 0.18799, 0.18587, 0.18398, 0.18232, 0.18085, 0.17925, 0.17777, 0.17604, 0.17434, 0.17337, 0.17219, 0.17139} + +#declare D_CC_E1 = array[36] {0.14423, 0.19827, 0.29443, 0.37544, 0.40837, 0.42095, 0.42618, 0.42609, 0.41932, 0.40343, 0.37927, 0.34636, 0.31112, 0.28124, 0.25388, 0.22889, 0.21420, 0.20835, 0.20162, 0.19440, 0.19257, 0.20018, 0.21441, 0.22952, 0.24058, 0.25396, 0.27851, 0.31322, 0.34779, 0.36587, 0.36579, 0.35942, 0.35799, 0.36493, 0.37723, 0.39783} +#declare D_CC_E2 = array[36] {0.06103, 0.06125, 0.06192, 0.06291, 0.06397, 0.06593, 0.06921, 0.07473, 0.08549, 0.10506, 0.13867, 0.19209, 0.27073, 0.37611, 0.47578, 0.53122, 0.54916, 0.54571, 0.52807, 0.50446, 0.47052, 0.42764, 0.38125, 0.34680, 0.32744, 0.31771, 0.31247, 0.30994, 0.31441, 0.32741, 0.34523, 0.36255, 0.37622, 0.38054, 0.37767, 0.37941} +#declare D_CC_E3 = array[36] {0.14455, 0.19511, 0.28259, 0.34577, 0.36182, 0.35432, 0.33361, 0.30571, 0.27623, 0.24756, 0.21805, 0.18988, 0.16786, 0.14896, 0.12697, 0.10723, 0.09962, 0.10189, 0.10356, 0.10907, 0.13680, 0.19963, 0.29013, 0.40006, 0.51580, 0.61486, 0.68655, 0.73177, 0.75975, 0.77433, 0.78314, 0.79256, 0.80337, 0.81155, 0.81718, 0.82541} +#declare D_CC_E4 = array[36] {0.06796, 0.07672, 0.08388, 0.08741, 0.08888, 0.09044, 0.09187, 0.09204, 0.09135, 0.09039, 0.08975, 0.08965, 0.08981, 0.08988, 0.08997, 0.08996, 0.09001, 0.09006, 0.08986, 0.08990, 0.08951, 0.08916, 0.08852, 0.08806, 0.08749, 0.08645, 0.08551, 0.08478, 0.08420, 0.08368, 0.08321, 0.08254, 0.08176, 0.08143, 0.08093, 0.08068} + +#declare D_CC_F1 = array[36] {0.13627, 0.17946, 0.24689, 0.29682, 0.32028, 0.33708, 0.35550, 0.38119, 0.41913, 0.46596, 0.51048, 0.54581, 0.56719, 0.57426, 0.56908, 0.55068, 0.52351, 0.48843, 0.44521, 0.39987, 0.35043, 0.29939, 0.25243, 0.22096, 0.20431, 0.19579, 0.19088, 0.18823, 0.19072, 0.19942, 0.21159, 0.22310, 0.23164, 0.23332, 0.22941, 0.22935} +#declare D_CC_F2 = array[36] {0.06282, 0.06284, 0.06334, 0.06354, 0.06371, 0.06442, 0.06536, 0.06599, 0.06694, 0.06841, 0.07128, 0.07571, 0.08722, 0.12531, 0.20583, 0.30526, 0.38315, 0.43094, 0.46915, 0.51789, 0.56793, 0.60688, 0.62805, 0.63703, 0.63999, 0.64198, 0.64545, 0.64824, 0.65102, 0.65307, 0.65736, 0.66403, 0.67265, 0.67970, 0.68376, 0.68829} +#declare D_CC_F3 = array[36] {0.10773, 0.14119, 0.19247, 0.23641, 0.26085, 0.28550, 0.31740, 0.35313, 0.39024, 0.42597, 0.44561, 0.44423, 0.42321, 0.38549, 0.33672, 0.28273, 0.23128, 0.18506, 0.14554, 0.11807, 0.10053, 0.08958, 0.08156, 0.07640, 0.07406, 0.07305, 0.07294, 0.07381, 0.07559, 0.07675, 0.07648, 0.07499, 0.07277, 0.07200, 0.07374, 0.07935} +#declare D_CC_F4 = array[36] {0.03102, 0.03199, 0.03228, 0.03256, 0.03275, 0.03282, 0.03282, 0.03262, 0.03248, 0.03240, 0.03233, 0.03231, 0.03228, 0.03215, 0.03209, 0.03198, 0.03196, 0.03198, 0.03192, 0.03195, 0.03182, 0.03179, 0.03173, 0.03185, 0.03193, 0.03190, 0.03191, 0.03194, 0.03202, 0.03212, 0.03222, 0.03223, 0.03224, 0.03233, 0.03237, 0.03250} + + +//================================================================================ +// IOR tables: +// +//================================================================================ + +// wavelength nm 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 + +#declare IOR_15 = array[36] {1.513, 1.512, 1.511, 1.510, 1.509, 1.508, 1.507, 1.506, 1.506, 1.505, 1.504, 1.504, 1.503, 1.4502, 1.502, 1.501, 1.501, 1.500, 1.500, 1.499, 1.499, 1.498, 1.498, 1.498, 1.497, 1.497, 1.497, 1.496, 1.496, 1.496, 1.496, 1.495, 1.495, 1.495, 1.495, 1.494} + + +//================================================================================ +// more (use defined) diffuse/specular reflectance data should go here ... +// +//================================================================================ + +// wavelength nm 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 + +// todo... + + + +//================================================================================ +// IOR functions +// ATM just water, glasses and minerals are moved to seperate files +// +//================================================================================ + +// water (20°C) +#declare IOR_Water = array[36]; + + +#for (I, 0, 35) + #local W = 0.38 + I*0.01; + #local W2 = pow(W,2); + + #declare IOR_Water[I] = ParamIOR_Water(W2); +#end + + +//================================================================================ +// dummy arrays for quick use with Spectral_XXX macros +// +//================================================================================ + +#declare Value_0 = array[36] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +#declare Value_1 = array[36] {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} + + +//================================================================================ +// spectral data set mixer +// example: +// F1 = 1.0 and F2 = 1.0 gives 50:50 of 100% +// F1 = 0.9 and F2 = 0.1 gives 90:10 of 100% +// F1 = 9 and F2 = 1 gives 90:10 of 100% +// +//================================================================================ + +#macro D_Average (SpecData1, F1, SpecData2, F2) + #local F = F1 + F2; + + #if ((F <= 0.0) | (F1 < 0) | (F2 < 0)) + error("D_Average: F1 + F2 has to be > 0.0"); + #end + + #local FF1 = F1/F; + #local FF2 = F2/F; + + #local Tmp = array[36]; + + #for(I, 0, 35) + #declare Tmp[I] = SpecData1[I]*FF1 + SpecData2[I]*FF2; + #end + + Tmp +#end + + +#macro D_RGB (R, G, B) + #local Tmp = array[36]; + + #for(I, 0, 35) + #declare Tmp[I] = D_CC_C3[I]*R*1.1 + D_CC_B3[I]*G*1.7 + D_CC_A3[I]*B*2.0; + #end + + Tmp +#end + + +//================================================================================ +// basic helper macros for the use with spectral data. +// +//================================================================================ + +#macro C_Spectral (Diffuse) + rgb Diffuse[WavelengthIndex] +#end + + +#macro C_Spectral_Filter (Diffuse, Filter) + rgb Diffuse[WavelengthIndex] filter Filter[WavelengthIndex] +#end + + +#macro C_Spectral_Transmit (Diffuse, Transmit) + rgb Diffuse[WavelengthIndex] transmit Transmit[WavelengthIndex] +#end + + +#macro IOR_Spectral (IOR) + ior IOR[WavelengthIndex] +#end + + +#macro FadeColor_Spectral1 (Color) + fade_color rgb Color[WavelengthIndex] +#end + +#macro FadeColor_Spectral2 (Color) + fade_color rgb pow(Color[WavelengthIndex],2) +#end + +#macro FadeColor_Spectral (Color) + fade_color rgb pow(Color[WavelengthIndex],3) +#end + + +//================================================================================ + +#else // !SpectralMode + +//================================================================================ +// PREVIEW MODE! +// +// the following is just for the "preview" mode using precalculated values +//================================================================================ + +//================================================================================ +// GretagMacbeth ColorChecker chart. +//================================================================================ + +#declare D_CC_A1 = <0.1724, 0.0840, 0.0574>; +#declare D_CC_A2 = <0.7167, 0.1991, 0.0270>; +#declare D_CC_A3 = <0.0234, 0.0491, 0.2916>; +#declare D_CC_A4 = <0.9165, 0.9155, 0.8706>; + +#declare D_CC_B1 = <0.5480, 0.2987, 0.2172>; +#declare D_CC_B2 = <0.0650, 0.1062, 0.3924>; +#declare D_CC_B3 = <0.0653, 0.3017, 0.0644>; +#declare D_CC_B4 = <0.5820, 0.5912, 0.5840>; + +#declare D_CC_C1 = <0.1099, 0.1970, 0.3361>; +#declare D_CC_C2 = <0.5417, 0.0884, 0.1204>; +#declare D_CC_C3 = <0.4293, 0.0317, 0.0404>; +#declare D_CC_C4 = <0.3553, 0.3610, 0.3591>; + +#declare D_CC_D1 = <0.1040, 0.1504, 0.0523>; +#declare D_CC_D2 = <0.1043, 0.0440, 0.1397>; +#declare D_CC_D3 = <0.8570, 0.5752, 0.0078>; +#declare D_CC_D4 = <0.1876, 0.1924, 0.1917>; + +#declare D_CC_E1 = <0.2242, 0.2178, 0.4305>; +#declare D_CC_E2 = <0.3547, 0.5078, 0.0483>; +#declare D_CC_E3 = <0.5030, 0.0887, 0.3055>; +#declare D_CC_E4 = <0.0871, 0.0899, 0.0910>; + +#declare D_CC_F1 = <0.1235, 0.5191, 0.4047>; +#declare D_CC_F2 = <0.7804, 0.3540, 0.0216>; +#declare D_CC_F3 = <0.0000, 0.2489, 0.3831>; +#declare D_CC_F4 = <0.0318, 0.0320, 0.0327>; + + +//================================================================================ +// IOR 1.5 at 550nm +// +//================================================================================ + +#declare IOR_15 = 1.5; + + +//================================================================================ +// more (user defined) diffuse/specular reflectance data should go here ... +// +//================================================================================ + + + +//================================================================================ +// parametric IOR at 550nm +// +//================================================================================ + +#local W2 = pow(WavelengthFromIndex(WavelengthIndex)/1000, 2); + +#declare IOR_Water = ParamIOR_Water(W2); + + +//================================================================================ +// dummy values for the use with Spectral_XXX macros +// +//================================================================================ + +#declare Value_0 = 0; +#declare Value_1 = 1; + + +//================================================================================ +// rgb mixer +// +//================================================================================ + +#macro D_Average (SpecData1, F1, SpecData2, F2) + #local F = F1 + F2; + + #if ((F <= 0.0) | (F1 < 0) | (F2 < 0)) + error("D_Average: F1 + F2 has to be > 0.0"); + #end + + #local FF1 = F1/F; + #local FF2 = F2/F; + + (SpecData1*FF1 + SpecData2*FF2) +#end + + +#macro D_RGB (R, G, B) + (D_CC_C3*R*1.1 + D_CC_B3*G*1.7 + D_CC_A3*B*2.0) +#end + + +//================================================================================ +// basic helper macros for preview - corresponding to those with spectral data. +// +//================================================================================ + +#macro C_Spectral (Diffuse) + rgb Diffuse +#end + + +#macro C_Spectral_Filter (Diffuse, Filter) + rgb Diffuse filter Filter +#end + + +#macro C_Spectral_Transmit (Diffuse, Transmit) + rgb Diffuse transmit Transmit +#end + + +#macro IOR_Spectral (IOR) + ior IOR +#end + + +#macro FadeColor_Spectral1 (Color) + #local C = rgb Color; + fade_color rgb +#end + + +#macro FadeColor_Spectral2 (Color) + #local C = rgb Color; + fade_color rgb +#end + +#macro FadeColor_Spectral (Color) + #local C = rgb Color; + fade_color rgb +#end + + +//================================================================================ + +#end // !SpectralMode + + +//================================================================================ +// +// HIGH LEVEL INTERFACE +// ******************** +// +// macros that are the same for spectral and rgb preview rendering +// Use them as they are or just as a reference for creating your own. +// +// Note that I'm just a color guy and not an expert in material properties. +// As such those macros do reflect just my poor ideas and do claim by no means +// any accurate real world behaviour or scientific usefulness. +// ... but any hints on this matter would be highly appreciated ;) +// +//================================================================================ + + +#macro C_Average (Diffuse1, F1, Diffuse2, F2) + C_Spectral(D_Average(Diffuse1, F1, Diffuse2, F2)) +#end + + +#macro C_RGB (R, G, B) + C_Spectral(D_RGB(R, G, B)) +#end + + +#macro P_Spectral (Diffuse) + pigment {C_Spectral(Diffuse)} +#end + + +#macro P_Spectral_Filter (Diffuse, Filter) + pigment {C_Spectral_Filter(Diffuse, Filter)} +#end + + +#macro P_Spectral_Transmit (Diffuse, Transmit) + pigment {C_Spectral_Transmit(Diffuse, Transmit)} +#end + + +#macro T_Spectral_Matte (Diffuse) + texture { + P_Spectral (Diffuse) + finish { + ambient 0 emission 0 diffuse 1 + } + } +#end + + +#macro T_Spectral_Emitting (Emission, Intensity) + texture { + P_Spectral (Emission) + finish { + ambient 0 emission Intensity diffuse 0 + } + } +#end + + +#macro M_Spectral_Matte (Diffuse) + material { + T_Spectral_Matte (Diffuse) + } +#end + + +#macro M_Spectral_Emitting (Emission, Intensity) + material { + T_Spectral_Emitting (Emission, Intensity) + } +#end + + +#macro M_Spectral_Shiny (Diffuse, Reflect, IOR) + material { + texture { + P_Spectral (Diffuse) + finish { + ambient 0 emission 0 diffuse 1-Reflect + reflection {0, Reflect fresnel on} conserve_energy + } + } + interior { IOR_Spectral(IOR) } + } +#end + + +#macro M_Spectral_Filter (Diffuse, IOR, FadeDist) + material { + texture { + P_Spectral_Filter (Diffuse, Value_1) + finish { + ambient 0 emission 0 diffuse 0 + reflection {0 1 fresnel on} conserve_energy + } + } + interior { + IOR_Spectral(IOR) + fade_power 1001 + fade_distance FadeDist + FadeColor_Spectral (Diffuse) + } + } +#end + + +//================================================================================ + +#end // ifndef (spectral_materials_inc) + diff --git a/Tools/povray/spectral_metals.inc b/Tools/povray/spectral_metals.inc new file mode 100644 index 00000000..416436ac --- /dev/null +++ b/Tools/povray/spectral_metals.inc @@ -0,0 +1,348 @@ +//================================================================================ +// POV-Ray spectral render materials V0.21 +// +// Metals +// ****** +// +// Metals have no measured diffuse reflectance but a complex number where +// N (refraction) is the real part and K (extinction) the imaginary part. +// The actual (diffuse) reflectance is calculated "on the fly" from this complex +// number using this fresnel equation: +// R(w) = ( ( sqr(N(w)-1) + sqr(K(w)) ) / ( sqr(N(w)+1) + sqr(K(w)) ) ) +// +// You'll find at the end of the file the section "high level interface" where +// the macros meant to be used are prefixed M_*** +// +// All measurement was taken from very thin highly polished samples while +// *perfect* polishing would be impossible. +// Actually the Reflection parameter should only control how polished the +// surface is (i.e. how blurred the reflection) and the definition of the fresnel +// reflection itself remain constant. But while keeping compatible to official +// POV this is currently out of the scope of this include file. +// As such the Reflection parameter is mostly intended for "artistic" usage, +// realistic values would be about 1.0 for chrome down to about 0.8 for iron. +// As the absorption for all metals is around 10% when viewed directly down to 5% at +// shallow angels (in addition to the fresnel reflection falloff) I've adjusted +// the macro M_Spectral_Metal in that way. +// The small amount of diffuse is meant to simulate some photons that are scattered +// around the surface and do indeed bounce diffuse back, but again this should be +// blurred reflection. +// +// +// - Ive, January 2014 +// +//================================================================================ + +#ifndef (spectral_metals_inc) #declare spectral_metals_inc = 1; + + +// fresnel reflectivity calculation for a given wavelength +#macro MetalIndex (N,K,I) + ( ( pow(N[I]-1, 2) + pow(K[I], 2) ) / + ( pow(N[I]+1, 2) + pow(K[I], 2) ) ) +#end + + +#if (SpectralMode) + +//================================================================================ +// SPECTRAL MODE +//================================================================================ +// internal metal helper macros for the use with spectral data. + + +#macro D_Metal (N,K) + + #local Tmp = array[36]; + + #for(I, 0, 35) + #declare Tmp[I] = MetalIndex (N,K,I); + #end + + Tmp + +#end + + +#macro C_Metal (N,K) + rgb MetalIndex (N,K,WavelengthIndex) +#end + + +//================================================================================ + +#else // !SpectralMode + +//================================================================================ +// PREVIEW MODE +//================================================================================ +// internal metal helper macros for preview - corresponding to those with spectral data. + +#macro D_Metal (N,K) + /* + creating a linear spline "on the fly" as this is what CIE.inc (and the function + Reflective2RGB() expects. It finally returns a simple rgb<> color. + */ + + #local TS = spline { linear_spline + #for (I, 0, 35) + #local W = 380 + I*10; + + W, MetalIndex(N,K,I) + + #end + } + + Reflective2RGB(TS) + +#end + + +#macro C_Metal (N,K) + rgb D_Metal (N,K) +#end + + + + +//================================================================================ + +#end // !SpectralMode + + + +//================================================================================ +// helper macros +//================================================================================ + +// IOR +#macro IOR_Metal (N,K) + ior pow(K[WavelengthIndex],2) / pow(N[WavelengthIndex],2) +#end + + +// extinction +#macro EXT_Metal (N,K) + K[WavelengthIndex] +#end + + + +#macro M_Spectral_Metal (N, K, Reflectance) + material { + texture { + pigment { C_Metal(N, K) } + finish { + ambient 0 emission 0 diffuse (0.5 - Reflectance*0.45) + reflection { + #if (SpectralMode) + Reflectance * MetalIndex(N,K,WavelengthIndex) * 0.9, 0.95 + #else + Reflectance * 0.9, 0.95 metallic + #end + fresnel on + } + conserve_energy + brilliance EXT_Metal(N, K) + metallic + } + } + interior { IOR_Metal(N, K) } + } +#end + + + + +#macro Spectral_Average (Data1, F1, Data2, F2) + #local F = F1 + F2; + + #if ((F <= 0.0) | (F1 < 0) | (F2 < 0)) + error("Spectral_Average: F1 + F2 has to be > 0.0"); + #end + + #local FF1 = F1/F; + #local FF2 = F2/F; + + #local Tmp = array[36]; + + #for(I, 0, 35) + #declare Tmp[I] = Data1[I]*FF1 + Data2[I]*FF2; + #end + + Tmp +#end + + + +#macro Spectral_Average3 (Data1, F1, Data2, F2, Data3, F3) + #local F = F1 + F2 + F3; + + #if ((F <= 0.0) | (F1 < 0) | (F2 < 0)) + error("Spectral_Average3: F1 + F2 + F3 has to be > 0.0"); + #end + + #local FF1 = F1/F; + #local FF2 = F2/F; + #local FF3 = F3/F; + + #local Tmp = array[36]; + + #for(I, 0, 35) + #declare Tmp[I] = Data1[I]*FF1 + Data2[I]*FF2 + Data3[I]*FF3; + #end + + Tmp +#end + + + +#macro M_Spectral_Alloy (N1, K1, F1, N2, K2 F2, Reflectance) + #local N = Spectral_Average (N1, F1, N2, F2); + #local K = Spectral_Average (K1, F1, K2, F2); + M_Spectral_Metal (N, K, Reflectance) +#end + + + +#macro M_Spectral_Alloy3 (N1, K1, F1, N2, K2 F2, N3, K3 F3, Reflectance) + #local N = Spectral_Average3 (N1, F1, N2, F2, N3, F3); + #local K = Spectral_Average3 (K1, F1, K2, F2, K3, F3); + M_Spectral_Metal (N, K, Reflectance) +#end + + +// wavelength nm 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 + +#declare IOR_N_Aluminium = array[36] { 0.43745, 0.46265, 0.48784, 0.51304, 0.54101, 0.57035, 0.59969, 0.63324, 0.66843, 0.70362, 0.73927, 0.77592, 0.81257, 0.84921, 0.88783, 0.93029, 0.97274, 1.01519, 1.05764, 1.10625, 1.15827, 1.21030, 1.26232, 1.31434, 1.36645, 1.43031, 1.49417, 1.55803, 1.62703, 1.69751, 1.76800, 1.83981, 1.92139, 2.00298, 2.08456, 2.16738 } +#declare IOR_K_Aluminium = array[36] { 4.58661, 4.71107, 4.83552, 4.95998, 5.08430, 5.20855, 5.33281, 5.45435, 5.57484, 5.69533, 5.81463, 5.93134, 6.04806, 6.16477, 6.28104, 6.39645, 6.51187, 6.62728, 6.74270, 6.85478, 6.96502, 7.07526, 7.18550, 7.29573, 7.40592, 7.50808, 7.61025, 7.71241, 7.80423, 7.89304, 7.98186, 8.06881, 8.14197, 8.21514, 8.28831, 8.35851 } + +#declare IOR_N_Chrome = array[36] { 1.91761, 1.96178, 2.01050, 2.06210, 2.12128, 2.18583, 2.25115, 2.32444, 2.40701, 2.49579, 2.59167, 2.69222, 2.78191, 2.85932, 2.94188, 3.03334, 3.11515, 3.17240, 3.20804, 3.22244, 3.22139, 3.21044, 3.19542, 3.17844, 3.15981, 3.14055, 3.12199, 3.10440, 3.08994, 3.07652, 3.06769, 3.05966, 3.05680, 3.05478, 3.05748, 3.06059 } +#declare IOR_K_Chrome = array[36] { 2.73668, 2.78563, 2.85060, 2.91028, 2.97307, 3.03354, 3.08587, 3.13556, 3.18391, 3.23125, 3.26771, 3.28974, 3.30703, 3.32214, 3.33077, 3.33198, 3.32972, 3.32657, 3.32179, 3.31481, 3.30712, 3.30027, 3.29792, 3.29795, 3.30008, 3.30794, 3.31690, 3.32738, 3.33847, 3.34977, 3.36054, 3.37091, 3.37853, 3.38608, 3.39329, 3.40061 } + +#declare IOR_N_Copper = array[36] { 1.20921, 1.18000, 1.18000, 1.18000, 1.17773, 1.17434, 1.17095, 1.16576, 1.15988, 1.15400, 1.14759, 1.14005, 1.13251, 1.12497, 1.10786, 1.07214, 1.03127, 0.94392, 0.85657, 0.73949, 0.60641, 0.47332, 0.40422, 0.33778, 0.27182, 0.25403, 0.23624, 0.21845, 0.21442, 0.21499, 0.21390, 0.21310, 0.21359, 0.21469, 0.21900, 0.22327 } +#declare IOR_K_Copper = array[36] { 2.12561, 2.21000, 2.21000, 2.21000, 2.24407, 2.29492, 2.34576, 2.38965, 2.43082, 2.47200, 2.50804, 2.53317, 2.55829, 2.58342, 2.59848, 2.59402, 2.59041, 2.59449, 2.59857, 2.65074, 2.72881, 2.80688, 2.94993, 3.09569, 3.24132, 3.37322, 3.50512, 3.63702, 3.75051, 3.85785, 3.96461, 4.06863, 4.16176, 4.25455, 4.34545, 4.43598 } + +#declare IOR_N_Nickel = array[36] { 1.61000, 1.61000, 1.61000, 1.61000, 1.61472, 1.62000, 1.62000, 1.62878, 1.64090, 1.65220, 1.66163, 1.66689, 1.67792, 1.69725, 1.71604, 1.73382, 1.75184, 1.77224, 1.79265, 1.81194, 1.83060, 1.84925, 1.87603, 1.90315, 1.93031, 1.96137, 1.98941, 2.01294, 2.04471, 2.08000, 2.11158, 2.14350, 2.17850, 2.21350, 2.24850, 2.28364 } +#declare IOR_K_Nickel = array[36] { 2.25551, 2.31200, 2.36000, 2.42015, 2.47775, 2.53471, 2.59353, 2.65390, 2.71452, 2.77102, 2.82958, 2.89274, 2.95575, 3.01855, 3.07964, 3.13742, 3.19514, 3.25229, 3.30943, 3.36582, 3.42179, 3.47776, 3.53532, 3.59295, 3.65056, 3.70646, 3.75882, 3.80588, 3.85706, 3.91000, 3.95737, 4.00450, 4.04950, 4.09450, 4.13950, 4.18318 } + +#declare IOR_N_Silver = array[36] { 0.19708, 0.18820, 0.17300, 0.17300, 0.16687, 0.15951, 0.15755, 0.15129, 0.14346, 0.13668, 0.13167, 0.13062, 0.13000, 0.13000, 0.12985, 0.12940, 0.12867, 0.12500, 0.12132, 0.12024, 0.12061, 0.12099, 0.12425, 0.12764, 0.13103, 0.13378, 0.13653, 0.13928, 0.14000, 0.14000, 0.14000, 0.14024, 0.14221, 0.14419, 0.14616, 0.14792 } +#declare IOR_K_Silver = array[36] { 1.72102, 1.83800, 1.95000, 2.07030, 2.18077, 2.28288, 2.37438, 2.47024, 2.56723, 2.65763, 2.74611, 2.83032, 2.91763, 3.00942, 3.09720, 3.17720, 3.25735, 3.33898, 3.42061, 3.50015, 3.57851, 3.65687, 3.73159, 3.80617, 3.88083, 3.96339, 4.04596, 4.12853, 4.20928, 4.28939, 4.36950, 4.44889, 4.52296, 4.59704, 4.67111, 4.74537 } + +#declare IOR_N_Gold = array[36] { 1.68798, 1.67080, 1.65800, 1.64146, 1.62656, 1.60718, 1.57188, 1.50229, 1.41768, 1.31373, 1.18881, 1.01723, 0.85500, 0.70620, 0.57687, 0.48532, 0.39847, 0.35929, 0.32011, 0.29593, 0.28020, 0.26447, 0.24874, 0.23301, 0.21728, 0.20155, 0.18582, 0.17009, 0.16477, 0.16312, 0.16146, 0.16012, 0.16111, 0.16209, 0.16308, 0.16415 } +#declare IOR_K_Gold = array[36] { 1.91693, 1.94000, 1.95600, 1.95750, 1.94951, 1.93412, 1.91059, 1.87854, 1.84374, 1.81549, 1.80318, 1.82634, 1.89546, 2.03072, 2.18347, 2.37013, 2.55249, 2.69127, 2.83004, 2.89942, 2.92975, 2.96009, 2.99043, 3.02076, 3.05110, 3.08144, 3.11178, 3.14211, 3.28287, 3.46243, 3.64199, 3.81630, 3.95210, 4.08790, 4.22370, 4.35783 } + +#declare IOR_N_Platinum = array[36] { 1.66103, 1.68832, 1.72022, 1.74261, 1.76887, 1.79654, 1.82268, 1.84756, 1.87181, 1.89441, 1.91816, 1.94447, 1.97386, 2.00768, 2.04062, 2.07187, 2.10285, 2.13130, 2.15976, 2.18433, 2.20672, 2.22910, 2.25278, 2.27651, 2.30025, 2.32479, 2.34933, 2.37387, 2.40686, 2.44267, 2.47848, 2.51356, 2.54319, 2.57281, 2.60244, 2.63200 } +#declare IOR_K_Platinum = array[36] { 2.71573, 2.77664, 2.84060, 2.90030, 2.96246, 3.02471, 3.08353, 3.14390, 3.20452, 3.26102, 3.31958, 3.38274, 3.44377, 3.50174, 3.55973, 3.61777, 3.67407, 3.71472, 3.75537, 3.80582, 3.86179, 3.91776, 3.96881, 4.01966, 4.07058, 4.12887, 4.18715, 4.24543, 4.29512, 4.34196, 4.38879, 4.43593, 4.48531, 4.53469, 4.58407, 4.63322 } + +#declare IOR_N_Iron = array[36] { 2.11234, 2.18836, 2.26116, 2.32917, 2.40153, 2.47354, 2.53351, 2.58522, 2.62938, 2.66658, 2.69534, 2.72039, 2.75680, 2.80722, 2.85589, 2.89567, 2.92992, 2.95137, 2.95699, 2.95195, 2.94205, 2.92776, 2.90614, 2.88682, 2.87964, 2.88729, 2.90214, 2.91576, 2.91974, 2.91096, 2.89484, 2.87703, 2.86317, 2.85730, 2.85572, 2.85717 } +#declare IOR_K_Iron = array[36] { 2.49479, 2.54602, 2.59398, 2.63805, 2.67497, 2.70684, 2.73801, 2.76723, 2.79329, 2.81756, 2.84303, 2.86773, 2.88662, 2.89926, 2.90905, 2.91635, 2.92176, 2.93130, 2.94743, 2.96690, 2.98639, 3.00433, 3.02226, 3.03923, 3.05417, 3.06597, 3.07631, 3.08743, 3.10162, 3.11973, 3.14029, 3.16168, 3.18232, 3.20103, 3.21879, 3.23600 } + + + + +//================================================================================ +// +// HIGH LEVEL INTERFACE +// ******************** +// +//================================================================================ + +// pure metals + +#macro M_Aluminium (Reflectance) + M_Spectral_Metal(IOR_N_Aluminium, IOR_K_Aluminium, Reflectance) +#end + + +#macro M_Chrome (Reflectance) + M_Spectral_Metal(IOR_N_Chrome, IOR_K_Chrome, Reflectance) +#end + + +#macro M_Copper (Reflectance) + M_Spectral_Metal(IOR_N_Copper, IOR_K_Copper, Reflectance) +#end + + +#macro M_Nickel (Reflectance) + M_Spectral_Metal(IOR_N_Nickel, IOR_K_Nickel, Reflectance) +#end + + +#macro M_Silver (Reflectance) + M_Spectral_Metal(IOR_N_Silver, IOR_K_Silver, Reflectance) +#end + + +#macro M_Gold (Reflectance) + M_Spectral_Metal(IOR_N_Gold, IOR_K_Gold, Reflectance) +#end + + +#macro M_Platinum (Reflectance) + M_Spectral_Metal(IOR_N_Platinum, IOR_K_Platinum, Reflectance) +#end + + +#macro M_Iron (Reflectance) + M_Spectral_Metal(IOR_N_Iron, IOR_K_Iron, Reflectance) +#end + + +// commonly used alloys for jewelry + +#macro M_GoldCopper_Alloy (CopperPercentage, Reflectance) + #local GoldPercentage = 100 - CopperPercentage; + M_Spectral_Alloy ( + IOR_N_Gold, IOR_K_Gold, GoldPercentage, + IOR_N_Copper, IOR_K_Copper, CopperPercentage, + Reflectance + ) +#end + + +#macro M_GoldSilver_Alloy (SilverPercentage, Reflectance) + #local GoldPercentage = 100 - SilverPercentage; + M_Spectral_Alloy ( + IOR_N_Gold, IOR_K_Gold, GoldPercentage, + IOR_N_Silver, IOR_K_Silver, SilverPercentage, + Reflectance + ) +#end + + +#macro M_GoldNickel_Alloy (NickelPercentage, Reflectance) + #local GoldPercentage = 100 - NickelPercentage; + M_Spectral_Alloy ( + IOR_N_Gold, IOR_K_Gold, GoldPercentage, + IOR_N_Nickel, IOR_K_Nickel, NickelPercentage, + Reflectance + ) +#end + + +#macro M_GoldPlatinum_Alloy (PlatinumPercentage, Reflectance) + #local GoldPercentage = 100 - PlatinumPercentage; + M_Spectral_Alloy ( + IOR_N_Gold, IOR_K_Gold, GoldPercentage, + IOR_N_Platinum, IOR_K_Platinum, PlatinumPercentage, + Reflectance + ) +#end + + +#macro M_GoldSilverCopper (Gold, Silver, Copper, Reflectance) + M_Spectral_Alloy3 ( + IOR_N_Gold, IOR_K_Gold, Gold, + IOR_N_Silver, IOR_K_Silver, Silver, + IOR_N_Copper, IOR_K_Copper, Copper, + Reflectance + ) +#end + + + +//================================================================================ + +#end // #ifndef (spectral_metals_inc) \ No newline at end of file diff --git a/Tools/povray/spectral_minerals.inc b/Tools/povray/spectral_minerals.inc new file mode 100644 index 00000000..4a3c9a2c --- /dev/null +++ b/Tools/povray/spectral_minerals.inc @@ -0,0 +1,608 @@ +//================================================================================ +// POV-Ray spectral render materials V0.22 +// +// Minerals +// ******** +// +// For all minerals the colors are calculated from absorbing instead +// of diffuse reflection. +// +// Ive, April 2014 +// +//================================================================================ +// Update November 2015 +// - added missing macro M_Diamond_LemonYellow +//================================================================================ + +#ifndef (spectral_minerals_inc) #declare spectral_minerals_inc = 1; + +//================================================================================ + + +// Amethyst pink rgb <0.8981, 0.8441, 0.8972> + +#local S_IOR_Amethyst = spline { linear_spline + 380, 1.560613 + 400, 1.559598 + 420, 1.558582 + 440, 1.557566 + 460, 1.556551 + 480, 1.555535 + 500, 1.554520 + 520, 1.553504 + 540, 1.552488 + 560, 1.551473 + 580, 1.550457 + 600, 1.549441 + 620, 1.548426 + 640, 1.547410 + 660, 1.546395 + 680, 1.545379 + 700, 1.544363 + 720, 1.543348 + 740, 1.542332 +} + + +#local S_ABS_Amethyst = spline { linear_spline + 380, 0.248000 + 400, 0.168000 + 420, 0.113000 + 440, 0.098000 + 460, 0.101000 + 480, 0.117000 + 500, 0.138000 + 520, 0.154000 + 540, 0.160000 + 560, 0.155000 + 580, 0.142000 + 600, 0.126000 + 620, 0.109000 + 640, 0.092000 + 660, 0.079000 + 680, 0.067000 + 700, 0.057000 + 720, 0.050000 + 740, 0.045000 +} + + +// Emerald green rgb <0.7276, 0.9320, 0.8543> + +#local S_IOR_Emerald = spline { linear_spline + 380, 1.602898 + 400, 1.601483 + 420, 1.600068 + 440, 1.598654 + 460, 1.597239 + 480, 1.595824 + 500, 1.594410 + 520, 1.592995 + 540, 1.591829 + 560, 1.590797 + 580, 1.589764 + 600, 1.588890 + 620, 1.588143 + 640, 1.587397 + 660, 1.586684 + 680, 1.586103 + 700, 1.585523 + 720, 1.584942 + 740, 1.584361 +} + +#local S_ABS_Emerald = spline { linear_spline + 380, 0.184058 + 400, 0.199834 + 420, 0.220868 + 440, 0.173539 + 460, 0.141987 + 480, 0.078881 + 500, 0.036812 + 520, 0.039441 + 540, 0.068363 + 560, 0.105175 + 580, 0.147246 + 600, 0.184058 + 620, 0.231386 + 640, 0.262939 + 660, 0.241904 + 680, 0.236644 + 700, 0.131470 + 720, 0.105175 + 740, 0.089398 +} + + +// Ruby red rgb <0.8788, 0.3291, 0.6008> + +#local S_IOR_Ruby = spline { linear_spline + 380, 1.774695 + 400, 1.773289 + 420, 1.771883 + 440, 1.770477 + 460, 1.769070 + 480, 1.767664 + 500, 1.766258 + 520, 1.764852 + 540, 1.763445 + 560, 1.762039 + 580, 1.760633 + 600, 1.759227 + 620, 1.757820 + 640, 1.756414 + 660, 1.755008 + 680, 1.753602 + 700, 1.752195 + 720, 1.750789 + 740, 1.749383 +} + +#local S_ABS_Ruby = spline { linear_spline + 380, 1.000000 + 385, 1.000000 + 390, 0.869714 + 395, 0.747876 + 400, 0.790648 + 405, 0.721264 + 410, 0.721296 + 415, 0.711108 + 420, 0.688742 + 425, 0.689493 + 430, 0.698973 + 435, 0.693165 + 440, 0.689509 + 445, 0.608740 + 450, 0.454494 + 455, 0.338460 + 460, 0.256066 + 465, 0.202535 + 470, 0.179838 + 475, 0.201137 + 480, 0.179536 + 485, 0.209021 + 490, 0.256152 + 495, 0.312968 + 500, 0.378655 + 505, 0.456705 + 510, 0.529905 + 515, 0.598007 + 520, 0.665409 + 525, 0.718171 + 530, 0.743652 + 535, 0.741810 + 540, 0.737309 + 545, 0.763488 + 550, 0.739814 + 555, 0.732113 + 560, 0.735976 + 565, 0.719975 + 570, 0.699403 + 575, 0.653108 + 580, 0.591774 + 585, 0.507517 + 590, 0.417545 + 595, 0.341172 + 600, 0.278328 + 605, 0.224907 + 610, 0.178696 + 615, 0.139049 + 620, 0.104245 + 625, 0.075961 + 630, 0.056322 + 635, 0.044188 + 640, 0.036911 + 645, 0.030835 + 650, 0.026564 + 655, 0.024715 + 660, 0.039440 + 665, 0.029970 + 670, 0.033350 + 675, 0.025837 + 680, 0.018808 + 685, 0.014509 + 690, 0.014071 + 695, 0.045534 + 700, 0.012844 + 705, 0.011042 + 710, 0.009917 + 715, 0.009976 + 720, 0.009405 + 725, 0.009062 + 730, 0.008901 +} + + + +// Sapphire blue rgb <-0.0044, 0.3702, 0.7609> +// Note: negative color components are perfectly legal, they just indicate a color +// outside of the gamut of the sRGB color space + +#local S_IOR_Sapphire = spline { linear_spline + 380, 1.420000 + 400, 1.773289 + 420, 1.771883 + 440, 1.770477 + 460, 1.769070 + 480, 1.767664 + 500, 1.766258 + 520, 1.764852 + 540, 1.763445 + 560, 1.762039 + 580, 1.760633 + 600, 1.759227 + 620, 1.757820 + 640, 1.756414 + 660, 1.755008 + 680, 1.753602 + 700, 1.752195 + 720, 1.750789 + 740, 1.749383 +} + +#local S_ABS_Sapphire = spline { linear_spline + 380, 1.020000 + 400, 0.280000 + 420, 0.110000 + 440, 0.270000 + 460, 0.400000 + 480, 0.220000 + 500, 0.310000 + 520, 0.490000 + 540, 0.650000 + 560, 0.770000 + 580, 0.820000 + 600, 0.840000 + 620, 0.840000 + 640, 0.860000 + 660, 0.900000 + 680, 0.970000 + 700, 1.070000 + 720, 1.190000 + 740, 1.400000 +} + + +//Topaz rgb <0.9485, 0.9679, 0.9730> + +#local S_IOR_Topaz = spline { linear_spline + 380, 1.641430 + 400, 1.640336 + 420, 1.639242 + 440, 1.638148 + 460, 1.637055 + 480, 1.635961 + 500, 1.634867 + 520, 1.633773 + 540, 1.632680 + 560, 1.631586 + 580, 1.630492 + 600, 1.629398 + 620, 1.628305 + 640, 1.627211 + 660, 1.626117 + 680, 1.625023 + 700, 1.623930 + 720, 1.622836 + 740, 1.621742 +} + +#local S_ABS_Topaz = spline { linear_spline + 380, 0.057000 + 400, 0.038000 + 420, 0.032000 + 440, 0.029000 + 460, 0.027000 + 480, 0.026000 + 500, 0.026000 + 520, 0.027000 + 540, 0.031000 + 560, 0.036000 + 580, 0.042000 + 600, 0.046000 + 620, 0.047000 + 640, 0.045000 + 660, 0.039000 + 680, 0.033000 + 700, 0.028000 + 720, 0.024000 + 740, 0.021000 +} + + + +// Diamond + +#local S_IOR_Diamond = spline { linear_spline + 380, 2.475000 + 400, 2.465000 + 420, 2.455000 + 440, 2.448000 + 460, 2.443000 + 480, 2.438000 + 500, 2.433000 + 520, 2.428000 + 540, 2.425000 + 560, 2.422000 + 580, 2.419000 + 600, 2.416000 + 620, 2.413000 + 640, 2.410000 + 660, 2.407000 + 680, 2.404000 + 700, 2.401000 + 720, 2.398000 + 740, 2.395000 +} + + +// Diamond Natural Yellow - rgb <0.9856, 0.9924, 0.8726> + +#local S_ABS_Diamond_NaturalYellow = spline { linear_spline + 380, 0.907000 + 400, 0.904200 + 420, 0.321200 + 440, 0.098000 + 460, 0.078000 + 480, 0.068200 + 500, 0.024200 + 520, 0.013200 + 540, 0.013200 + 560, 0.013200 + 580, 0.013200 + 600, 0.013200 + 620, 0.013200 + 640, 0.013200 + 660, 0.002200 + 680, 0.002200 + 700, 0.002200 + 720, 0.002200 + 740, 0.002200 +} + + +// Diamond Fancy Yellow - rgb <1.0035, 0.9922, 0.8737> + +#local S_ABS_Diamond_FancyYellow = spline { linear_spline + 380, 0.530415 + 400, 0.346351 + 420, 0.227044 + 440, 0.138168 + 460, 0.091619 + 480, 0.059224 + 500, 0.036794 + 520, 0.019333 + 540, 0.010107 + 560, 0.008617 + 580, 0.006091 + 600, 0.001052 + 620,-0.002963 + 640, 0.001707 + 660, 0.005392 + 680, 0.005897 + 700, 0.008932 + 720, 0.013364 + 740, 0.012528 +} + + +// Diamond Lemon Yellow - rgb <0.9909, 0.9697, 0.8961> + +#local S_ABS_Diamond_LemonYellow = spline { linear_spline + 380, 0.157956 + 400, 0.128985 + 420, 0.083160 + 440, 0.082684 + 460, 0.104507 + 480, 0.109775 + 500, 0.080905 + 520, 0.023000 + 540, 0.024000 + 560, 0.026000 + 580, 0.024209 + 600, 0.020125 + 620, 0.018200 + 640, 0.018200 + 660, 0.018200 + 680, 0.018133 + 700, 0.018200 + 720, 0.018200 + 740, 0.018200 +} + + +//================================================================================ + +#if (SpectralMode) + +//================================================================================ +// SPECTRAL MODE +//================================================================================ + + +#declare IOR_Amethyst = array[36]; +#declare D_Amethyst = array[36]; + +#declare IOR_Sapphire = array[36]; +#declare D_Sapphire = array[36]; + +#declare IOR_Emerald = array[36]; +#declare D_Emerald = array[36]; + +#declare IOR_Ruby = array[36]; +#declare D_Ruby = array[36]; + +#declare IOR_Topaz = array[36]; +#declare D_Topaz = array[36]; + +#declare IOR_Diamond = array[36]; +#declare D_Diamond_NaturalYellow = array[36]; +#declare D_Diamond_FancyYellow = array[36]; +#declare D_Diamond_LemonYellow = array[36]; + + + +#for (I, 0, 35) + #local W = 380 + I*10; + + #declare IOR_Amethyst[I] = S_IOR_Amethyst(W).y; + #declare D_Amethyst[I] = 1-S_ABS_Amethyst(W).y; + + #declare IOR_Emerald[I] = S_IOR_Emerald(W).y; + #declare D_Emerald[I] = 1-S_ABS_Emerald(W).y; + + #declare IOR_Ruby[I] = S_IOR_Ruby(W).y; + #declare D_Ruby[I] = 1-S_ABS_Ruby(W).y; + + #declare IOR_Sapphire[I] = S_IOR_Sapphire(W).y; + #declare D_Sapphire[I] = 1-S_ABS_Sapphire(W).y; + + #declare IOR_Topaz[I] = S_IOR_Topaz(W).y; + #declare D_Topaz[I] = 1-S_ABS_Topaz(W).y; + + + #declare IOR_Diamond[I] = S_IOR_Diamond(W).y; + #declare D_Diamond_NaturalYellow[I] = 1-S_ABS_Diamond_NaturalYellow(W).y; + #declare D_Diamond_FancyYellow[I] = 1-S_ABS_Diamond_FancyYellow(W).y; + #declare D_Diamond_LemonYellow[I] = 1-S_ABS_Diamond_LemonYellow(W).y; + +#end + + + +//================================================================================ + +#else // !SpectralMode + +//================================================================================ +// PREVIEW MODE +//================================================================================ + + +#macro SpectralInverse(D) + spline { linear_spline + #for (I, 380, 760, 10) + I, 1 - D(I).y + #end + } +#end + +#local W = WavelengthFromIndex(WavelengthIndex); + + +#declare IOR_Amethyst = S_IOR_Amethyst(W).y; +#declare D_Amethyst = Reflective2RGB(SpectralInverse(S_ABS_Amethyst)); + +#declare IOR_Emerald = S_IOR_Emerald(W).y; +#declare D_Emerald = Reflective2RGB(SpectralInverse(S_ABS_Emerald)); + +#declare IOR_Ruby = S_IOR_Ruby(W).y; +#declare D_Ruby = Reflective2RGB(SpectralInverse(S_ABS_Ruby)); + +#declare IOR_Sapphire = S_IOR_Sapphire(W).y; +#declare D_Sapphire = Reflective2RGB(SpectralInverse(S_ABS_Sapphire)); + +#declare IOR_Topaz = S_IOR_Topaz(W).y; +#declare D_Topaz = Reflective2RGB(SpectralInverse(S_ABS_Topaz)); + + +#declare IOR_Diamond = S_IOR_Diamond(W).y; +#declare D_Diamond_NaturalYellow = Reflective2RGB(SpectralInverse(S_ABS_Diamond_NaturalYellow)); +#declare D_Diamond_FancyYellow = Reflective2RGB(SpectralInverse(S_ABS_Diamond_FancyYellow)); +#declare D_Diamond_LemonYellow = Reflective2RGB(SpectralInverse(S_ABS_Diamond_LemonYellow)); + + + +//================================================================================ + +#end // !SpectralMode + +//================================================================================ + +#macro M_Gem (D, IOR, FD) + material { + texture { + P_Spectral_Filter (D, Value_1) + finish { + ambient 0 emission 0 diffuse 0 + reflection {0 1 fresnel on} conserve_energy + } + } + interior { + IOR_Spectral(IOR) + fade_power 1001 + fade_distance FD + FadeColor_Spectral (D) + } + } +#end + + +//================================================================================ +// +// HIGH LEVEL INTERFACE +// ******************** +// +//================================================================================ + +#macro M_Amethyst(FadeDist) + M_Gem (D_Amethyst, IOR_Amethyst, FadeDist) +#end + +#macro M_Emerald(FadeDist) + M_Gem (D_Emerald, IOR_Emerald, FadeDist) +#end + +#macro M_Ruby(FadeDist) + M_Gem (D_Ruby, IOR_Ruby, FadeDist) +#end + +#macro M_Sapphire(FadeDist) + M_Gem (D_Sapphire, IOR_Sapphire, FadeDist) +#end + +#macro M_Topaz(FadeDist) + M_Gem (D_Topaz, IOR_Topaz, FadeDist) +#end + +#macro M_Diamond_NaturalYellow(FadeDist) + M_Gem (D_Diamond_NaturalYellow, IOR_Diamond, FadeDist) +#end + +#macro M_Diamond_FancyYellow(FadeDist) + M_Gem (D_Diamond_FancyYellow, IOR_Diamond, FadeDist) +#end + +#macro M_Diamond_LemonYellow(FadeDist) + M_Gem (D_Diamond_LemonYellow, IOR_Diamond, FadeDist) +#end + + +//================================================================================ + +#end // #ifndef (spectral_minerals_inc) + + + +/* + +// some debugging, only used during development + +#macro DebugColor(What, C) + #debug "\n" #debug What #debug " - rgb <" + #debug str(C.red, 1,4) #debug ", " + #debug str(C.green,1,4) #debug ", " + #debug str(C.blue, 1,4) #debug ">\n" +#end + + +DebugColor("Amethyst", rgb D_Amethyst) +DebugColor("Emerald ", rgb D_Emerald) +DebugColor("Ruby ", rgb D_Ruby) +DebugColor("Sapphire", rgb D_Sapphire) +DebugColor("Topaz ", rgb D_Topaz) +DebugColor("Diamond Natural Yellow", D_Diamond_NaturalYellow) +DebugColor("Diamond Fancy Yellow ", D_Diamond_FancyYellow) +DebugColor("Diamond Lemon Yellow ", D_Diamond_LemonYellow) + +*/ \ No newline at end of file