1 |
#ifndef lint |
2 |
static const char RCSid[] = "$Id: rglsrc.c,v 3.5 2003/07/17 09:21:29 schorsch Exp $"; |
3 |
#endif |
4 |
/* |
5 |
* Routines for handling OpenGL light sources |
6 |
*/ |
7 |
|
8 |
#include "copyright.h" |
9 |
|
10 |
#include "radogl.h" |
11 |
|
12 |
double expval = 0.; /* global exposure value */ |
13 |
|
14 |
COLOR ambval = {0.2, 0.2, 0.2}; /* global ambient value */ |
15 |
|
16 |
int dolights = MAXLIGHTS; /* do how many more light sources? */ |
17 |
|
18 |
int glightid[MAXLIGHTS] = {GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, |
19 |
GL_LIGHT3, GL_LIGHT4, GL_LIGHT5, GL_LIGHT6, GL_LIGHT7}; |
20 |
|
21 |
static int lightlist; /* light list id */ |
22 |
|
23 |
/* source types */ |
24 |
#define L_NONE 0 |
25 |
#define L_SOURCE 1 |
26 |
#define L_FLAT 2 |
27 |
#define L_SPHERE 3 |
28 |
|
29 |
static struct { |
30 |
int type; /* light type (0 if none) */ |
31 |
MATREC *m; /* light material */ |
32 |
FVECT pos; /* light position (or direction) */ |
33 |
FVECT norm; /* flat source normal */ |
34 |
double area; /* source area (or solid angle) */ |
35 |
} lightrec[MAXLIGHTS]; /* light source list */ |
36 |
|
37 |
static int nlights; /* number of defined lights */ |
38 |
|
39 |
static void l_flatsrc(int), l_sphsrc(int), l_source(int); |
40 |
|
41 |
|
42 |
void |
43 |
lightinit() /* initialize lighting */ |
44 |
{ |
45 |
GLfloat ambv[4]; |
46 |
|
47 |
if (!dolights) |
48 |
return; |
49 |
glPushAttrib(GL_LIGHTING_BIT); |
50 |
if (expval <= FTINY && bright(ambval) > FTINY) |
51 |
expval = 0.2/bright(ambval); |
52 |
ambv[0] = expval*colval(ambval,RED); |
53 |
ambv[1] = expval*colval(ambval,GRN); |
54 |
ambv[2] = expval*colval(ambval,BLU); |
55 |
ambv[3] = 1.; |
56 |
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambv); |
57 |
glCallList(lightlist = newglist()); |
58 |
rgl_checkerr("in lightinit"); |
59 |
nlights = 0; |
60 |
} |
61 |
|
62 |
|
63 |
void |
64 |
lightclean() /* clean up light source commands */ |
65 |
{ |
66 |
if ((dolights += nlights) <= 0) |
67 |
return; |
68 |
glPopAttrib(); |
69 |
} |
70 |
|
71 |
|
72 |
void |
73 |
lightdefs() /* define light source list */ |
74 |
{ |
75 |
if (!nlights) |
76 |
return; |
77 |
glNewList(lightlist, GL_COMPILE); |
78 |
while (nlights--) { |
79 |
switch (lightrec[nlights].type) { |
80 |
case L_FLAT: |
81 |
l_flatsrc(nlights); |
82 |
break; |
83 |
case L_SPHERE: |
84 |
l_sphsrc(nlights); |
85 |
break; |
86 |
case L_SOURCE: |
87 |
l_source(nlights); |
88 |
break; |
89 |
default: |
90 |
error(CONSISTENCY, "botched light type in lightdefs"); |
91 |
} |
92 |
freemtl(lightrec[nlights].m); |
93 |
lightrec[nlights].type = L_NONE; |
94 |
} |
95 |
glEndList(); |
96 |
rgl_checkerr("defining lights"); |
97 |
} |
98 |
|
99 |
|
100 |
int |
101 |
o_source(o) /* record a distant source */ |
102 |
register OBJREC *o; |
103 |
{ |
104 |
if (!dolights || !issrcmat((MATREC *)o->os)) |
105 |
return(0); |
106 |
if (o->oargs.nfargs != 4) |
107 |
objerror(o, USER, "bad # real arguments"); |
108 |
/* record type & material */ |
109 |
lightrec[nlights].type = L_SOURCE; |
110 |
(lightrec[nlights].m = (MATREC *)o->os)->nlinks++; |
111 |
/* assign direction */ |
112 |
VCOPY(lightrec[nlights].pos, o->oargs.farg); |
113 |
/* compute solid angle */ |
114 |
if (o->oargs.farg[3] <= FTINY) |
115 |
objerror(o, USER, "zero size"); |
116 |
lightrec[nlights].area = 2.*PI*(1. - cos(PI/180./2.*o->oargs.farg[3])); |
117 |
nlights++; dolights--; |
118 |
return(1); |
119 |
} |
120 |
|
121 |
|
122 |
int |
123 |
doflatsrc(m, pos, norm, area) /* record a flat source */ |
124 |
MATREC *m; |
125 |
FVECT pos, norm; |
126 |
double area; |
127 |
{ |
128 |
if (!dolights || !issrcmat(m) || area <= FTINY) |
129 |
return(0); |
130 |
/* record type & material */ |
131 |
lightrec[nlights].type = L_FLAT; |
132 |
(lightrec[nlights].m = m)->nlinks++; |
133 |
/* assign geometry */ |
134 |
VCOPY(lightrec[nlights].pos, pos); |
135 |
VCOPY(lightrec[nlights].norm, norm); |
136 |
lightrec[nlights].area = area; |
137 |
nlights++; dolights--; |
138 |
return(1); |
139 |
} |
140 |
|
141 |
|
142 |
int |
143 |
dosphsrc(m, pos, area) /* record a spherical source */ |
144 |
register MATREC *m; |
145 |
FVECT pos; |
146 |
double area; |
147 |
{ |
148 |
if (!dolights || !issrcmat(m) || area <= FTINY) |
149 |
return(0); |
150 |
/* record type & material */ |
151 |
lightrec[nlights].type = L_SPHERE; |
152 |
(lightrec[nlights].m = m)->nlinks++; |
153 |
/* assign geometry */ |
154 |
VCOPY(lightrec[nlights].pos, pos); |
155 |
lightrec[nlights].area = area; |
156 |
nlights++; dolights--; |
157 |
return(1); |
158 |
} |
159 |
|
160 |
|
161 |
static void |
162 |
l_source(n) /* convert a distant source */ |
163 |
register int n; |
164 |
{ |
165 |
register MATREC *m = lightrec[n].m; |
166 |
int thislight = glightid[n]; |
167 |
GLfloat vec[4]; |
168 |
/* assign direction */ |
169 |
VCOPY(vec, lightrec[n].pos); |
170 |
vec[3] = 0.; |
171 |
glLightfv(thislight, GL_POSITION, vec); |
172 |
/* assign color */ |
173 |
vec[0] = expval*lightrec[n].area*colval(m->u.l.emission,RED); |
174 |
vec[1] = expval*lightrec[n].area*colval(m->u.l.emission,GRN); |
175 |
vec[2] = expval*lightrec[n].area*colval(m->u.l.emission,BLU); |
176 |
vec[3] = 1.; |
177 |
glLightfv(thislight, GL_SPECULAR, vec); |
178 |
glLightfv(thislight, GL_DIFFUSE, vec); |
179 |
vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.; |
180 |
glLightfv(thislight, GL_AMBIENT, vec); |
181 |
glEnable(thislight); |
182 |
} |
183 |
|
184 |
|
185 |
static void |
186 |
l_flatsrc(n) /* convert a flat source */ |
187 |
register int n; |
188 |
{ |
189 |
GLfloat vec[4]; |
190 |
register MATREC *m = lightrec[n].m; |
191 |
int thislight = glightid[n]; |
192 |
/* assign position */ |
193 |
VCOPY(vec, lightrec[n].pos); vec[3] = 1.; |
194 |
glLightfv(thislight, GL_POSITION, vec); |
195 |
/* assign color */ |
196 |
vec[0] = expval*lightrec[n].area*colval(m->u.l.emission,RED); |
197 |
vec[1] = expval*lightrec[n].area*colval(m->u.l.emission,GRN); |
198 |
vec[2] = expval*lightrec[n].area*colval(m->u.l.emission,BLU); |
199 |
vec[3] = 1.; |
200 |
glLightfv(thislight, GL_SPECULAR, vec); |
201 |
glLightfv(thislight, GL_DIFFUSE, vec); |
202 |
vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.; |
203 |
glLightfv(thislight, GL_AMBIENT, vec); |
204 |
glLightf(thislight, GL_SPOT_EXPONENT, 1.); |
205 |
glLightf(thislight, GL_CONSTANT_ATTENUATION, 0.); |
206 |
glLightf(thislight, GL_LINEAR_ATTENUATION, 0.); |
207 |
glLightf(thislight, GL_QUADRATIC_ATTENUATION, 1.); |
208 |
if (m->type == MAT_SPOT && m->u.l.spotang < 90.) { |
209 |
glLightf(thislight, GL_SPOT_CUTOFF, m->u.l.spotang); |
210 |
glLightfv(thislight, GL_SPOT_DIRECTION, m->u.l.spotdir); |
211 |
} else { |
212 |
glLightf(thislight, GL_SPOT_CUTOFF, 90.); |
213 |
VCOPY(vec, lightrec[n].norm); |
214 |
glLightfv(thislight, GL_SPOT_DIRECTION, vec); |
215 |
} |
216 |
glEnable(thislight); |
217 |
} |
218 |
|
219 |
|
220 |
static void |
221 |
l_sphsrc(n) /* convert a spherical source */ |
222 |
register int n; |
223 |
{ |
224 |
GLfloat vec[4]; |
225 |
register MATREC *m = lightrec[n].m; |
226 |
int thislight = glightid[n]; |
227 |
/* assign position */ |
228 |
VCOPY(vec, lightrec[n].pos); vec[3] = 1.; |
229 |
glLightfv(thislight, GL_POSITION, vec); |
230 |
/* assign color */ |
231 |
vec[0] = expval*lightrec[n].area*colval(m->u.l.emission,RED); |
232 |
vec[1] = expval*lightrec[n].area*colval(m->u.l.emission,GRN); |
233 |
vec[2] = expval*lightrec[n].area*colval(m->u.l.emission,BLU); |
234 |
vec[3] = 1.; |
235 |
glLightfv(thislight, GL_SPECULAR, vec); |
236 |
glLightfv(thislight, GL_DIFFUSE, vec); |
237 |
vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.; |
238 |
glLightfv(thislight, GL_AMBIENT, vec); |
239 |
glLightf(thislight, GL_SPOT_EXPONENT, 0.); |
240 |
glLightf(thislight, GL_CONSTANT_ATTENUATION, 0.); |
241 |
glLightf(thislight, GL_LINEAR_ATTENUATION, 0.); |
242 |
glLightf(thislight, GL_QUADRATIC_ATTENUATION, 1.); |
243 |
if (m->type == MAT_SPOT && m->u.l.spotang <= 90.) { |
244 |
glLightf(thislight, GL_SPOT_CUTOFF, m->u.l.spotang); |
245 |
glLightfv(thislight, GL_SPOT_DIRECTION, m->u.l.spotdir); |
246 |
} else |
247 |
glLightf(thislight, GL_SPOT_CUTOFF, 180.); |
248 |
glEnable(thislight); |
249 |
} |