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