Panda3D
colrops.c
1 /* Filename: colrops.c
2  * Created by:
3  *
4  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5  *
6  * PANDA 3D SOFTWARE
7  * Copyright (c) Carnegie Mellon University. All rights reserved.
8  *
9  * All use of this software is subject to the terms of the revised BSD
10  * license. You should have received a copy of this license along
11  * with this source code in a file named "LICENSE."
12  *
13  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
14 
15 /*
16  * Integer operations on COLR scanlines
17  */
18 
19 #include "color.h"
20 
21 #ifndef NULL
22 #define NULL 0
23 #endif
24 
25 #define bmalloc malloc
26 #if !defined(WIN32_VC) && !defined(WIN64_VC)
27 extern char *bmalloc(int);
28 #else
29 #include <malloc.h>
30 #include <math.h>
31 #endif
32 
33 #define MAXGSHIFT 31 /* maximum shift for gamma table */
34 
35 static BYTE *g_mant = NULL, *g_nexp = NULL;
36 
37 static BYTE (*g_bval)[256] = NULL;
38 
39 #ifndef pow
40 #if !defined(WIN32_VC) && !defined(WIN64_VC)
41 extern double pow(double, double);
42 #endif
43 #endif
44 
45 
46 int setcolrcor(double (*f)(double, double), double a2)
47  /* set brightness correction */
48 {
49  double mult;
50  int i, j;
51  /* allocate tables */
52  if (g_bval == NULL && (g_bval =
53  (BYTE (*)[256])bmalloc((MAXGSHIFT+1)*256)) == NULL)
54  return(-1);
55  /* compute colr -> gamb mapping */
56  mult = 1.0/256.0;
57  for (i = 0; i <= MAXGSHIFT; i++) {
58  for (j = 0; j < 256; j++)
59  g_bval[i][j] = (BYTE) (256.0 * (*f)((j+.5)*mult, a2));
60  mult *= 0.5;
61  }
62  return(0);
63 }
64 
65 
66 int setcolrinv(double (*f)(double, double), double a2)
67  /* set inverse brightness correction */
68 {
69  double mult;
70  int i, j;
71  /* allocate tables */
72  if (g_mant == NULL && (g_mant = (BYTE *)bmalloc(256)) == NULL)
73  return(-1);
74  if (g_nexp == NULL && (g_nexp = (BYTE *)bmalloc(256)) == NULL)
75  return(-1);
76  /* compute gamb -> colr mapping */
77  i = 0;
78  mult = 256.0;
79  for (j = 255; j > 0; j--) {
80  while ((g_mant[j] = (BYTE)(mult * (*f)(j/256.0, a2))) < 128) {
81  i++;
82  mult *= 2.0;
83  }
84  g_nexp[j] = i;
85  }
86  g_mant[0] = 0;
87  g_nexp[0] = COLXS;
88  return(0);
89 }
90 
91 
92 int setcolrgam(double g) /* set gamma conversion */
93 {
94  if (setcolrcor(pow, 1.0/g) < 0)
95  return(-1);
96  return(setcolrinv(pow, g));
97 }
98 
99 
100 int colrs_gambs(COLR *scan, int len)
101  /* convert scanline of colrs to gamma bytes */
102 {
103  int i, expo;
104 
105  if (g_bval == NULL)
106  return(-1);
107  while (len-- > 0) {
108  expo = scan[0][EXP] - COLXS;
109  if (expo < -MAXGSHIFT) {
110  if (expo < -MAXGSHIFT-8) {
111  scan[0][RED] =
112  scan[0][GRN] =
113  scan[0][BLU] = 0;
114  } else {
115  i = (-MAXGSHIFT-1) - expo;
116  scan[0][RED] =
117  g_bval[MAXGSHIFT][((scan[0][RED]>>i)+1)>>1];
118  scan[0][GRN] =
119  g_bval[MAXGSHIFT][((scan[0][GRN]>>i)+1)>>1];
120  scan[0][BLU] =
121  g_bval[MAXGSHIFT][((scan[0][BLU]>>i)+1)>>1];
122  }
123  } else if (expo > 0) {
124  if (expo > 8) {
125  scan[0][RED] =
126  scan[0][GRN] =
127  scan[0][BLU] = 255;
128  } else {
129  i = (scan[0][RED]<<1 | 1) << (expo-1);
130  scan[0][RED] = i > 255 ? 255 : g_bval[0][i];
131  i = (scan[0][GRN]<<1 | 1) << (expo-1);
132  scan[0][GRN] = i > 255 ? 255 : g_bval[0][i];
133  i = (scan[0][BLU]<<1 | 1) << (expo-1);
134  scan[0][BLU] = i > 255 ? 255 : g_bval[0][i];
135  }
136  } else {
137  scan[0][RED] = g_bval[-expo][scan[0][RED]];
138  scan[0][GRN] = g_bval[-expo][scan[0][GRN]];
139  scan[0][BLU] = g_bval[-expo][scan[0][BLU]];
140  }
141  scan[0][EXP] = COLXS;
142  scan++;
143  }
144  return(0);
145 }
146 
147 
148 int gambs_colrs(COLR *scan, int len)
149  /* convert gamma bytes to colr scanline */
150 {
151  int nexpo;
152 
153  if (g_mant == NULL || g_nexp == NULL)
154  return(-1);
155  while (len-- > 0) {
156  nexpo = g_nexp[scan[0][RED]];
157  if (g_nexp[scan[0][GRN]] < nexpo)
158  nexpo = g_nexp[scan[0][GRN]];
159  if (g_nexp[scan[0][BLU]] < nexpo)
160  nexpo = g_nexp[scan[0][BLU]];
161  if (nexpo < g_nexp[scan[0][RED]])
162  scan[0][RED] = g_mant[scan[0][RED]]
163  >> (g_nexp[scan[0][RED]]-nexpo);
164  else
165  scan[0][RED] = g_mant[scan[0][RED]];
166  if (nexpo < g_nexp[scan[0][GRN]])
167  scan[0][GRN] = g_mant[scan[0][GRN]]
168  >> (g_nexp[scan[0][GRN]]-nexpo);
169  else
170  scan[0][GRN] = g_mant[scan[0][GRN]];
171  if (nexpo < g_nexp[scan[0][BLU]])
172  scan[0][BLU] = g_mant[scan[0][BLU]]
173  >> (g_nexp[scan[0][BLU]]-nexpo);
174  else
175  scan[0][BLU] = g_mant[scan[0][BLU]];
176  scan[0][EXP] = COLXS - nexpo;
177  scan++;
178  }
179  return(0);
180 }
181 
182 
183 void
184 shiftcolrs(COLR *scan, int len, int adjust)
185  /* shift a scanline of colors by 2^adjust */
186 {
187  int minexp;
188 
189  if (adjust == 0)
190  return;
191  minexp = adjust < 0 ? -adjust : 0;
192  while (len-- > 0) {
193  if (scan[0][EXP] <= minexp)
194  scan[0][RED] = scan[0][GRN] = scan[0][BLU] =
195  scan[0][EXP] = 0;
196  else
197  scan[0][EXP] += adjust;
198  scan++;
199  }
200 }
201 
202 
203 void
204 normcolrs(COLR *scan, int len, int adjust)
205 /* normalize a scanline of colrs */
206 {
207  int c;
208  int shift;
209 
210  while (len-- > 0) {
211  shift = scan[0][EXP] + adjust - COLXS;
212  if (shift > 0) {
213  if (shift > 8) {
214  scan[0][RED] =
215  scan[0][GRN] =
216  scan[0][BLU] = 255;
217  } else {
218  shift--;
219  c = (scan[0][RED]<<1 | 1) << shift;
220  scan[0][RED] = c > 255 ? 255 : c;
221  c = (scan[0][GRN]<<1 | 1) << shift;
222  scan[0][GRN] = c > 255 ? 255 : c;
223  c = (scan[0][BLU]<<1 | 1) << shift;
224  scan[0][BLU] = c > 255 ? 255 : c;
225  }
226  } else if (shift < 0) {
227  if (shift < -8) {
228  scan[0][RED] =
229  scan[0][GRN] =
230  scan[0][BLU] = 0;
231  } else {
232  shift = -1-shift;
233  scan[0][RED] = ((scan[0][RED]>>shift)+1)>>1;
234  scan[0][GRN] = ((scan[0][GRN]>>shift)+1)>>1;
235  scan[0][BLU] = ((scan[0][BLU]>>shift)+1)>>1;
236  }
237  }
238  scan[0][EXP] = COLXS - adjust;
239  scan++;
240  }
241 }