version 2.8
light.c
1 #include "zgl.h"
2 #include "msghandling.h"
3 
4 void glopMaterial(GLContext *c,GLParam *p)
5 {
6  int mode=p[1].i;
7  int type=p[2].i;
8  float *v=&p[3].f;
9  int i;
10  GLMaterial *m;
11 
12  if (mode == GL_FRONT_AND_BACK) {
13  p[1].i=GL_FRONT;
14  glopMaterial(c,p);
15  mode=GL_BACK;
16  }
17  if (mode == GL_FRONT) m=&c->materials[0];
18  else m=&c->materials[1];
19 
20  switch(type) {
21  case GL_EMISSION:
22  for(i=0;i<4;i++)
23  m->emission.v[i]=v[i];
24  break;
25  case GL_AMBIENT:
26  for(i=0;i<4;i++)
27  m->ambient.v[i]=v[i];
28  break;
29  case GL_DIFFUSE:
30  for(i=0;i<4;i++)
31  m->diffuse.v[i]=v[i];
32  break;
33  case GL_SPECULAR:
34  for(i=0;i<4;i++)
35  m->specular.v[i]=v[i];
36  break;
37  case GL_SHININESS:
38  m->shininess=v[0];
39  m->shininess_i = (v[0]/128.0f)*SPECULAR_BUFFER_RESOLUTION;
40  break;
41  case GL_AMBIENT_AND_DIFFUSE:
42  for(i=0;i<4;i++)
43  m->diffuse.v[i]=v[i];
44  for(i=0;i<4;i++)
45  m->ambient.v[i]=v[i];
46  break;
47  default:
48  gl_assert(0);
49  }
50 }
51 
52 void glopColorMaterial(GLContext *c,GLParam *p)
53 {
54  int mode=p[1].i;
55  int type=p[2].i;
56 
57  c->current_color_material_mode=mode;
58  c->current_color_material_type=type;
59 }
60 
61 void glopLight(GLContext *c,GLParam *p)
62 {
63  int light=p[1].i;
64  int type=p[2].i;
65  V4 v;
66  GLLight *l;
67  int i;
68 
69  gl_assert(light >= GL_LIGHT0 && light < GL_LIGHT0+MAX_LIGHTS );
70 
71  l=&c->lights[light-GL_LIGHT0];
72 
73  for(i=0;i<4;i++) v.v[i]=p[3+i].f;
74 
75  switch(type) {
76  case GL_AMBIENT:
77  l->ambient=v;
78  break;
79  case GL_DIFFUSE:
80  l->diffuse=v;
81  break;
82  case GL_SPECULAR:
83  l->specular=v;
84  break;
85  case GL_POSITION:
86  {
87  V4 pos;
88  gl_M4_MulV4(&pos,c->matrix_stack_ptr[0],&v);
89 
90  l->position=pos;
91 
92  if (l->position.v[3] == 0) {
93  l->norm_position.X=pos.X;
94  l->norm_position.Y=pos.Y;
95  l->norm_position.Z=pos.Z;
96 
97  gl_V3_Norm(&l->norm_position);
98  }
99  }
100  break;
101  case GL_SPOT_DIRECTION:
102  for(i=0;i<3;i++) {
103  l->spot_direction.v[i]=v.v[i];
104  l->norm_spot_direction.v[i]=v.v[i];
105  }
106  gl_V3_Norm(&l->norm_spot_direction);
107  break;
108  case GL_SPOT_EXPONENT:
109  l->spot_exponent=v.v[0];
110  break;
111  case GL_SPOT_CUTOFF:
112  {
113  float a=v.v[0];
114  gl_assert(a == 180 || (a>=0 && a<=90));
115  l->spot_cutoff=a;
116  if (a != 180) l->cos_spot_cutoff=cos(a * M_PI / 180.0);
117  }
118  break;
119  case GL_CONSTANT_ATTENUATION:
120  l->attenuation[0]=v.v[0];
121  break;
122  case GL_LINEAR_ATTENUATION:
123  l->attenuation[1]=v.v[0];
124  break;
125  case GL_QUADRATIC_ATTENUATION:
126  l->attenuation[2]=v.v[0];
127  break;
128  default:
129  gl_assert(0);
130  }
131 }
132 
133 
134 void glopLightModel(GLContext *c,GLParam *p)
135 {
136  int pname=p[1].i;
137  float *v=&p[2].f;
138  int i;
139 
140  switch(pname) {
141  case GL_LIGHT_MODEL_AMBIENT:
142  for(i=0;i<4;i++)
143  c->ambient_light_model.v[i]=v[i];
144  break;
145  case GL_LIGHT_MODEL_LOCAL_VIEWER:
146  c->local_light_model=(int)v[0];
147  break;
148  case GL_LIGHT_MODEL_TWO_SIDE:
149  c->light_model_two_side = (int)v[0];
150  break;
151  default:
152  tgl_warning("glopLightModel: illegal pname: 0x%x\n", pname);
153  //gl_assert(0);
154  break;
155  }
156 }
157 
158 
159 static inline float clampf(float a,float min,float max)
160 {
161  if (a<min) return min;
162  else if (a>max) return max;
163  else return a;
164 }
165 
166 void gl_enable_disable_light(GLContext *c,int light,int v)
167 {
168  GLLight *l=&c->lights[light];
169  if (v && !l->enabled) {
170  l->enabled=1;
171  l->next=c->first_light;
172  c->first_light=l;
173  l->prev=NULL;
174  } else if (!v && l->enabled) {
175  l->enabled=0;
176  if (l->prev == NULL) c->first_light=l->next;
177  else l->prev->next=l->next;
178  if (l->next != NULL) l->next->prev=l->prev;
179  }
180 }
181 
182 /* non optimized lightening model */
183 void gl_shade_vertex(GLContext *c,GLVertex *v)
184 {
185  float R,G,B,A;
186  GLMaterial *m;
187  GLLight *l;
188  V3 n,s,d;
189  float dist,tmp,att,dot,dot_spot,dot_spec;
190  int twoside = c->light_model_two_side;
191 
192  m=&c->materials[0];
193 
194  n.X=v->normal.X;
195  n.Y=v->normal.Y;
196  n.Z=v->normal.Z;
197 
198  R=m->emission.v[0]+m->ambient.v[0]*c->ambient_light_model.v[0];
199  G=m->emission.v[1]+m->ambient.v[1]*c->ambient_light_model.v[1];
200  B=m->emission.v[2]+m->ambient.v[2]*c->ambient_light_model.v[2];
201  A=clampf(m->diffuse.v[3],0,1);
202 
203  for(l=c->first_light;l!=NULL;l=l->next) {
204  float lR,lB,lG;
205 
206  /* ambient */
207  lR=l->ambient.v[0] * m->ambient.v[0];
208  lG=l->ambient.v[1] * m->ambient.v[1];
209  lB=l->ambient.v[2] * m->ambient.v[2];
210 
211  if (l->position.v[3] == 0) {
212  /* light at infinity */
213  d.X=l->position.v[0];
214  d.Y=l->position.v[1];
215  d.Z=l->position.v[2];
216  att=1;
217  } else {
218  /* distance attenuation */
219  d.X=l->position.v[0]-v->ec.v[0];
220  d.Y=l->position.v[1]-v->ec.v[1];
221  d.Z=l->position.v[2]-v->ec.v[2];
222  dist=sqrt(d.X*d.X+d.Y*d.Y+d.Z*d.Z);
223  if (dist>1E-3) {
224  tmp=1/dist;
225  d.X*=tmp;
226  d.Y*=tmp;
227  d.Z*=tmp;
228  }
229  att=1.0f/(l->attenuation[0]+dist*(l->attenuation[1]+
230  dist*l->attenuation[2]));
231  }
232  dot=d.X*n.X+d.Y*n.Y+d.Z*n.Z;
233  if (twoside && dot < 0) dot = -dot;
234  if (dot>0) {
235  /* diffuse light */
236  lR+=dot * l->diffuse.v[0] * m->diffuse.v[0];
237  lG+=dot * l->diffuse.v[1] * m->diffuse.v[1];
238  lB+=dot * l->diffuse.v[2] * m->diffuse.v[2];
239 
240  /* spot light */
241  if (l->spot_cutoff != 180) {
242  dot_spot=-(d.X*l->norm_spot_direction.v[0]+
243  d.Y*l->norm_spot_direction.v[1]+
244  d.Z*l->norm_spot_direction.v[2]);
245  if (twoside && dot_spot < 0) dot_spot = -dot_spot;
246  if (dot_spot < l->cos_spot_cutoff) {
247  /* no contribution */
248  continue;
249  } else {
250  /* TODO: optimize */
251  if (l->spot_exponent > 0) {
252  att=att*pow(dot_spot,l->spot_exponent);
253  }
254  }
255  }
256 
257  /* specular light */
258 
259  if (c->local_light_model) {
260  V3 vcoord;
261  vcoord.X=v->ec.X;
262  vcoord.Y=v->ec.Y;
263  vcoord.Z=v->ec.Z;
264  gl_V3_Norm(&vcoord);
265  s.X=d.X-vcoord.X;
266  s.Y=d.Y-vcoord.X;
267  s.Z=d.Z-vcoord.X;
268  } else {
269  s.X=d.X;
270  s.Y=d.Y;
271  s.Z=d.Z+1.0;
272  }
273  dot_spec=n.X*s.X+n.Y*s.Y+n.Z*s.Z;
274  if (twoside && dot_spec < 0) dot_spec = -dot_spec;
275  if (dot_spec>0) {
276  GLSpecBuf *specbuf;
277  int idx;
278  tmp=sqrt(s.X*s.X+s.Y*s.Y+s.Z*s.Z);
279  if (tmp > 1E-3) {
280  dot_spec=dot_spec / tmp;
281  }
282 
283  /* TODO: optimize */
284  /* testing specular buffer code */
285  /* dot_spec= pow(dot_spec,m->shininess);*/
286  specbuf = specbuf_get_buffer(c, m->shininess_i, m->shininess);
287  idx = (int)(dot_spec*SPECULAR_BUFFER_SIZE);
288  if (idx > SPECULAR_BUFFER_SIZE) idx = SPECULAR_BUFFER_SIZE;
289  dot_spec = specbuf->buf[idx];
290  lR+=dot_spec * l->specular.v[0] * m->specular.v[0];
291  lG+=dot_spec * l->specular.v[1] * m->specular.v[1];
292  lB+=dot_spec * l->specular.v[2] * m->specular.v[2];
293  }
294  }
295 
296  R+=att * lR;
297  G+=att * lG;
298  B+=att * lB;
299  }
300 
301  v->color.v[0]=clampf(R,0,1);
302  v->color.v[1]=clampf(G,0,1);
303  v->color.v[2]=clampf(B,0,1);
304  v->color.v[3]=A;
305 }
306