/*1Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.2All rights reserved.3Copyright (C) 2007-2010, Gabriel Dos Reis.4All rights reserved.56Redistribution and use in source and binary forms, with or without7modification, are permitted provided that the following conditions are8met:910- Redistributions of source code must retain the above copyright11notice, this list of conditions and the following disclaimer.1213- Redistributions in binary form must reproduce the above copyright14notice, this list of conditions and the following disclaimer in15the documentation and/or other materials provided with the16distribution.1718- Neither the name of The Numerical ALgorithms Group Ltd. nor the19names of its contributors may be used to endorse or promote products20derived from this software without specific prior written permission.2122THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS23IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED24TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A25PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER26OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,27EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,28PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR29PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF30LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING31NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS32SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.33*/3435#include "openaxiom-c-macros.h"36#include "spadcolors.h"3738#include <X11/Xlib.h>39#include <stdio.h>40#include <stdlib.h>41#include <math.h>4243#include "spadcolors.h"44#include "util.H1"4546#if 047int colors[100];48#endif4950static unsigned long pixels[smoothConst+1];515253/*54* make sure you define a global variable like int *spadColors; in the main55* program56*/5758/*59* code taken from Foley and Van Dam "Fundamentals of Interactive Computer60* Graphics"61*/62636465RGB66HSVtoRGB(HSV hsv)67{68RGB rgb;69float h, f, p, q, t;70int i;7172rgb.r = 0.0;73rgb.g = 0.0;74rgb.b = 0.0;75if (hsv.s == 0.0) {76rgb.r = rgb.g = rgb.b = hsv.v;77return (rgb);78}79else {80if (hsv.h == 360.0) {81hsv.h = 0.0;82}83h = hsv.h / 60;84i = floor(h);85f = h - i;86p = hsv.v * (1 - hsv.s);87q = hsv.v * (1 - (hsv.s * f));88t = hsv.v * (1 - (hsv.s * (1 - f)));89switch (i) {90case 0:91rgb.r = hsv.v;92rgb.g = t;93rgb.b = p;94break;95case 1:96rgb.r = q;97rgb.g = hsv.v;98rgb.b = p;99break;100case 2:101rgb.r = p;102rgb.g = hsv.v;103rgb.b = t;104break;105case 3:106rgb.r = p;107rgb.g = q;108rgb.b = hsv.v;109break;110case 4:111rgb.r = t;112rgb.g = p;113rgb.b = hsv.v;114break;115case 5:116rgb.r = hsv.v;117rgb.g = p;118rgb.b = q;119break;120}121return (rgb);122}123}124125float126value(float n1, float n2, float hue)127{128float v;129130if (hue > 360.0)131hue -= 360.0;132if (hue < 0.0)133hue += 360.0;134if (hue < 60.0) {135v = n1 + (n2 - n1) * hue / 60.0;136}137else {138if (hue < 180.0)139v = n2;140else {141if (hue < 240.0)142v = n1 + (n2 - n1) * (240.0 - hue) / 60.0;143else144v = n1;145}146}147return (v);148}149150151152RGB153HLStoRGB(HLS hls)154{155RGB rgb;156float m1, m2;157158if (hls.l <= 0.5) {159m2 = hls.l * (1.0 + hls.s);160}161else {162m2 = hls.l + hls.s - hls.l * hls.s;163}164m1 = 2.0 * hls.l - m2;165rgb.r = value(m1, m2, hls.h + 120.0);166rgb.g = value(m1, m2, hls.h);167rgb.b = value(m1, m2, hls.h - 120.0);168169return (rgb);170}171172173/******************************************************174* int makeColors(dsply,scrn,colorMap,total_Shades) *175* *176* This routine tries to allocate an adequate color *177* map to be used by all the OpenAxiom applications *178* that are to be run under X Windows that use *179* colors that may be user-definable (e.g. viewports, *180* HyperTeX, etc). All these application should call *181* this routine and then access the colors with the *182* the returned color map. *183* For example, the following creates the map and *184* then sets the foreground color for a GC: *185* *186* i = makeColors(d,s,&cmap,&spadColors,&ts); *187* XSetForegroundColor(d,gc,spadColors[3]); *188* *189* where *190* spadColors is of type (unsigned long *) *191* i (the return value) is the total number of colors *192* allocated. *193* ts is the total number of shades for each hue *194* *195* KF 6/14/90 (modification) *196* makeColors creates color table once only. *197* hiya is of type static. *198******************************************************/199200int201makeColors(Display *dsply, int scrn, Colormap *colorMap,202unsigned long **colorIndex, int *total_Shades)203{204205int h, s;206static unsigned long *hiya; /* keep colortable around for next time */207HSV hsv;208RGB rgb;209XColor color;210int okay = yes; /* is true (1) so long as XAllocColor is211* working ok. if 0, then we ran out of room212* on the color table. */213int colorNum;214215/* shade5 definition */216217static float saturations[5] = {0.90, 0.80, 0.74, 0.50, 0.18};218static float values[5] = {0.38, 0.58, 0.75, 0.88, 0.94};219220/* static float values[5] = {0.34, 0.52, 0.80, 0.88, 0.94}; */221222/* fprintf(stderr,"makeColors called\n");*/223224/* printf("making new colors....\n"); */225*total_Shades = totalShadesConst;226227/* space for color table */228hiya = (unsigned long *) saymem("spadcolors30.c", totalHuesConst * (*total_Shades) + 2, sizeof(unsigned long));229*colorIndex = hiya;230231for (h = 0, colorNum = 0; okay && h < 60; h += (hueStep - 6)) {232for (s = 0; okay && s < *total_Shades; s++) {233hsv.h = h;234hsv.s = saturations[s];235hsv.v = values[s];236rgb = HSVtoRGB(hsv);237color.red = rgb.r *((1<<16)-1);238color.green = rgb.g *((1<<16)-1);239color.blue = rgb.b *((1<<16)-1);240color.flags = DoRed | DoGreen | DoBlue;241/*242fprintf(stderr,"%f\t%f\t%f\n",rgb.r,rgb.g,rgb.b);243fprintf(stderr,"%d\t%d\t%d\n",color.red,color.green,color.blue);244*/245if ((okay = XAllocColor(dsply, *colorMap, &color)))246hiya[colorNum++] = color.pixel; /* hiya points to table */247} /* for s */248} /* for h */249for (h = 60; okay && h < 180; h += 20) {250for (s = 0; okay && s < *total_Shades; s++) {251hsv.h = h;252hsv.s = saturations[s];253hsv.v = values[s];254rgb = HSVtoRGB(hsv);255256color.red = rgb.r *((1<<16)-1);257color.green = rgb.g *((1<<16)-1);258color.blue = rgb.b *((1<<16)-1);259color.flags = DoRed | DoGreen | DoBlue;260/*261fprintf(stderr,"%f\t%f\t%f\n",rgb.r,rgb.g,rgb.b);262fprintf(stderr,"%d\t%d\t%d\n",color.red,color.green,color.blue);263*/264265if ((okay = XAllocColor(dsply, *colorMap, &color)))266hiya[colorNum++] = color.pixel;267}268}269270for (h = 180; okay && h <= 300; h += hueStep) {271for (s = 0; okay && s < *total_Shades; s++) {272hsv.h = h;273hsv.s = saturations[s];274hsv.v = values[s];275rgb = HSVtoRGB(hsv);276277color.red = rgb.r *((1<<16)-1);278color.green = rgb.g *((1<<16)-1);279color.blue = rgb.b *((1<<16)-1);280color.flags = DoRed | DoGreen | DoBlue;281/*282fprintf(stderr,"%f\t%f\t%f\n",rgb.r,rgb.g,rgb.b);283fprintf(stderr,"%d\t%d\t%d\n",color.red,color.green,color.blue);284*/285if ((okay = XAllocColor(dsply, *colorMap, &color)))286hiya[colorNum++] = color.pixel;287}288}289290hiya[colorNum++] = BlackPixel(dsply, scrn);291hiya[colorNum++] = WhitePixel(dsply, scrn);292293if (colorNum < (totalShadesConst * totalHuesConst + 2)) {294free(*colorIndex);295fprintf(stderr,296" > Warning: cannot allocate all the necessary colors - switching to monochrome mode\n");297*colorIndex = (unsigned long *) saymem("while allocating the colormap for OpenAxiom ", 2, sizeof(unsigned long));298(*colorIndex)[0] = BlackPixel(dsply, scrn);299(*colorIndex)[1] = WhitePixel(dsply, scrn);300return (-1);301}302303return (colorNum);304}305306#ifdef OLD307/***********************************************************************308KF 6/14/90309INPUT: display dsply, screen scrn310OUTPUT: a pointer to the permutation color vector (permIndex)311PURPOSE: when called for the first time, this procedure creates a312permutation vector of the color table spadColor. It313returns the pointer to this vector for subsequent calls.314315***********************************************************************/316317int318makePermVector(Display *dsply, int scrn, unsigned long **permIndex)319{320static int firstTime = yes;321unsigned long *spadColorsToo;322static unsigned long *pIndex;323Colormap cmap;324int num_colors;325int i, ts;326327if (firstTime) {328329/* initialization */330331cmap = DefaultColormap(dsply, scrn); /* what are other cmaps?? */332pIndex = (unsigned long *) saymem("makePermVector", Colorcells, sizeof(unsigned long));333334/* get spadColors table */335336if ((num_colors = makeColors(dsply, scrn, &cmap, &spadColorsToo, &ts)) < 0) {337printf("num_colors < 0!!\n");338exit(-1);339}340341/* initialize unused slots in permutation vector */342343for (i = 0; i < spadColorsToo[0]; i++)344pIndex[i] = 0;345for (i = num_colors; i < Colorcells; i++)346pIndex[i] = 0;347348/* make permutation vector */349350for (i = 0; i < num_colors; i++)351pIndex[spadColorsToo[i]] = i;352353firstTime = no;354}355356*permIndex = pIndex;357return (Colorcells);358}359360#endif361362/******************************************************363* int makeNewColorMap(dsply,colorMap,smoothHue) *364* *365* This routine tries to allocate an adequate color *366* map to be used by the OpenAxiom smooth shading *367* application that is to be run under X Windows. *368* The colors are allocated from available space in *369* the colorMap and returned in the array pixels. *370* The size of the array is determined by smoothConst *371* which is the number of shades desired. The colors *372* returned are variations in lightness of the hue *373* smoothHue indicated on the control panel Colormap. *374* *375* If smoothConst colors can be allocated the value *376* 1 is returned, otherwise returns 0 *377* *378******************************************************/379380381int382makeNewColorMap(Display *dsply, Colormap colorMap, int smoothHue)383384{385386int count, i;387float lightness;388RGB rgb;389XColor xcolor;390HLS hls;391392count = 0;393for (i = 0; i < (smoothConst + 1); i++) { /* i = 0 .. smoothConst */394lightness = (float) (i) / (float) (smoothConst); /* lightnes = 0.0 .. 1.0 */395hls.h = (float) smoothHue;396hls.l = lightness;397hls.s = saturation;398rgb = HLStoRGB(hls);399400xcolor.red = rgb.r *((1<<16)-1);401xcolor.green = rgb.g *((1<<16)-1);402xcolor.blue = rgb.b *((1<<16)-1);403xcolor.flags = DoRed | DoGreen | DoBlue;404/*405fprintf(stderr,"%f\t%f\t%f\n",rgb.r,rgb.g,rgb.b);406fprintf(stderr,"%d\t%d\t%d\n",xcolor.red,xcolor.green,xcolor.blue);407*/408if (XAllocColor(dsply, colorMap, &xcolor)) {409pixels[count] = xcolor.pixel;410count++;411}412}413/* count says how many succeeded */414if (count != (smoothConst+1) ) {415416/* we have failed to get all of them - free the ones we got */417418FreePixels(dsply,colorMap,count);419return (0);420}421return (1);422}423424425426/******************************************************427* unsigned long XPixelColor(num) *428* *429* XPixelColor is a straight forward function that *430* merely returns the XColor value desired within *431* the pixels array. For smooth shading, given an *432* intensity from 0..1, scaling by the number of *433* values in the array will return the location in *434* pixels[] of the desired color for that intensity. *435* *436******************************************************/437438unsigned long439XPixelColor(int num)440{441if (num < 0)442num = 0;443return (pixels[num]);444}445446447/******************************************************448* FreePixels(dsply,colorMap,num) *449* *450* FreePixels is a call to XFreeColors which frees *451* previously allocated colors for the indicated *452* colorMap. If it cannot free the number of colors *453* given by num a BadAccess error will crash the *454* viewport process. This should ONLY be used if *455* it can be guaranteed that there will be num colors *456* to free in colorMap. return 0 == success *457* *458******************************************************/459460461void462FreePixels(Display *dsply, Colormap colorMap, int num)463{464465XFreeColors(dsply, colorMap, pixels, num, 0);466}467468469470/******************************************************471* int AllocCells(dsply,colorMap,smoothHue) *472* *473* Use either makeNewColormap() OR AllocCells(). *474* This routine tries to allocate an adequate color *475* map to be used by the OpenAxiom smooth shading *476* application that is to be run under X Windows. *477* The colors are allocated from available space in *478* the colorMap and returned in the array pixels. *479* The size of the array is determined by smoothConst *480* which is the number of shades desired. The colors *481* returned are variations in lightness of the hue *482* smoothHue indicated on the control panel Colormap. *483* *484* It is different from makeNewColormap() in that *485* the cells are read/write, and if it cannot alloc *486* all the colors desired it doesn't allocate any. *487* *488******************************************************/489490491int492AllocCells(Display *dsply, Colormap colorMap, int smoothHue)493{494unsigned long plane_masks[1];495int i, count;496float lightness;497RGB rgb;498XColor xcolor;499HLS hls;500501count = 0;502for (i = 0; i < (smoothConst + 1); i++) {503lightness = (float) (i) / (float) (smoothConst);504hls.h = (float) smoothHue;505hls.l = lightness;506hls.s = saturation;507rgb = HLStoRGB(hls);508xcolor.red = rgb.r *((1<<16)-1);509xcolor.green = rgb.g *((1<<16)-1);510xcolor.blue = rgb.b *((1<<16)-1);511xcolor.flags = DoRed | DoGreen | DoBlue;512/*513fprintf(stderr,"%f\t%f\t%f\n",rgb.r,rgb.g,rgb.b);514fprintf(stderr,"%d\t%d\t%d\n",xcolor.red,xcolor.green,xcolor.blue);515*/516if (XAllocColor(dsply, colorMap, &xcolor)) {517pixels[count] = xcolor.pixel;518count++;519}520}521/* count says how many succeeded */522if (count != (smoothConst+1) ) {523/* we have failed to get all of them - free the ones we got */524FreePixels(dsply,colorMap,count);525return (0);526}527if (XAllocColorCells(dsply, colorMap, False,528plane_masks, 0, pixels, smoothConst + 1)) {529return (smoothConst + 1);530}531else {532return (0);533}534}535536537