| 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 | } |