Blender V2.61 - r43446

material.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <string.h>
00034 #include <math.h>
00035 #include <stddef.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "DNA_curve_types.h"
00040 #include "DNA_material_types.h"
00041 #include "DNA_mesh_types.h"
00042 #include "DNA_meshdata_types.h"
00043 #include "DNA_customdata_types.h"
00044 #include "DNA_ID.h"
00045 #include "DNA_meta_types.h"
00046 #include "DNA_node_types.h"
00047 #include "DNA_object_types.h"
00048 #include "DNA_scene_types.h"
00049 
00050 #include "BLI_math.h"       
00051 #include "BLI_listbase.h"       
00052 #include "BLI_utildefines.h"
00053 #include "BLI_bpath.h"
00054 #include "BLI_string.h"
00055 
00056 #include "BKE_animsys.h"
00057 #include "BKE_displist.h"
00058 #include "BKE_global.h"
00059 #include "BKE_icons.h"
00060 #include "BKE_image.h"
00061 #include "BKE_library.h"
00062 #include "BKE_main.h"
00063 #include "BKE_material.h"
00064 #include "BKE_mesh.h"
00065 #include "BKE_node.h"
00066 #include "BKE_curve.h"
00067 
00068 #include "GPU_material.h"
00069 
00070 /* used in UI and render */
00071 Material defmaterial;
00072 
00073 /* called on startup, creator.c */
00074 void init_def_material(void)
00075 {
00076     init_material(&defmaterial);
00077 }
00078 
00079 /* not material itself */
00080 void free_material(Material *ma)
00081 {
00082     MTex *mtex;
00083     int a;
00084     
00085     for(a=0; a<MAX_MTEX; a++) {
00086         mtex= ma->mtex[a];
00087         if(mtex && mtex->tex) mtex->tex->id.us--;
00088         if(mtex) MEM_freeN(mtex);
00089     }
00090     
00091     if(ma->ramp_col) MEM_freeN(ma->ramp_col);
00092     if(ma->ramp_spec) MEM_freeN(ma->ramp_spec);
00093     
00094     BKE_free_animdata((ID *)ma);
00095     
00096     if(ma->preview)
00097         BKE_previewimg_free(&ma->preview);
00098     BKE_icon_delete((struct ID*)ma);
00099     ma->id.icon_id = 0;
00100     
00101     /* is no lib link block, but material extension */
00102     if(ma->nodetree) {
00103         ntreeFreeTree(ma->nodetree);
00104         MEM_freeN(ma->nodetree);
00105     }
00106 
00107     if(ma->gpumaterial.first)
00108         GPU_material_free(ma);
00109 }
00110 
00111 void init_material(Material *ma)
00112 {
00113     ma->r= ma->g= ma->b= ma->ref= 0.8;
00114     ma->specr= ma->specg= ma->specb= 1.0;
00115     ma->mirr= ma->mirg= ma->mirb= 1.0;
00116     ma->spectra= 1.0;
00117     ma->amb= 1.0;
00118     ma->alpha= 1.0;
00119     ma->spec= ma->hasize= 0.5;
00120     ma->har= 50;
00121     ma->starc= ma->ringc= 4;
00122     ma->linec= 12;
00123     ma->flarec= 1;
00124     ma->flaresize= ma->subsize= 1.0;
00125     ma->flareboost= 1;
00126     ma->seed2= 6;
00127     ma->friction= 0.5;
00128     ma->refrac= 4.0;
00129     ma->roughness= 0.5;
00130     ma->param[0]= 0.5;
00131     ma->param[1]= 0.1;
00132     ma->param[2]= 0.5;
00133     ma->param[3]= 0.1;
00134     ma->rms= 0.1;
00135     ma->darkness= 1.0;  
00136     
00137     ma->strand_sta= ma->strand_end= 1.0f;
00138     
00139     ma->ang= 1.0;
00140     ma->ray_depth= 2;
00141     ma->ray_depth_tra= 2;
00142     ma->fresnel_mir= 0.0;
00143     ma->fresnel_tra= 0.0;
00144     ma->fresnel_tra_i= 1.25;
00145     ma->fresnel_mir_i= 1.25;
00146     ma->tx_limit= 0.0;
00147     ma->tx_falloff= 1.0;
00148     ma->shad_alpha= 1.0f;
00149     
00150     ma->gloss_mir = ma->gloss_tra= 1.0;
00151     ma->samp_gloss_mir = ma->samp_gloss_tra= 18;
00152     ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
00153     ma->dist_mir = 0.0;
00154     ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
00155     
00156     ma->rampfac_col= 1.0;
00157     ma->rampfac_spec= 1.0;
00158     ma->pr_lamp= 3;         /* two lamps, is bits */
00159     ma->pr_type= MA_SPHERE;
00160 
00161     ma->sss_radius[0]= 1.0f;
00162     ma->sss_radius[1]= 1.0f;
00163     ma->sss_radius[2]= 1.0f;
00164     ma->sss_col[0]= 1.0f;
00165     ma->sss_col[1]= 1.0f;
00166     ma->sss_col[2]= 1.0f;
00167     ma->sss_error= 0.05f;
00168     ma->sss_scale= 0.1f;
00169     ma->sss_ior= 1.3f;
00170     ma->sss_colfac= 1.0f;
00171     ma->sss_texfac= 0.0f;
00172     ma->sss_front= 1.0f;
00173     ma->sss_back= 1.0f;
00174 
00175     ma->vol.density = 1.0f;
00176     ma->vol.emission = 0.0f;
00177     ma->vol.scattering = 1.0f;
00178     ma->vol.reflection = 1.0f;
00179     ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f;
00180     ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f;
00181     ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f;
00182     ma->vol.density_scale = 1.0f;
00183     ma->vol.depth_cutoff = 0.01f;
00184     ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
00185     ma->vol.stepsize = 0.2f;
00186     ma->vol.shade_type = MA_VOL_SHADE_SHADED;
00187     ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
00188     ma->vol.precache_resolution = 50;
00189     ma->vol.ms_spread = 0.2f;
00190     ma->vol.ms_diff = 1.f;
00191     ma->vol.ms_intensity = 1.f;
00192     
00193     ma->game.flag = GEMAT_BACKCULL;
00194     ma->game.alpha_blend=0;
00195     ma->game.face_orientation=0;
00196     
00197     ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RAYBIAS|MA_TANGENT_STR|MA_ZTRANSP;
00198     ma->shade_flag= MA_APPROX_OCCLUSION;
00199     ma->preview = NULL;
00200 }
00201 
00202 Material *add_material(const char *name)
00203 {
00204     Material *ma;
00205 
00206     ma= alloc_libblock(&G.main->mat, ID_MA, name);
00207     
00208     init_material(ma);
00209     
00210     return ma;  
00211 }
00212 
00213 /* XXX keep synced with next function */
00214 Material *copy_material(Material *ma)
00215 {
00216     Material *man;
00217     int a;
00218     
00219     man= copy_libblock(&ma->id);
00220     
00221     id_lib_extern((ID *)man->group);
00222     
00223     for(a=0; a<MAX_MTEX; a++) {
00224         if(ma->mtex[a]) {
00225             man->mtex[a]= MEM_mallocN(sizeof(MTex), "copymaterial");
00226             memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex));
00227             id_us_plus((ID *)man->mtex[a]->tex);
00228         }
00229     }
00230     
00231     if(ma->ramp_col) man->ramp_col= MEM_dupallocN(ma->ramp_col);
00232     if(ma->ramp_spec) man->ramp_spec= MEM_dupallocN(ma->ramp_spec);
00233     
00234     if (ma->preview) man->preview = BKE_previewimg_copy(ma->preview);
00235 
00236     if(ma->nodetree) {
00237         man->nodetree= ntreeCopyTree(ma->nodetree); /* 0 == full new tree */
00238     }
00239 
00240     man->gpumaterial.first= man->gpumaterial.last= NULL;
00241     
00242     return man;
00243 }
00244 
00245 /* XXX (see above) material copy without adding to main dbase */
00246 Material *localize_material(Material *ma)
00247 {
00248     Material *man;
00249     int a;
00250     
00251     man= copy_libblock(&ma->id);
00252     BLI_remlink(&G.main->mat, man);
00253 
00254     /* no increment for texture ID users, in previewrender.c it prevents decrement */
00255     for(a=0; a<MAX_MTEX; a++) {
00256         if(ma->mtex[a]) {
00257             man->mtex[a]= MEM_mallocN(sizeof(MTex), "copymaterial");
00258             memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex));
00259         }
00260     }
00261     
00262     if(ma->ramp_col) man->ramp_col= MEM_dupallocN(ma->ramp_col);
00263     if(ma->ramp_spec) man->ramp_spec= MEM_dupallocN(ma->ramp_spec);
00264     
00265     man->preview = NULL;
00266     
00267     if(ma->nodetree)
00268         man->nodetree= ntreeLocalize(ma->nodetree);
00269     
00270     man->gpumaterial.first= man->gpumaterial.last= NULL;
00271     
00272     return man;
00273 }
00274 
00275 static void extern_local_material(Material *ma)
00276 {
00277     int i;
00278     for(i=0; i < MAX_MTEX; i++) {
00279         if(ma->mtex[i]) id_lib_extern((ID *)ma->mtex[i]->tex);
00280     }
00281 }
00282 
00283 void make_local_material(Material *ma)
00284 {
00285     Main *bmain= G.main;
00286     Object *ob;
00287     Mesh *me;
00288     Curve *cu;
00289     MetaBall *mb;
00290     int a, is_local= FALSE, is_lib= FALSE;
00291 
00292     /* - only lib users: do nothing
00293         * - only local users: set flag
00294         * - mixed: make copy
00295         */
00296     
00297     if(ma->id.lib==NULL) return;
00298 
00299     /* One local user; set flag and return. */
00300     if(ma->id.us==1) {
00301         id_clear_lib_data(bmain, &ma->id);
00302         extern_local_material(ma);
00303         return;
00304     }
00305 
00306     /* Check which other IDs reference this one to determine if it's used by
00307        lib or local */
00308     /* test objects */
00309     ob= bmain->object.first;
00310     while(ob) {
00311         if(ob->mat) {
00312             for(a=0; a<ob->totcol; a++) {
00313                 if(ob->mat[a]==ma) {
00314                     if(ob->id.lib) is_lib= TRUE;
00315                     else is_local= TRUE;
00316                 }
00317             }
00318         }
00319         ob= ob->id.next;
00320     }
00321     /* test meshes */
00322     me= bmain->mesh.first;
00323     while(me) {
00324         if(me->mat) {
00325             for(a=0; a<me->totcol; a++) {
00326                 if(me->mat[a]==ma) {
00327                     if(me->id.lib) is_lib= TRUE;
00328                     else is_local= TRUE;
00329                 }
00330             }
00331         }
00332         me= me->id.next;
00333     }
00334     /* test curves */
00335     cu= bmain->curve.first;
00336     while(cu) {
00337         if(cu->mat) {
00338             for(a=0; a<cu->totcol; a++) {
00339                 if(cu->mat[a]==ma) {
00340                     if(cu->id.lib) is_lib= TRUE;
00341                     else is_local= TRUE;
00342                 }
00343             }
00344         }
00345         cu= cu->id.next;
00346     }
00347     /* test mballs */
00348     mb= bmain->mball.first;
00349     while(mb) {
00350         if(mb->mat) {
00351             for(a=0; a<mb->totcol; a++) {
00352                 if(mb->mat[a]==ma) {
00353                     if(mb->id.lib) is_lib= TRUE;
00354                     else is_local= TRUE;
00355                 }
00356             }
00357         }
00358         mb= mb->id.next;
00359     }
00360 
00361     /* Only local users. */
00362     if(is_local && is_lib == FALSE) {
00363         id_clear_lib_data(bmain, &ma->id);
00364         extern_local_material(ma);
00365     }
00366     /* Both user and local, so copy. */
00367     else if(is_local && is_lib) {
00368         Material *ma_new= copy_material(ma);
00369 
00370         ma_new->id.us= 0;
00371 
00372         /* Remap paths of new ID using old library as base. */
00373         BKE_id_lib_local_paths(bmain, ma->id.lib, &ma_new->id);
00374 
00375         /* do objects */
00376         ob= bmain->object.first;
00377         while(ob) {
00378             if(ob->mat) {
00379                 for(a=0; a<ob->totcol; a++) {
00380                     if(ob->mat[a]==ma) {
00381                         if(ob->id.lib==NULL) {
00382                             ob->mat[a]= ma_new;
00383                             ma_new->id.us++;
00384                             ma->id.us--;
00385                         }
00386                     }
00387                 }
00388             }
00389             ob= ob->id.next;
00390         }
00391         /* do meshes */
00392         me= bmain->mesh.first;
00393         while(me) {
00394             if(me->mat) {
00395                 for(a=0; a<me->totcol; a++) {
00396                     if(me->mat[a]==ma) {
00397                         if(me->id.lib==NULL) {
00398                             me->mat[a]= ma_new;
00399                             ma_new->id.us++;
00400                             ma->id.us--;
00401                         }
00402                     }
00403                 }
00404             }
00405             me= me->id.next;
00406         }
00407         /* do curves */
00408         cu= bmain->curve.first;
00409         while(cu) {
00410             if(cu->mat) {
00411                 for(a=0; a<cu->totcol; a++) {
00412                     if(cu->mat[a]==ma) {
00413                         if(cu->id.lib==NULL) {
00414                             cu->mat[a]= ma_new;
00415                             ma_new->id.us++;
00416                             ma->id.us--;
00417                         }
00418                     }
00419                 }
00420             }
00421             cu= cu->id.next;
00422         }
00423         /* do mballs */
00424         mb= bmain->mball.first;
00425         while(mb) {
00426             if(mb->mat) {
00427                 for(a=0; a<mb->totcol; a++) {
00428                     if(mb->mat[a]==ma) {
00429                         if(mb->id.lib==NULL) {
00430                             mb->mat[a]= ma_new;
00431                             ma_new->id.us++;
00432                             ma->id.us--;
00433                         }
00434                     }
00435                 }
00436             }
00437             mb= mb->id.next;
00438         }
00439     }
00440 }
00441 
00442 /* for curve, mball, mesh types */
00443 void extern_local_matarar(struct Material **matar, short totcol)
00444 {
00445     short i;
00446     for(i= 0; i < totcol; i++) {
00447         id_lib_extern((ID *)matar[i]);
00448     }
00449 }
00450 
00451 Material ***give_matarar(Object *ob)
00452 {
00453     Mesh *me;
00454     Curve *cu;
00455     MetaBall *mb;
00456     
00457     if(ob->type==OB_MESH) {
00458         me= ob->data;
00459         return &(me->mat);
00460     }
00461     else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) {
00462         cu= ob->data;
00463         return &(cu->mat);
00464     }
00465     else if(ob->type==OB_MBALL) {
00466         mb= ob->data;
00467         return &(mb->mat);
00468     }
00469     return NULL;
00470 }
00471 
00472 short *give_totcolp(Object *ob)
00473 {
00474     Mesh *me;
00475     Curve *cu;
00476     MetaBall *mb;
00477     
00478     if(ob->type==OB_MESH) {
00479         me= ob->data;
00480         return &(me->totcol);
00481     }
00482     else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) {
00483         cu= ob->data;
00484         return &(cu->totcol);
00485     }
00486     else if(ob->type==OB_MBALL) {
00487         mb= ob->data;
00488         return &(mb->totcol);
00489     }
00490     return NULL;
00491 }
00492 
00493 /* same as above but for ID's */
00494 Material ***give_matarar_id(ID *id)
00495 {
00496     switch(GS(id->name)) {
00497     case ID_ME:
00498         return &(((Mesh *)id)->mat);
00499         break;
00500     case ID_CU:
00501         return &(((Curve *)id)->mat);
00502         break;
00503     case ID_MB:
00504         return &(((MetaBall *)id)->mat);
00505         break;
00506     }
00507     return NULL;
00508 }
00509 
00510 short *give_totcolp_id(ID *id)
00511 {
00512     switch(GS(id->name)) {
00513     case ID_ME:
00514         return &(((Mesh *)id)->totcol);
00515         break;
00516     case ID_CU:
00517         return &(((Curve *)id)->totcol);
00518         break;
00519     case ID_MB:
00520         return &(((MetaBall *)id)->totcol);
00521         break;
00522     }
00523     return NULL;
00524 }
00525 
00526 static void data_delete_material_index_id(ID *id, short index)
00527 {
00528     switch(GS(id->name)) {
00529     case ID_ME:
00530         mesh_delete_material_index((Mesh *)id, index);
00531         break;
00532     case ID_CU:
00533         curve_delete_material_index((Curve *)id, index);
00534         break;
00535     case ID_MB:
00536         /* meta-elems dont have materials atm */
00537         break;
00538     }
00539 }
00540 
00541 void material_append_id(ID *id, Material *ma)
00542 {
00543     Material ***matar;
00544     if((matar= give_matarar_id(id))) {
00545         short *totcol= give_totcolp_id(id);
00546         Material **mat= MEM_callocN(sizeof(void *) * ((*totcol) + 1), "newmatar");
00547         if(*totcol) memcpy(mat, *matar, sizeof(void *) * (*totcol));
00548         if(*matar) MEM_freeN(*matar);
00549 
00550         *matar= mat;
00551         (*matar)[(*totcol)++]= ma;
00552 
00553         id_us_plus((ID *)ma);
00554         test_object_materials(id);
00555     }
00556 }
00557 
00558 Material *material_pop_id(ID *id, int index_i, int remove_material_slot)
00559 {
00560     short index= (short)index_i;
00561     Material *ret= NULL;
00562     Material ***matar;
00563     if((matar= give_matarar_id(id))) {
00564         short *totcol= give_totcolp_id(id);
00565         if(index >= 0 && index < (*totcol)) {
00566             ret= (*matar)[index];
00567             id_us_min((ID *)ret);
00568 
00569             if (remove_material_slot) {
00570                 if(*totcol <= 1) {
00571                     *totcol= 0;
00572                     MEM_freeN(*matar);
00573                     *matar= NULL;
00574                 }
00575                 else {
00576                     Material **mat;
00577                     if(index + 1 != (*totcol))
00578                         memmove((*matar)+index, (*matar)+(index+1), sizeof(void *) * ((*totcol) - (index + 1)));
00579 
00580                     (*totcol)--;
00581                     
00582                     mat= MEM_callocN(sizeof(void *) * (*totcol), "newmatar");
00583                     memcpy(mat, *matar, sizeof(void *) * (*totcol));
00584                     MEM_freeN(*matar);
00585 
00586                     *matar= mat;
00587                     test_object_materials(id);
00588                 }
00589 
00590                 /* decrease mat_nr index */
00591                 data_delete_material_index_id(id, index);
00592             }
00593 
00594             /* don't remove material slot, only clear it*/
00595             else
00596                 (*matar)[index]= NULL;
00597         }
00598     }
00599     
00600     return ret;
00601 }
00602 
00603 Material *give_current_material(Object *ob, short act)
00604 {
00605     Material ***matarar, *ma;
00606     short *totcolp;
00607     
00608     if(ob==NULL) return NULL;
00609     
00610     /* if object cannot have material, totcolp==NULL */
00611     totcolp= give_totcolp(ob);
00612     if(totcolp==NULL || ob->totcol==0) return NULL;
00613     
00614     if(act<0) {
00615         printf("no!\n");
00616     }
00617     
00618     if(act>ob->totcol) act= ob->totcol;
00619     else if(act<=0) act= 1;
00620 
00621     if(ob->matbits && ob->matbits[act-1]) { /* in object */
00622         ma= ob->mat[act-1];
00623     }
00624     else {                              /* in data */
00625 
00626         /* check for inconsistency */
00627         if(*totcolp < ob->totcol)
00628             ob->totcol= *totcolp;
00629         if(act>ob->totcol) act= ob->totcol;
00630 
00631         matarar= give_matarar(ob);
00632         
00633         if(matarar && *matarar) ma= (*matarar)[act-1];
00634         else ma= NULL;
00635         
00636     }
00637     
00638     return ma;
00639 }
00640 
00641 ID *material_from(Object *ob, short act)
00642 {
00643 
00644     if(ob==NULL) return NULL;
00645 
00646     if(ob->totcol==0) return ob->data;
00647     if(act==0) act= 1;
00648 
00649     if(ob->matbits[act-1]) return (ID *)ob;
00650     else return ob->data;
00651 }
00652 
00653 Material *give_node_material(Material *ma)
00654 {
00655     if(ma && ma->use_nodes && ma->nodetree) {
00656         bNode *node= nodeGetActiveID(ma->nodetree, ID_MA);
00657 
00658         if(node)
00659             return (Material *)node->id;
00660     }
00661 
00662     return NULL;
00663 }
00664 
00665 /* GS reads the memory pointed at in a specific ordering. There are,
00666  * however two definitions for it. I have jotted them down here, both,
00667  * but I think the first one is actually used. The thing is that
00668  * big-endian systems might read this the wrong way round. OTOH, we
00669  * constructed the IDs that are read out with this macro explicitly as
00670  * well. I expect we'll sort it out soon... */
00671 
00672 /* from blendef: */
00673 #define GS(a)   (*((short *)(a)))
00674 
00675 /* from misc_util: flip the bytes from x  */
00676 /*  #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
00677 
00678 void resize_object_material(Object *ob, const short totcol)
00679 {
00680     Material **newmatar;
00681     char *newmatbits;
00682 
00683     if(totcol==0) {
00684         if(ob->totcol) {
00685             MEM_freeN(ob->mat);
00686             MEM_freeN(ob->matbits);
00687             ob->mat= NULL;
00688             ob->matbits= NULL;
00689         }
00690     }
00691     else if(ob->totcol<totcol) {
00692         newmatar= MEM_callocN(sizeof(void *)*totcol, "newmatar");
00693         newmatbits= MEM_callocN(sizeof(char)*totcol, "newmatbits");
00694         if(ob->totcol) {
00695             memcpy(newmatar, ob->mat, sizeof(void *)*ob->totcol);
00696             memcpy(newmatbits, ob->matbits, sizeof(char)*ob->totcol);
00697             MEM_freeN(ob->mat);
00698             MEM_freeN(ob->matbits);
00699         }
00700         ob->mat= newmatar;
00701         ob->matbits= newmatbits;
00702     }
00703     ob->totcol= totcol;
00704     if(ob->totcol && ob->actcol==0) ob->actcol= 1;
00705     if(ob->actcol>ob->totcol) ob->actcol= ob->totcol;
00706 }
00707 
00708 void test_object_materials(ID *id)
00709 {
00710     /* make the ob mat-array same size as 'ob->data' mat-array */
00711     Object *ob;
00712     short *totcol;
00713 
00714     if(id==NULL || (totcol=give_totcolp_id(id))==NULL) {
00715         return;
00716     }
00717 
00718     for(ob= G.main->object.first; ob; ob= ob->id.next) {
00719         if(ob->data==id) {
00720             resize_object_material(ob, *totcol);
00721         }
00722     }
00723 }
00724 
00725 void assign_material_id(ID *id, Material *ma, short act)
00726 {
00727     Material *mao, **matar, ***matarar;
00728     short *totcolp;
00729 
00730     if(act>MAXMAT) return;
00731     if(act<1) act= 1;
00732 
00733     /* prevent crashing when using accidentally */
00734     BLI_assert(id->lib == NULL);
00735     if(id->lib) return;
00736 
00737     /* test arraylens */
00738 
00739     totcolp= give_totcolp_id(id);
00740     matarar= give_matarar_id(id);
00741 
00742     if(totcolp==NULL || matarar==NULL) return;
00743 
00744     if(act > *totcolp) {
00745         matar= MEM_callocN(sizeof(void *)*act, "matarray1");
00746 
00747         if(*totcolp) {
00748             memcpy(matar, *matarar, sizeof(void *)*(*totcolp));
00749             MEM_freeN(*matarar);
00750         }
00751 
00752         *matarar= matar;
00753         *totcolp= act;
00754     }
00755 
00756     /* in data */
00757     mao= (*matarar)[act-1];
00758     if(mao) mao->id.us--;
00759     (*matarar)[act-1]= ma;
00760 
00761     if(ma)
00762         id_us_plus((ID *)ma);
00763 
00764     test_object_materials(id);
00765 }
00766 
00767 void assign_material(Object *ob, Material *ma, short act)
00768 {
00769     Material *mao, **matar, ***matarar;
00770     char *matbits;
00771     short *totcolp;
00772 
00773     if(act>MAXMAT) return;
00774     if(act<1) act= 1;
00775     
00776     /* prevent crashing when using accidentally */
00777     BLI_assert(ob->id.lib == NULL);
00778     if(ob->id.lib) return;
00779     
00780     /* test arraylens */
00781     
00782     totcolp= give_totcolp(ob);
00783     matarar= give_matarar(ob);
00784     
00785     if(totcolp==NULL || matarar==NULL) return;
00786     
00787     if(act > *totcolp) {
00788         matar= MEM_callocN(sizeof(void *)*act, "matarray1");
00789 
00790         if(*totcolp) {
00791             memcpy(matar, *matarar, sizeof(void *)*(*totcolp));
00792             MEM_freeN(*matarar);
00793         }
00794 
00795         *matarar= matar;
00796         *totcolp= act;
00797     }
00798     
00799     if(act > ob->totcol) {
00800         matar= MEM_callocN(sizeof(void *)*act, "matarray2");
00801         matbits= MEM_callocN(sizeof(char)*act, "matbits1");
00802         if( ob->totcol) {
00803             memcpy(matar, ob->mat, sizeof(void *)*( ob->totcol ));
00804             memcpy(matbits, ob->matbits, sizeof(char)*(*totcolp));
00805             MEM_freeN(ob->mat);
00806             MEM_freeN(ob->matbits);
00807         }
00808         ob->mat= matar;
00809         ob->matbits= matbits;
00810         ob->totcol= act;
00811 
00812         /* copy object/mesh linking, or assign based on userpref */
00813         if(ob->actcol)
00814             ob->matbits[act-1]= ob->matbits[ob->actcol-1];
00815         else
00816             ob->matbits[act-1]= (U.flag & USER_MAT_ON_OB)? 1: 0;
00817     }
00818     
00819     /* do it */
00820 
00821     if(ob->matbits[act-1]) {    /* in object */
00822         mao= ob->mat[act-1];
00823         if(mao) mao->id.us--;
00824         ob->mat[act-1]= ma;
00825     }
00826     else {  /* in data */
00827         mao= (*matarar)[act-1];
00828         if(mao) mao->id.us--;
00829         (*matarar)[act-1]= ma;
00830     }
00831 
00832     if(ma)
00833         id_us_plus((ID *)ma);
00834     test_object_materials(ob->data);
00835 }
00836 
00837 /* XXX - this calls many more update calls per object then are needed, could be optimized */
00838 void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
00839 {
00840     int actcol_orig= ob->actcol;
00841     short i;
00842 
00843     while(object_remove_material_slot(ob)) {};
00844 
00845     /* now we have the right number of slots */
00846     for(i=0; i<totcol; i++)
00847         assign_material(ob, (*matar)[i], i+1);
00848 
00849     if(actcol_orig > ob->totcol)
00850         actcol_orig= ob->totcol;
00851 
00852     ob->actcol= actcol_orig;
00853 }
00854 
00855 
00856 short find_material_index(Object *ob, Material *ma)
00857 {
00858     Material ***matarar;
00859     short a, *totcolp;
00860     
00861     if(ma==NULL) return 0;
00862     
00863     totcolp= give_totcolp(ob);
00864     matarar= give_matarar(ob);
00865     
00866     if(totcolp==NULL || matarar==NULL) return 0;
00867     
00868     for(a=0; a<*totcolp; a++)
00869         if((*matarar)[a]==ma)
00870            break;
00871     if(a<*totcolp)
00872         return a+1;
00873     return 0;      
00874 }
00875 
00876 int object_add_material_slot(Object *ob)
00877 {
00878     if(ob==NULL) return FALSE;
00879     if(ob->totcol>=MAXMAT) return FALSE;
00880     
00881     assign_material(ob, NULL, ob->totcol+1);
00882     ob->actcol= ob->totcol;
00883     return TRUE;
00884 }
00885 
00886 static void do_init_render_material(Material *ma, int r_mode, float *amb)
00887 {
00888     MTex *mtex;
00889     int a, needuv=0, needtang=0;
00890     
00891     if(ma->flarec==0) ma->flarec= 1;
00892 
00893     /* add all texcoflags from mtex, texco and mapto were cleared in advance */
00894     for(a=0; a<MAX_MTEX; a++) {
00895         
00896         /* separate tex switching */
00897         if(ma->septex & (1<<a)) continue;
00898 
00899         mtex= ma->mtex[a];
00900         if(mtex && mtex->tex && (mtex->tex->type | (mtex->tex->use_nodes && mtex->tex->nodetree) )) {
00901             
00902             ma->texco |= mtex->texco;
00903             ma->mapto |= mtex->mapto;
00904 
00905             /* always get derivatives for these textures */
00906             if ELEM3(mtex->tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) ma->texco |= TEXCO_OSA;
00907             else if(mtex->texflag & (MTEX_COMPAT_BUMP|MTEX_3TAP_BUMP|MTEX_5TAP_BUMP|MTEX_BICUBIC_BUMP)) ma->texco |= TEXCO_OSA;
00908             
00909             if(ma->texco & (TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM|TEXCO_STRAND|TEXCO_STRESS)) needuv= 1;
00910             else if(ma->texco & (TEXCO_GLOB|TEXCO_UV|TEXCO_OBJECT|TEXCO_SPEED)) needuv= 1;
00911             else if(ma->texco & (TEXCO_LAVECTOR|TEXCO_VIEW|TEXCO_STICKY)) needuv= 1;
00912 
00913             if((ma->mapto & MAP_NORM) && (mtex->normapspace == MTEX_NSPACE_TANGENT))
00914                 needtang= 1;
00915         }
00916     }
00917 
00918     if(needtang) ma->mode |= MA_NORMAP_TANG;
00919     else ma->mode &= ~MA_NORMAP_TANG;
00920     
00921     if(ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE)) {
00922         needuv= 1;
00923         if(r_mode & R_OSA) ma->texco |= TEXCO_OSA;      /* for texfaces */
00924     }
00925     if(needuv) ma->texco |= NEED_UV;
00926     
00927     /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */
00928     if(r_mode & R_RAYTRACE) {
00929         if((ma->mode & (MA_RAYMIRROR|MA_SHADOW_TRA)) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_RAYTRANSP))) {
00930             ma->texco |= NEED_UV|TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM;
00931             if(r_mode & R_OSA) ma->texco |= TEXCO_OSA;
00932         }
00933     }
00934     
00935     if(amb) {
00936         ma->ambr= ma->amb*amb[0];
00937         ma->ambg= ma->amb*amb[1];
00938         ma->ambb= ma->amb*amb[2];
00939     }   
00940     /* will become or-ed result of all node modes */
00941     ma->mode_l= ma->mode;
00942     ma->mode_l &= ~MA_SHLESS;
00943 
00944     if(ma->strand_surfnor > 0.0f)
00945         ma->mode_l |= MA_STR_SURFDIFF;
00946 
00947     /* parses the geom+tex nodes */
00948     if(ma->nodetree && ma->use_nodes)
00949         ntreeShaderGetTexcoMode(ma->nodetree, r_mode, &ma->texco, &ma->mode_l);
00950 }
00951 
00952 static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode, float *amb)
00953 {
00954     bNode *node;
00955     
00956     for(node=ntree->nodes.first; node; node= node->next) {
00957         if(node->id) {
00958             if(GS(node->id->name)==ID_MA) {
00959                 Material *ma= (Material *)node->id;
00960                 if(ma!=basemat) {
00961                     do_init_render_material(ma, r_mode, amb);
00962                     basemat->texco |= ma->texco;
00963                     basemat->mode_l |= ma->mode_l & ~(MA_TRANSP|MA_ZTRANSP|MA_RAYTRANSP); 
00964                 }
00965             }
00966             else if(node->type==NODE_GROUP)
00967                 init_render_nodetree((bNodeTree *)node->id, basemat, r_mode, amb);
00968         }
00969     }
00970 }
00971 
00972 void init_render_material(Material *mat, int r_mode, float *amb)
00973 {
00974     
00975     do_init_render_material(mat, r_mode, amb);
00976     
00977     if(mat->nodetree && mat->use_nodes) {
00978         init_render_nodetree(mat->nodetree, mat, r_mode, amb);
00979         
00980         if (!mat->nodetree->execdata)
00981             mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree, 1);
00982     }
00983 }
00984 
00985 void init_render_materials(Main *bmain, int r_mode, float *amb)
00986 {
00987     Material *ma;
00988     
00989     /* clear these flags before going over materials, to make sure they
00990      * are cleared only once, otherwise node materials contained in other
00991      * node materials can go wrong */
00992     for(ma= bmain->mat.first; ma; ma= ma->id.next) {
00993         if(ma->id.us) {
00994             ma->texco= 0;
00995             ma->mapto= 0;
00996         }
00997     }
00998 
00999     /* two steps, first initialize, then or the flags for layers */
01000     for(ma= bmain->mat.first; ma; ma= ma->id.next) {
01001         /* is_used flag comes back in convertblender.c */
01002         ma->flag &= ~MA_IS_USED;
01003         if(ma->id.us) 
01004             init_render_material(ma, r_mode, amb);
01005     }
01006     
01007     do_init_render_material(&defmaterial, r_mode, amb);
01008 }
01009 
01010 /* only needed for nodes now */
01011 void end_render_material(Material *mat)
01012 {
01013     if(mat && mat->nodetree && mat->use_nodes) {
01014         if (mat->nodetree->execdata)
01015             ntreeShaderEndExecTree(mat->nodetree->execdata, 1);
01016     }
01017 }
01018 
01019 void end_render_materials(Main *bmain)
01020 {
01021     Material *ma;
01022     for(ma= bmain->mat.first; ma; ma= ma->id.next)
01023         if(ma->id.us) 
01024             end_render_material(ma);
01025 }
01026 
01027 static int material_in_nodetree(bNodeTree *ntree, Material *mat)
01028 {
01029     bNode *node;
01030 
01031     for(node=ntree->nodes.first; node; node= node->next) {
01032         if(node->id && GS(node->id->name)==ID_MA) {
01033             if(node->id==(ID*)mat)
01034                 return 1;
01035         }
01036         else if(node->type==NODE_GROUP)
01037             if(material_in_nodetree((bNodeTree*)node->id, mat))
01038                 return 1;
01039     }
01040 
01041     return 0;
01042 }
01043 
01044 int material_in_material(Material *parmat, Material *mat)
01045 {
01046     if(parmat==mat)
01047         return 1;
01048     else if(parmat->nodetree && parmat->use_nodes)
01049         return material_in_nodetree(parmat->nodetree, mat);
01050     else
01051         return 0;
01052 }
01053     
01054 /* ****************** */
01055 
01056 static char colname_array[125][20]= {
01057 "Black","DarkRed","HalfRed","Red","Red",
01058 "DarkGreen","DarkOlive","Brown","Chocolate","OrangeRed",
01059 "HalfGreen","GreenOlive","DryOlive","Goldenrod","DarkOrange",
01060 "LightGreen","Chartreuse","YellowGreen","Yellow","Gold",
01061 "Green","LawnGreen","GreenYellow","LightOlive","Yellow",
01062 "DarkBlue","DarkPurple","HotPink","VioletPink","RedPink",
01063 "SlateGray","DarkGrey","PalePurple","IndianRed","Tomato",
01064 "SeaGreen","PaleGreen","GreenKhaki","LightBrown","LightSalmon",
01065 "SpringGreen","PaleGreen","MediumOlive","YellowBrown","LightGold",
01066 "LightGreen","LightGreen","LightGreen","GreenYellow","PaleYellow",
01067 "HalfBlue","DarkSky","HalfMagenta","VioletRed","DeepPink",
01068 "SteelBlue","SkyBlue","Orchid","LightHotPink","HotPink",
01069 "SeaGreen","SlateGray","MediumGrey","Burlywood","LightPink",
01070 "SpringGreen","Aquamarine","PaleGreen","Khaki","PaleOrange",
01071 "SpringGreen","SeaGreen","PaleGreen","PaleWhite","YellowWhite",
01072 "LightBlue","Purple","MediumOrchid","Magenta","Magenta",
01073 "RoyalBlue","SlateBlue","MediumOrchid","Orchid","Magenta",
01074 "DeepSkyBlue","LightSteelBlue","LightSkyBlue","Violet","LightPink",
01075 "Cyan","DarkTurquoise","SkyBlue","Grey","Snow",
01076 "Mint","Mint","Aquamarine","MintCream","Ivory",
01077 "Blue","Blue","DarkMagenta","DarkOrchid","Magenta",
01078 "SkyBlue","RoyalBlue","LightSlateBlue","MediumOrchid","Magenta",
01079 "DodgerBlue","SteelBlue","MediumPurple","PalePurple","Plum",
01080 "DeepSkyBlue","PaleBlue","LightSkyBlue","PalePurple","Thistle",
01081 "Cyan","ColdBlue","PaleTurquoise","GhostWhite","White"
01082 };
01083 
01084 void automatname(Material *ma)
01085 {
01086     int nr, r, g, b;
01087     float ref;
01088     
01089     if(ma==NULL) return;
01090     if(ma->mode & MA_SHLESS) ref= 1.0;
01091     else ref= ma->ref;
01092     
01093     r= (int)(4.99f*(ref*ma->r));
01094     g= (int)(4.99f*(ref*ma->g));
01095     b= (int)(4.99f*(ref*ma->b));
01096     nr= r + 5*g + 25*b;
01097     if(nr>124) nr= 124;
01098     new_id(&G.main->mat, (ID *)ma, colname_array[nr]);
01099     
01100 }
01101 
01102 
01103 int object_remove_material_slot(Object *ob)
01104 {
01105     Material *mao, ***matarar;
01106     Object *obt;
01107     short *totcolp;
01108     short a, actcol;
01109     
01110     if (ob==NULL || ob->totcol==0) {
01111         return FALSE;
01112     }
01113 
01114     /* this should never happen and used to crash */
01115     if (ob->actcol <= 0) {
01116         printf("%s: invalid material index %d, report a bug!\n", __func__, ob->actcol);
01117         BLI_assert(0);
01118         return FALSE;
01119     }
01120 
01121     /* take a mesh/curve/mball as starting point, remove 1 index,
01122      * AND with all objects that share the ob->data
01123      * 
01124      * after that check indices in mesh/curve/mball!!!
01125      */
01126     
01127     totcolp= give_totcolp(ob);
01128     matarar= give_matarar(ob);
01129 
01130     if(*matarar==NULL) return FALSE;
01131 
01132     /* we delete the actcol */
01133     mao= (*matarar)[ob->actcol-1];
01134     if(mao) mao->id.us--;
01135     
01136     for(a=ob->actcol; a<ob->totcol; a++)
01137         (*matarar)[a-1]= (*matarar)[a];
01138     (*totcolp)--;
01139     
01140     if(*totcolp==0) {
01141         MEM_freeN(*matarar);
01142         *matarar= NULL;
01143     }
01144     
01145     actcol= ob->actcol;
01146     obt= G.main->object.first;
01147     while(obt) {
01148     
01149         if(obt->data==ob->data) {
01150             
01151             /* WATCH IT: do not use actcol from ob or from obt (can become zero) */
01152             mao= obt->mat[actcol-1];
01153             if(mao) mao->id.us--;
01154         
01155             for(a=actcol; a<obt->totcol; a++) {
01156                 obt->mat[a-1]= obt->mat[a];
01157                 obt->matbits[a-1]= obt->matbits[a];
01158             }
01159             obt->totcol--;
01160             if(obt->actcol > obt->totcol) obt->actcol= obt->totcol;
01161             
01162             if(obt->totcol==0) {
01163                 MEM_freeN(obt->mat);
01164                 MEM_freeN(obt->matbits);
01165                 obt->mat= NULL;
01166                 obt->matbits= NULL;
01167             }
01168         }
01169         obt= obt->id.next;
01170     }
01171 
01172     /* check indices from mesh */
01173     if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
01174         data_delete_material_index_id((ID *)ob->data, actcol-1);
01175         freedisplist(&ob->disp);
01176     }
01177 
01178     return TRUE;
01179 }
01180 
01181 
01182 /* r_col = current value, col = new value, fac==0 is no change */
01183 void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
01184 {
01185     float tmp, facm= 1.0f-fac;
01186     
01187     switch (type) {
01188         case MA_RAMP_BLEND:
01189             r_col[0] = facm*(r_col[0]) + fac*col[0];
01190             r_col[1] = facm*(r_col[1]) + fac*col[1];
01191             r_col[2] = facm*(r_col[2]) + fac*col[2];
01192             break;
01193         case MA_RAMP_ADD:
01194             r_col[0] += fac*col[0];
01195             r_col[1] += fac*col[1];
01196             r_col[2] += fac*col[2];
01197             break;
01198         case MA_RAMP_MULT:
01199             r_col[0] *= (facm + fac*col[0]);
01200             r_col[1] *= (facm + fac*col[1]);
01201             r_col[2] *= (facm + fac*col[2]);
01202             break;
01203         case MA_RAMP_SCREEN:
01204             r_col[0] = 1.0f - (facm + fac*(1.0f - col[0])) * (1.0f - r_col[0]);
01205             r_col[1] = 1.0f - (facm + fac*(1.0f - col[1])) * (1.0f - r_col[1]);
01206             r_col[2] = 1.0f - (facm + fac*(1.0f - col[2])) * (1.0f - r_col[2]);
01207             break;
01208         case MA_RAMP_OVERLAY:
01209             if(r_col[0] < 0.5f)
01210                 r_col[0] *= (facm + 2.0f*fac*col[0]);
01211             else
01212                 r_col[0] = 1.0f - (facm + 2.0f*fac*(1.0f - col[0])) * (1.0f - r_col[0]);
01213             if(r_col[1] < 0.5f)
01214                 r_col[1] *= (facm + 2.0f*fac*col[1]);
01215             else
01216                 r_col[1] = 1.0f - (facm + 2.0f*fac*(1.0f - col[1])) * (1.0f - r_col[1]);
01217             if(r_col[2] < 0.5f)
01218                 r_col[2] *= (facm + 2.0f*fac*col[2]);
01219             else
01220                 r_col[2] = 1.0f - (facm + 2.0f*fac*(1.0f - col[2])) * (1.0f - r_col[2]);
01221             break;
01222         case MA_RAMP_SUB:
01223             r_col[0] -= fac*col[0];
01224             r_col[1] -= fac*col[1];
01225             r_col[2] -= fac*col[2];
01226             break;
01227         case MA_RAMP_DIV:
01228             if(col[0]!=0.0f)
01229                 r_col[0] = facm*(r_col[0]) + fac*(r_col[0])/col[0];
01230             if(col[1]!=0.0f)
01231                 r_col[1] = facm*(r_col[1]) + fac*(r_col[1])/col[1];
01232             if(col[2]!=0.0f)
01233                 r_col[2] = facm*(r_col[2]) + fac*(r_col[2])/col[2];
01234             break;
01235         case MA_RAMP_DIFF:
01236             r_col[0] = facm*(r_col[0]) + fac*fabsf(r_col[0]-col[0]);
01237             r_col[1] = facm*(r_col[1]) + fac*fabsf(r_col[1]-col[1]);
01238             r_col[2] = facm*(r_col[2]) + fac*fabsf(r_col[2]-col[2]);
01239             break;
01240         case MA_RAMP_DARK:
01241             tmp=col[0]+((1-col[0])*facm);
01242             if(tmp < r_col[0]) r_col[0]= tmp;
01243             tmp=col[1]+((1-col[1])*facm);
01244             if(tmp < r_col[1]) r_col[1]= tmp;
01245             tmp=col[2]+((1-col[2])*facm);
01246             if(tmp < r_col[2]) r_col[2]= tmp;
01247             break;
01248         case MA_RAMP_LIGHT:
01249             tmp= fac*col[0];
01250             if(tmp > r_col[0]) r_col[0]= tmp;
01251                 tmp= fac*col[1];
01252                 if(tmp > r_col[1]) r_col[1]= tmp;
01253                 tmp= fac*col[2];
01254                 if(tmp > r_col[2]) r_col[2]= tmp;
01255                 break;
01256         case MA_RAMP_DODGE:
01257             if(r_col[0] !=0.0f){
01258                 tmp = 1.0f - fac*col[0];
01259                 if(tmp <= 0.0f)
01260                     r_col[0] = 1.0f;
01261                 else if ((tmp = (r_col[0]) / tmp)> 1.0f)
01262                     r_col[0] = 1.0f;
01263                 else
01264                     r_col[0] = tmp;
01265             }
01266             if(r_col[1] !=0.0f){
01267                 tmp = 1.0f - fac*col[1];
01268                 if(tmp <= 0.0f )
01269                     r_col[1] = 1.0f;
01270                 else if ((tmp = (r_col[1]) / tmp) > 1.0f )
01271                     r_col[1] = 1.0f;
01272                 else
01273                     r_col[1] = tmp;
01274             }
01275             if(r_col[2] !=0.0f){
01276                 tmp = 1.0f - fac*col[2];
01277                 if(tmp <= 0.0f)
01278                     r_col[2] = 1.0f;
01279                 else if ((tmp = (r_col[2]) / tmp) > 1.0f )
01280                     r_col[2] = 1.0f;
01281                 else
01282                     r_col[2] = tmp;
01283             }
01284             break;
01285         case MA_RAMP_BURN:
01286             tmp = facm + fac*col[0];
01287 
01288             if(tmp <= 0.0f)
01289                 r_col[0] = 0.0f;
01290             else if (( tmp = (1.0f - (1.0f - (r_col[0])) / tmp )) < 0.0f)
01291                     r_col[0] = 0.0f;
01292             else if (tmp > 1.0f)
01293                 r_col[0]=1.0f;
01294             else
01295                 r_col[0] = tmp;
01296 
01297             tmp = facm + fac*col[1];
01298             if(tmp <= 0.0f)
01299                 r_col[1] = 0.0f;
01300             else if (( tmp = (1.0f - (1.0f - (r_col[1])) / tmp )) < 0.0f )
01301                     r_col[1] = 0.0f;
01302             else if(tmp >1.0f)
01303                 r_col[1]=1.0f;
01304             else
01305                 r_col[1] = tmp;
01306 
01307                 tmp = facm + fac*col[2];
01308                 if(tmp <= 0.0f)
01309                 r_col[2] = 0.0f;
01310             else if (( tmp = (1.0f - (1.0f - (r_col[2])) / tmp )) < 0.0f  )
01311                     r_col[2] = 0.0f;
01312             else if(tmp >1.0f)
01313                 r_col[2]= 1.0f;
01314             else
01315                 r_col[2] = tmp;
01316             break;
01317         case MA_RAMP_HUE:
01318             {
01319                 float rH,rS,rV;
01320                 float colH,colS,colV;
01321                 float tmpr,tmpg,tmpb;
01322                 rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
01323                 if(colS!=0 ){
01324                     rgb_to_hsv(r_col[0],r_col[1],r_col[2],&rH,&rS,&rV);
01325                     hsv_to_rgb( colH , rS, rV, &tmpr, &tmpg, &tmpb);
01326                     r_col[0] = facm*(r_col[0]) + fac*tmpr;
01327                     r_col[1] = facm*(r_col[1]) + fac*tmpg;
01328                     r_col[2] = facm*(r_col[2]) + fac*tmpb;
01329                 }
01330             }
01331             break;
01332         case MA_RAMP_SAT:
01333             {
01334                 float rH,rS,rV;
01335                 float colH,colS,colV;
01336                 rgb_to_hsv(r_col[0],r_col[1],r_col[2],&rH,&rS,&rV);
01337                 if(rS!=0){
01338                     rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
01339                     hsv_to_rgb( rH, (facm*rS +fac*colS), rV, r_col+0, r_col+1, r_col+2);
01340                 }
01341             }
01342             break;
01343         case MA_RAMP_VAL:
01344             {
01345                 float rH,rS,rV;
01346                 float colH,colS,colV;
01347                 rgb_to_hsv(r_col[0],r_col[1],r_col[2],&rH,&rS,&rV);
01348                 rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
01349                 hsv_to_rgb( rH, rS, (facm*rV +fac*colV), r_col+0, r_col+1, r_col+2);
01350             }
01351             break;
01352         case MA_RAMP_COLOR:
01353             {
01354                 float rH,rS,rV;
01355                 float colH,colS,colV;
01356                 float tmpr,tmpg,tmpb;
01357                 rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
01358                 if(colS!=0){
01359                     rgb_to_hsv(r_col[0],r_col[1],r_col[2],&rH,&rS,&rV);
01360                     hsv_to_rgb( colH, colS, rV, &tmpr, &tmpg, &tmpb);
01361                     r_col[0] = facm*(r_col[0]) + fac*tmpr;
01362                     r_col[1] = facm*(r_col[1]) + fac*tmpg;
01363                     r_col[2] = facm*(r_col[2]) + fac*tmpb;
01364                 }
01365             }
01366             break;
01367         case MA_RAMP_SOFT:
01368             {
01369                 float scr, scg, scb;
01370 
01371                 /* first calculate non-fac based Screen mix */
01372                 scr = 1.0f - (1.0f - col[0]) * (1.0f - r_col[0]);
01373                 scg = 1.0f - (1.0f - col[1]) * (1.0f - r_col[1]);
01374                 scb = 1.0f - (1.0f - col[2]) * (1.0f - r_col[2]);
01375 
01376                 r_col[0] = facm*(r_col[0]) + fac*(((1.0f - r_col[0]) * col[0] * (r_col[0])) + (r_col[0] * scr));
01377                 r_col[1] = facm*(r_col[1]) + fac*(((1.0f - r_col[1]) * col[1] * (r_col[1])) + (r_col[1] * scg));
01378                 r_col[2] = facm*(r_col[2]) + fac*(((1.0f - r_col[2]) * col[2] * (r_col[2])) + (r_col[2] * scb));
01379             }
01380             break;
01381         case MA_RAMP_LINEAR:
01382             if (col[0] > 0.5f)
01383                 r_col[0] = r_col[0] + fac*(2.0f*(col[0]-0.5f));
01384             else
01385                 r_col[0] = r_col[0] + fac*(2.0f*(col[0]) - 1.0f);
01386             if (col[1] > 0.5f)
01387                 r_col[1] = r_col[1] + fac*(2.0f*(col[1]-0.5f));
01388             else
01389                 r_col[1] = r_col[1] + fac*(2.0f*(col[1]) -1.0f);
01390             if (col[2] > 0.5f)
01391                 r_col[2] = r_col[2] + fac*(2.0f*(col[2]-0.5f));
01392             else
01393                 r_col[2] = r_col[2] + fac*(2.0f*(col[2]) - 1.0f);
01394             break;
01395     }
01396 }
01397 
01398 /* copy/paste buffer, if we had a propper py api that would be better */
01399 static Material matcopybuf;
01400 static short matcopied= 0;
01401 
01402 void clear_matcopybuf(void)
01403 {
01404     memset(&matcopybuf, 0, sizeof(Material));
01405     matcopied= 0;
01406 }
01407 
01408 void free_matcopybuf(void)
01409 {
01410     int a;
01411 
01412     for(a=0; a<MAX_MTEX; a++) {
01413         if(matcopybuf.mtex[a]) {
01414             MEM_freeN(matcopybuf.mtex[a]);
01415             matcopybuf.mtex[a]= NULL;
01416         }
01417     }
01418 
01419     if(matcopybuf.ramp_col) MEM_freeN(matcopybuf.ramp_col);
01420     if(matcopybuf.ramp_spec) MEM_freeN(matcopybuf.ramp_spec);
01421 
01422     matcopybuf.ramp_col= NULL;
01423     matcopybuf.ramp_spec= NULL;
01424 
01425     if(matcopybuf.nodetree) {
01426         ntreeFreeTree(matcopybuf.nodetree);
01427         MEM_freeN(matcopybuf.nodetree);
01428         matcopybuf.nodetree= NULL;
01429     }
01430 
01431     matcopied= 0;
01432 }
01433 
01434 void copy_matcopybuf(Material *ma)
01435 {
01436     int a;
01437     MTex *mtex;
01438 
01439     if(matcopied)
01440         free_matcopybuf();
01441 
01442     memcpy(&matcopybuf, ma, sizeof(Material));
01443     if(matcopybuf.ramp_col) matcopybuf.ramp_col= MEM_dupallocN(matcopybuf.ramp_col);
01444     if(matcopybuf.ramp_spec) matcopybuf.ramp_spec= MEM_dupallocN(matcopybuf.ramp_spec);
01445 
01446     for(a=0; a<MAX_MTEX; a++) {
01447         mtex= matcopybuf.mtex[a];
01448         if(mtex) {
01449             matcopybuf.mtex[a]= MEM_dupallocN(mtex);
01450         }
01451     }
01452     matcopybuf.nodetree= ntreeCopyTree(ma->nodetree);
01453     matcopybuf.preview= NULL;
01454     matcopybuf.gpumaterial.first= matcopybuf.gpumaterial.last= NULL;
01455     matcopied= 1;
01456 }
01457 
01458 void paste_matcopybuf(Material *ma)
01459 {
01460     int a;
01461     MTex *mtex;
01462     ID id;
01463 
01464     if(matcopied==0)
01465         return;
01466     /* free current mat */
01467     if(ma->ramp_col) MEM_freeN(ma->ramp_col);
01468     if(ma->ramp_spec) MEM_freeN(ma->ramp_spec);
01469     for(a=0; a<MAX_MTEX; a++) {
01470         mtex= ma->mtex[a];
01471         if(mtex && mtex->tex) mtex->tex->id.us--;
01472         if(mtex) MEM_freeN(mtex);
01473     }
01474 
01475     if(ma->nodetree) {
01476         ntreeFreeTree(ma->nodetree);
01477         MEM_freeN(ma->nodetree);
01478     }
01479 
01480     GPU_material_free(ma);
01481 
01482     id= (ma->id);
01483     memcpy(ma, &matcopybuf, sizeof(Material));
01484     (ma->id)= id;
01485 
01486     if(matcopybuf.ramp_col) ma->ramp_col= MEM_dupallocN(matcopybuf.ramp_col);
01487     if(matcopybuf.ramp_spec) ma->ramp_spec= MEM_dupallocN(matcopybuf.ramp_spec);
01488 
01489     for(a=0; a<MAX_MTEX; a++) {
01490         mtex= ma->mtex[a];
01491         if(mtex) {
01492             ma->mtex[a]= MEM_dupallocN(mtex);
01493             if(mtex->tex) id_us_plus((ID *)mtex->tex);
01494         }
01495     }
01496 
01497     ma->nodetree= ntreeCopyTree(matcopybuf.nodetree);
01498 }
01499 
01500 
01501 /*********************** texface to material convert functions **********************/
01502 /* encode all the TF information into a single int */
01503 static int encode_tfaceflag(MTFace *tf, int convertall)
01504 {
01505     /* calculate the flag */
01506     int flag = tf->mode;
01507 
01508     /* options that change the material offline render */   
01509     if (!convertall) {
01510         flag &= ~TF_OBCOL;
01511     }
01512 
01513     /* clean flags that are not being converted */
01514     flag &= ~TF_TEX;
01515     flag &= ~TF_SHAREDVERT;
01516     flag &= ~TF_SHAREDCOL;
01517     flag &= ~TF_CONVERTED;
01518 
01519     /* light tface flag is ignored in GLSL mode */
01520     flag &= ~TF_LIGHT;
01521     
01522     /* 15 is how big the flag can be - hardcoded here and in decode_tfaceflag() */
01523     flag |= tf->transp << 15;
01524     
01525     /* increase 1 so flag 0 is different than no flag yet */
01526     return flag + 1;
01527 }
01528 
01529 /* set the material options based in the tface flag */
01530 static void decode_tfaceflag(Material *ma, int flag, int convertall)
01531 {
01532     int alphablend; 
01533     GameSettings *game= &ma->game;
01534 
01535     /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
01536     flag -= 1;
01537 
01538     alphablend = flag >> 15; //encoded in the encode_tfaceflag function
01539     (*game).flag = 0;
01540     
01541     /* General Material Options */
01542     if ((flag & TF_DYNAMIC)==0) (*game).flag    |= GEMAT_NOPHYSICS;
01543     
01544     /* Material Offline Rendering Properties */
01545     if (convertall) {
01546         if (flag & TF_OBCOL) ma->shade_flag |= MA_OBCOLOR;
01547     }
01548     
01549     /* Special Face Properties */
01550     if ((flag & TF_TWOSIDE)==0) (*game).flag |= GEMAT_BACKCULL;
01551     if (flag & TF_INVISIBLE)(*game).flag |= GEMAT_INVISIBLE;
01552     if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT;
01553     
01554     /* Face Orientation */
01555     if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO;
01556     else if (flag & TF_BILLBOARD2) (*game).face_orientation |= GEMAT_BILLBOARD;
01557     else if (flag & TF_SHADOW) (*game).face_orientation |= GEMAT_SHADOW;
01558     
01559     /* Alpha Blend */
01560     if (flag & TF_ALPHASORT && ELEM(alphablend, TF_ALPHA, TF_ADD)) (*game).alpha_blend = GEMAT_ALPHA_SORT;
01561     else if (alphablend & TF_ALPHA) (*game).alpha_blend = GEMAT_ALPHA;
01562     else if (alphablend & TF_ADD) (*game).alpha_blend = GEMAT_ADD;
01563     else if (alphablend & TF_CLIP) (*game).alpha_blend = GEMAT_CLIP;
01564 }
01565 
01566 /* boolean check to see if the mesh needs a material */
01567 static int check_tfaceneedmaterial(int flag)
01568 {
01569     // check if the flags we have are not deprecated != than default material options
01570     // also if only flags are visible and collision see if all objects using this mesh have this option in physics
01571 
01572     /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
01573     flag -=1;
01574 
01575     // deprecated flags
01576     flag &= ~TF_OBCOL;
01577     flag &= ~TF_SHAREDVERT;
01578     flag &= ~TF_SHAREDCOL;
01579 
01580     /* light tface flag is ignored in GLSL mode */
01581     flag &= ~TF_LIGHT;
01582     
01583     // automatic detected if tex image has alpha
01584     flag &= ~(TF_ALPHA << 15);
01585     // automatic detected if using texture
01586     flag &= ~TF_TEX;
01587 
01588     // settings for the default NoMaterial
01589     if (flag == TF_DYNAMIC)
01590         return 0;
01591 
01592     else
01593         return 1;
01594 }
01595 
01596 /* return number of digits of an integer */
01597 // XXX to be optmized or replaced by an equivalent blender internal function
01598 static int integer_getdigits(int number)
01599 {
01600     int i=0;
01601     if (number == 0) return 1;
01602 
01603     while (number != 0){
01604         number = (int)(number/10);
01605         i++;
01606     }
01607     return i;
01608 }
01609 
01610 static void calculate_tface_materialname(char *matname, char *newname, int flag)
01611 {
01612     // if flag has only light and collision and material matches those values
01613     // you can do strcpy(name, mat_name);
01614     // otherwise do:
01615     int digits = integer_getdigits(flag);
01616     /* clamp the old name, remove the MA prefix and add the .TF.flag suffix
01617     e.g. matname = "MALoooooooooooooongName"; newname = "Loooooooooooooon.TF.2" */
01618     BLI_snprintf(newname, MAX_ID_NAME, "%.*s.TF.%0*d", MAX_ID_NAME-(digits+5), matname, digits, flag);
01619 }
01620 
01621 /* returns -1 if no match */
01622 static short mesh_getmaterialnumber(Mesh *me, Material *ma)
01623 {
01624     short a;
01625 
01626     for (a=0; a<me->totcol; a++) {
01627         if (me->mat[a] == ma) {
01628             return a;
01629         }
01630     }
01631 
01632     return -1;
01633 }
01634 
01635 /* append material */
01636 static short mesh_addmaterial(Mesh *me, Material *ma)
01637 {
01638     material_append_id(&me->id, NULL);
01639     me->mat[me->totcol-1]= ma;
01640 
01641     id_us_plus(&ma->id);
01642 
01643     return me->totcol-1;
01644 }
01645 
01646 static void set_facetexture_flags(Material *ma, Image *image)
01647 {
01648     if(image) {
01649         ma->mode |= MA_FACETEXTURE;
01650         /* we could check if the texture has alpha, but then more meshes sharing the same
01651          * material may need it. Let's make it simple. */
01652         if(BKE_image_has_alpha(image))
01653             ma->mode |= MA_FACETEXTURE_ALPHA;
01654     }
01655 }
01656 
01657 /* returns material number */
01658 static short convert_tfacenomaterial(Main *main, Mesh *me, MTFace *tf, int flag)
01659 {
01660     Material *ma;
01661     char idname[MAX_ID_NAME];
01662     short mat_nr= -1;
01663     
01664     /* new material, the name uses the flag*/
01665     BLI_snprintf(idname, sizeof(idname), "MAMaterial.TF.%0*d", integer_getdigits(flag), flag);
01666 
01667     if ((ma= BLI_findstring(&main->mat, idname+2, offsetof(ID, name)+2))) {
01668         mat_nr= mesh_getmaterialnumber(me, ma);
01669         /* assign the material to the mesh */
01670         if(mat_nr == -1) mat_nr= mesh_addmaterial(me, ma);
01671 
01672         /* if needed set "Face Textures [Alpha]" Material options */
01673         set_facetexture_flags(ma, tf->tpage);
01674     }
01675     /* create a new material */
01676     else {
01677         ma= add_material(idname+2);
01678 
01679         if(ma){
01680             printf("TexFace Convert: Material \"%s\" created.\n", idname+2);
01681             mat_nr= mesh_addmaterial(me, ma);
01682             
01683             /* if needed set "Face Textures [Alpha]" Material options */
01684             set_facetexture_flags(ma, tf->tpage);
01685 
01686             decode_tfaceflag(ma, flag, 1);
01687             // the final decoding will happen after, outside the main loop
01688             // for now store the flag into the material and change light/tex/collision 
01689             // store the flag as a negative number
01690             ma->game.flag = -flag;
01691             id_us_min((ID *)ma);    
01692         }
01693         else printf("Error: Unable to create Material \"%s\" for Mesh \"%s\".", idname+2, me->id.name+2);
01694     }
01695 
01696     /* set as converted, no need to go bad to this face */
01697     tf->mode |= TF_CONVERTED;   
01698     return mat_nr;
01699 }
01700 
01701 /* Function to fully convert materials */
01702 static void convert_tfacematerial(Main *main, Material *ma)
01703 {
01704     Mesh *me;
01705     Material *mat_new;
01706     MFace *mf;
01707     MTFace *tf;
01708     int flag, index;
01709     int a;
01710     short mat_nr;
01711     CustomDataLayer *cdl;
01712     char idname[MAX_ID_NAME];
01713 
01714     for(me=main->mesh.first; me; me=me->id.next){
01715         /* check if this mesh uses this material */
01716         for(a=0;a<me->totcol;a++)
01717             if(me->mat[a] == ma) break;
01718             
01719         /* no material found */
01720         if (a == me->totcol) continue;
01721 
01722         /* get the active tface layer */
01723         index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
01724         cdl= (index == -1)? NULL: &me->fdata.layers[index];
01725         if (!cdl) continue;
01726 
01727         /* loop over all the faces and stop at the ones that use the material*/
01728         for(a=0, mf=me->mface; a<me->totface; a++, mf++) {
01729             if(me->mat[mf->mat_nr] != ma) continue;
01730 
01731             /* texface data for this face */
01732             tf = ((MTFace*)cdl->data) + a;
01733             flag = encode_tfaceflag(tf, 1);
01734 
01735             /* the name of the new material */
01736             calculate_tface_materialname(ma->id.name, (char *)&idname, flag);
01737 
01738             if ((mat_new= BLI_findstring(&main->mat, idname+2, offsetof(ID, name)+2))) {
01739                 /* material already existent, see if the mesh has it */
01740                 mat_nr = mesh_getmaterialnumber(me, mat_new);
01741                 /* material is not in the mesh, add it */
01742                 if(mat_nr == -1) mat_nr= mesh_addmaterial(me, mat_new);
01743             }
01744             /* create a new material */
01745             else {
01746                 mat_new=copy_material(ma);
01747                 if(mat_new){
01748                     /* rename the material*/
01749                     strcpy(mat_new->id.name, idname);
01750                     id_us_min((ID *)mat_new);   
01751 
01752                     mat_nr= mesh_addmaterial(me, mat_new);
01753                     decode_tfaceflag(mat_new, flag, 1);
01754                 }
01755                 else {
01756                     printf("Error: Unable to create Material \"%s\" for Mesh \"%s.", idname+2, me->id.name+2);
01757                     mat_nr = mf->mat_nr;
01758                     continue;
01759                 }
01760             }
01761             
01762             /* if the material has a texture but no texture channel
01763              * set "Face Textures [Alpha]" Material options 
01764              * actually we need to run it always, because of old behavior
01765              * of using face texture if any texture channel was present (multitex) */
01766             //if((!mat_new->mtex[0]) && (!mat_new->mtex[0]->tex))
01767             set_facetexture_flags(mat_new, tf->tpage);
01768 
01769             /* set the material number to the face*/
01770             mf->mat_nr = mat_nr;
01771         }
01772         /* remove material from mesh */
01773         for(a=0;a<me->totcol;)
01774             if(me->mat[a] == ma) material_pop_id(&me->id, a, 1);else a++;
01775     }
01776 }
01777 
01778 
01779 #define MAT_BGE_DISPUTED -99999
01780 
01781 int do_version_tface(Main *main, int fileload)
01782 {
01783     Mesh *me;
01784     Material *ma;
01785     MFace *mf;
01786     MTFace *tf;
01787     CustomDataLayer *cdl;
01788     int a;
01789     int flag;
01790     int index;
01791 
01792     /* sometimes mesh has no materials but will need a new one. In those
01793      * cases we need to ignore the mf->mat_nr and only look at the face
01794      * mode because it can be zero as uninitialized or the 1st created material
01795      */
01796     int nomaterialslots;
01797 
01798     /* alert to user to check the console */
01799     int nowarning = 1;
01800 
01801     /* mark all the materials to conversion with a flag
01802      * if there is tface create a complete flag for that storing in flag
01803      * if there is tface and flag > 0: creates a new flag based on this face
01804      * if flags are different set flag to -1  
01805      */
01806     
01807     /* 1st part: marking mesh materials to update */
01808     for(me=main->mesh.first; me; me=me->id.next){
01809         if (me->id.lib) continue;
01810 
01811         /* get the active tface layer */
01812         index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
01813         cdl= (index == -1)? NULL: &me->fdata.layers[index];
01814         if (!cdl) continue;
01815 
01816         nomaterialslots = (me->totcol==0?1:0);
01817         
01818         /* loop over all the faces*/
01819         for(a=0, mf=me->mface; a<me->totface; a++, mf++) {
01820             /* texface data for this face */
01821             tf = ((MTFace*)cdl->data) + a;
01822 
01823             /* conversion should happen only once */
01824             if (fileload)
01825                 tf->mode &= ~TF_CONVERTED;
01826             else {
01827                 if((tf->mode & TF_CONVERTED)) continue;
01828                 else tf->mode |= TF_CONVERTED;
01829             }
01830             
01831             /* no material slots */
01832             if(nomaterialslots) {
01833                 flag = encode_tfaceflag(tf, 1);
01834                 
01835                 /* create/find a new material and assign to the face */
01836                 if (check_tfaceneedmaterial(flag)) {
01837                     mf->mat_nr= convert_tfacenomaterial(main, me, tf, flag);
01838                 }
01839                 /* else mark them as no-material to be reverted to 0 later */
01840                 else {
01841                     mf->mat_nr = -1;
01842                 }
01843             }
01844             else if(mf->mat_nr < me->totcol) {
01845                 ma= me->mat[mf->mat_nr];
01846                 
01847                 /* no material create one if necessary */
01848                 if(!ma) {
01849                     /* find a new material and assign to the face */
01850                     flag = encode_tfaceflag(tf, 1);
01851 
01852                     /* create/find a new material and assign to the face */
01853                     if (check_tfaceneedmaterial(flag))
01854                         mf->mat_nr= convert_tfacenomaterial(main, me, tf, flag);
01855 
01856                     continue;
01857                 }
01858 
01859                 /* we can't read from this if it comes from a library,
01860                  * at doversion time: direct_link might not have happened on it,
01861                  * so ma->mtex is not pointing to valid memory yet.
01862                  * later we could, but it's better not */
01863                 else if(ma->id.lib)
01864                     continue;
01865                 
01866                 /* material already marked as disputed */
01867                 else if(ma->game.flag == MAT_BGE_DISPUTED)
01868                     continue;
01869 
01870                 /* found a material */
01871                 else {
01872                     flag = encode_tfaceflag(tf, ((fileload)?0:1));
01873 
01874                     /* first time changing this material */
01875                     if (ma->game.flag == 0)
01876                         ma->game.flag= -flag;
01877             
01878                     /* mark material as disputed */
01879                     else if (ma->game.flag != -flag) {
01880                         ma->game.flag = MAT_BGE_DISPUTED;
01881                         continue;
01882                     }
01883             
01884                     /* material ok so far */
01885                     else {
01886                         ma->game.flag = -flag;
01887                         
01888                         /* some people uses multitexture with TexFace by creating a texture
01889                          * channel which not neccessarly the tf->tpage image. But the game engine
01890                          * was enabling it. Now it's required to set "Face Texture [Alpha] in the
01891                          * material settings. */
01892                         if(!fileload)
01893                             set_facetexture_flags(ma, tf->tpage);
01894                     }
01895                 }
01896             }
01897             else
01898                 continue;
01899         }
01900 
01901         /* if we didn't have material slot and now we do, we need to
01902          * make sure the materials are correct */
01903         if(nomaterialslots) {
01904             if (me->totcol>0) {
01905                 for(a=0, mf=me->mface; a<me->totface; a++, mf++) {
01906                     if (mf->mat_nr == -1) {
01907                         /* texface data for this face */
01908                         tf = ((MTFace*)cdl->data) + a;
01909                         mf->mat_nr= convert_tfacenomaterial(main, me, tf, encode_tfaceflag(tf, 1));
01910                     }
01911                 }
01912             }
01913             else {
01914                 for(a=0, mf=me->mface; a<me->totface; a++, mf++) {
01915                     mf->mat_nr=0;
01916                 }
01917             }
01918         }
01919 
01920     }
01921     
01922     /* 2nd part - conversion */
01923     /* skip library files */
01924 
01925     /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */
01926     for (ma= main->mat.first, a=0; ma; ma= ma->id.next, a++) {
01927         if (ma->id.lib) continue;
01928 
01929         /* disputed material */
01930         if (ma->game.flag == MAT_BGE_DISPUTED) {
01931             ma->game.flag = 0;
01932             if (fileload) {
01933                 printf("Warning: material \"%s\" skipped - to convert old game texface to material go to the Help menu.\n", ma->id.name+2);
01934                 nowarning = 0;
01935             }
01936             else
01937                 convert_tfacematerial(main, ma);
01938             continue;   
01939         }
01940     
01941         /* no conflicts in this material - 90% of cases
01942          * convert from tface system to material */
01943         else if (ma->game.flag < 0) {
01944             decode_tfaceflag(ma, -(ma->game.flag), 1);
01945 
01946             /* material is good make sure all faces using
01947              * this material are set to converted */
01948             if (fileload) {
01949                 for(me=main->mesh.first; me; me=me->id.next){
01950                     /* check if this mesh uses this material */
01951                     for(a=0;a<me->totcol;a++)
01952                         if(me->mat[a] == ma) break;
01953                         
01954                     /* no material found */
01955                     if (a == me->totcol) continue;
01956             
01957                     /* get the active tface layer */
01958                     index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
01959                     cdl= (index == -1)? NULL: &me->fdata.layers[index];
01960                     if (!cdl) continue;
01961             
01962                     /* loop over all the faces and stop at the ones that use the material*/
01963                     for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
01964                         if (me->mat[mf->mat_nr] == ma) {
01965                             /* texface data for this face */
01966                             tf = ((MTFace*)cdl->data) + a;
01967                             tf->mode |= TF_CONVERTED;
01968                         }
01969                     }
01970                 }
01971             }
01972         }
01973         /* material is not used by faces with texface
01974          * set the default flag - do it only once */
01975         else
01976              if (fileload)
01977                     ma->game.flag = GEMAT_BACKCULL;
01978     }
01979 
01980     return nowarning;
01981 }
01982