ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

graphics/tinygl/light.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /*
00024  * This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
00025  * which is licensed under the zlib-license (see LICENSE).
00026  * It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
00027  */
00028 
00029 #include "graphics/tinygl/zgl.h"
00030 
00031 namespace TinyGL {
00032 
00033 void glopMaterial(GLContext *c, GLParam *p) {
00034     int mode = p[1].i;
00035     int type = p[2].i;
00036     Vector4 v(p[3].f, p[4].f, p[5].f, p[6].f);
00037     GLMaterial *m;
00038 
00039     if (mode == TGL_FRONT_AND_BACK) {
00040         p[1].i = TGL_FRONT;
00041         glopMaterial(c, p);
00042         mode = TGL_BACK;
00043     }
00044     if (mode == TGL_FRONT)
00045         m = &c->materials[0];
00046     else
00047         m = &c->materials[1];
00048 
00049     switch (type) {
00050     case TGL_EMISSION:
00051         m->emission = v;
00052         break;
00053     case TGL_AMBIENT:
00054         m->ambient = v;
00055         break;
00056     case TGL_DIFFUSE:
00057         m->diffuse = v;
00058         break;
00059     case TGL_SPECULAR:
00060         m->specular = v;
00061         m->has_specular = v.X != 0 || v.Y != 0 || v.Z != 0 || v.W != 1;
00062         break;
00063     case TGL_SHININESS:
00064         m->shininess = v.X;
00065         m->shininess_i = (int)(v.X / 128.0f) * SPECULAR_BUFFER_RESOLUTION;
00066         break;
00067     case TGL_AMBIENT_AND_DIFFUSE:
00068         m->diffuse = v;
00069         m->ambient = v;
00070         break;
00071     default:
00072         assert(0);
00073     }
00074 }
00075 
00076 void glopColorMaterial(GLContext *c, GLParam *p) {
00077     int mode = p[1].i;
00078     int type = p[2].i;
00079 
00080     c->current_color_material_mode = mode;
00081     c->current_color_material_type = type;
00082 }
00083 
00084 void glopLight(GLContext *c, GLParam *p) {
00085     int light = p[1].i;
00086     int type = p[2].i;
00087     Vector4 v(p[3].f, p[4].f, p[5].f, p[6].f);
00088     GLLight *l;
00089 
00090     assert(light >= TGL_LIGHT0 && light < TGL_LIGHT0 + T_MAX_LIGHTS);
00091 
00092     l = &c->lights[light - TGL_LIGHT0];
00093 
00094     switch (type) {
00095     case TGL_AMBIENT:
00096         l->ambient = v;
00097         break;
00098     case TGL_DIFFUSE:
00099         l->diffuse = v;
00100         break;
00101     case TGL_SPECULAR:
00102         l->specular = v;
00103         l->has_specular = v.X != 0 || v.Y != 0 || v.Z != 0 || v.W != 1;
00104         break;
00105     case TGL_POSITION: {
00106         Vector4 pos;
00107         c->matrix_stack_ptr[0]->transform(v, pos);
00108 
00109         l->position = pos;
00110 
00111         if (l->position.W == 0) {
00112             l->norm_position.X = pos.X;
00113             l->norm_position.Y = pos.Y;
00114             l->norm_position.Z = pos.Z;
00115             l->norm_position.normalize();
00116         }
00117     }
00118     break;
00119     case TGL_SPOT_DIRECTION:
00120         l->spot_direction.X = v.X;
00121         l->spot_direction.Y = v.Y;
00122         l->spot_direction.Z = v.Z;
00123         c->matrix_stack_ptr[0]->transform3x3(l->spot_direction, l->norm_spot_direction);
00124         l->norm_spot_direction.normalize();
00125         break;
00126     case TGL_SPOT_EXPONENT:
00127         l->spot_exponent = v.X;
00128         break;
00129     case TGL_SPOT_CUTOFF: {
00130         float a = v.X;
00131         assert(a == 180 || (a >= 0 && a <= 90));
00132         l->spot_cutoff = a;
00133         if (a != 180)
00134             l->cos_spot_cutoff = (float)(cos(a * LOCAL_PI / 180.0));
00135     }
00136     break;
00137     case TGL_CONSTANT_ATTENUATION:
00138         l->attenuation[0] = v.X;
00139         break;
00140     case TGL_LINEAR_ATTENUATION:
00141         l->attenuation[1] = v.X;
00142         break;
00143     case TGL_QUADRATIC_ATTENUATION:
00144         l->attenuation[2] = v.X;
00145         break;
00146     default:
00147         assert(0);
00148     }
00149 }
00150 
00151 void glopLightModel(GLContext *c, GLParam *p) {
00152     int pname = p[1].i;
00153 
00154     switch (pname) {
00155     case TGL_LIGHT_MODEL_AMBIENT:
00156         c->ambient_light_model = Vector4(p[2].f, p[3].f, p[4].f, p[5].f);
00157         break;
00158     case TGL_LIGHT_MODEL_LOCAL_VIEWER:
00159         c->local_light_model = (int)p[2].f;
00160         break;
00161     case TGL_LIGHT_MODEL_TWO_SIDE:
00162         c->light_model_two_side = (int)p[2].f;
00163         break;
00164     default:
00165         warning("glopLightModel: illegal pname: 0x%x", pname);
00166         break;
00167     }
00168 }
00169 
00170 
00171 static inline float clampf(float a, float min, float max) {
00172     if (a < min)
00173         return min;
00174     else if (a > max)
00175         return max;
00176     else
00177         return a;
00178 }
00179 
00180 void gl_enable_disable_light(GLContext *c, int light, int v) {
00181     GLLight *l = &c->lights[light];
00182     if (v && !l->enabled) {
00183         l->enabled = 1;
00184         if (c->first_light != l) {
00185             l->next = c->first_light;
00186             if (c->first_light)
00187                 c->first_light->prev = l;
00188             c->first_light = l;
00189             l->prev = NULL;
00190         }
00191     } else if (!v && l->enabled) {
00192         l->enabled = 0;
00193         if (!l->prev)
00194             c->first_light = l->next;
00195         else
00196             l->prev->next = l->next;
00197         if (l->next)
00198             l->next->prev = l->prev;
00199     }
00200 }
00201 
00202 // non optimized lightening model
00203 void gl_shade_vertex(GLContext *c, GLVertex *v) {
00204     float R, G, B, A;
00205     GLMaterial *m;
00206     GLLight *l;
00207     Vector3 n, s, d;
00208     float dist, tmp, att, dot, dot_spot, dot_spec;
00209     int twoside = c->light_model_two_side;
00210 
00211     m = &c->materials[0];
00212 
00213     n = v->normal;
00214 
00215     R = m->emission.X + m->ambient.X * c->ambient_light_model.X;
00216     G = m->emission.Y + m->ambient.Y * c->ambient_light_model.Y;
00217     B = m->emission.Z + m->ambient.Z * c->ambient_light_model.Z;
00218     A = clampf(m->diffuse.W, 0, 1);
00219 
00220     for (l = c->first_light; l != NULL; l = l->next) {
00221         float lR, lB, lG;
00222 
00223         // ambient
00224         lR = l->ambient.X * m->ambient.X;
00225         lG = l->ambient.Y * m->ambient.Y;
00226         lB = l->ambient.Z * m->ambient.Z;
00227 
00228         if (l->position.W == 0) {
00229             // light at infinity
00230             d.X = l->norm_position.X;
00231             d.Y = l->norm_position.Y;
00232             d.Z = l->norm_position.Z;
00233             dist = 1;
00234             att = 1;
00235         } else {
00236             // distance attenuation
00237             d.X = l->position.X - v->ec.X;
00238             d.Y = l->position.Y - v->ec.Y;
00239             d.Z = l->position.Z - v->ec.Z;
00240             dist = sqrt(d.X * d.X + d.Y * d.Y + d.Z * d.Z);
00241             att = 1.0f / (l->attenuation[0] + dist * (l->attenuation[1] +
00242                           dist * l->attenuation[2]));
00243         }
00244         dot = d.X * n.X + d.Y * n.Y + d.Z * n.Z;
00245         if (twoside && dot < 0)
00246             dot = -dot;
00247         if (dot > 0) {
00248             tmp = 1 / dist;
00249             d *= tmp;
00250             dot *= tmp;
00251             // diffuse light
00252             lR += dot * l->diffuse.X * m->diffuse.X;
00253             lG += dot * l->diffuse.Y * m->diffuse.Y;
00254             lB += dot * l->diffuse.Z * m->diffuse.Z;
00255 
00256             const bool is_spotlight = l->spot_cutoff != 180;
00257             const bool has_specular = l->has_specular && m->has_specular;
00258             if (is_spotlight || has_specular) {
00259                 if (is_spotlight) {
00260                     dot_spot = -(d.X * l->norm_spot_direction.X +
00261                                  d.Y * l->norm_spot_direction.Y +
00262                                  d.Z * l->norm_spot_direction.Z);
00263                     if (twoside && dot_spot < 0)
00264                         dot_spot = -dot_spot;
00265                     if (dot_spot < l->cos_spot_cutoff) {
00266                         // no contribution
00267                         continue;
00268                     } else {
00269                         // TODO: optimize
00270                         if (l->spot_exponent > 0) {
00271                             att = att * pow(dot_spot, l->spot_exponent);
00272                         }
00273                     }
00274                 }
00275 
00276                 if (has_specular) {
00277                     if (c->local_light_model) {
00278                         Vector3 vcoord;
00279                         vcoord.X = v->ec.X;
00280                         vcoord.Y = v->ec.Y;
00281                         vcoord.Z = v->ec.Z;
00282                         vcoord.normalize();
00283                         s.X = d.X - vcoord.X;
00284                         s.Y = d.Y - vcoord.Y;
00285                         s.Z = d.Z - vcoord.Z;
00286                     } else {
00287                         s.X = d.X;
00288                         s.Y = d.Y;
00289                         s.Z = (float)(d.Z + 1.0);
00290                     }
00291                     dot_spec = n.X * s.X + n.Y * s.Y + n.Z * s.Z;
00292                     if (twoside && dot_spec < 0)
00293                         dot_spec = -dot_spec;
00294                     if (dot_spec > 0) {
00295                         GLSpecBuf *specbuf;
00296                         int idx;
00297                         dot_spec = dot_spec / sqrt(s.X * s.X + s.Y * s.Y + s.Z * s.Z);
00298                         // TODO: optimize
00299                         // testing specular buffer code
00300                         // dot_spec= pow(dot_spec,m->shininess)
00301                         specbuf = specbuf_get_buffer(c, m->shininess_i, m->shininess);
00302                         tmp = dot_spec * SPECULAR_BUFFER_SIZE;
00303                         if (tmp > SPECULAR_BUFFER_SIZE)
00304                             idx = SPECULAR_BUFFER_SIZE;
00305                         else
00306                             idx = (int)tmp;
00307 
00308                         dot_spec = specbuf->buf[idx];
00309                         lR += dot_spec * l->specular.X * m->specular.X;
00310                         lG += dot_spec * l->specular.Y * m->specular.Y;
00311                         lB += dot_spec * l->specular.Z * m->specular.Z;
00312                     }
00313                 }
00314             }
00315         }
00316 
00317         R += att * lR;
00318         G += att * lG;
00319         B += att * lB;
00320     }
00321 
00322     v->color.X = clampf(c->current_color.X * R, 0, 1);
00323     v->color.Y = clampf(c->current_color.Y * G, 0, 1);
00324     v->color.Z = clampf(c->current_color.Z * B, 0, 1);
00325     v->color.W = c->current_color.W * A;
00326 }
00327 
00328 } // end of namespace TinyGL


Generated on Sat Mar 23 2019 05:01:46 for ResidualVM by doxygen 1.7.1
curved edge   curved edge