[1] | 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 | |
---|