/****************************************************************************************/
/*  FINALIZE.C                                                                          */
/*                                                                                      */
/*  Author: Timothy Roff	                                                            */
/*  Description:  Shader implementation                                                 */
/*                                                                                      */
/*  The contents of this file are subject to the Jet3D Public License                   */
/*  Version 1.02 (the "License"); you may not use this file except in                   */
/*  compliance with the License. You may obtain a copy of the License at                */
/*  http://www.jet3d.com                                                                */
/*                                                                                      */
/*  Software distributed under the License is distributed on an "AS IS"                 */
/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
/*  the License for the specific language governing rights and limitations              */
/*  under the License.                                                                  */
/*                                                                                      */
/*  This file was not part of the original Jet3D, released December 12, 1999.           */
/*                                                                                      */
/****************************************************************************************/

#include "jeShaderDefs.h"
#include "jeShader_h.h"

//=====================================================================================
//	finalize_skyparms
//=====================================================================================
void request_sky_box_maps(shader_t* shader, char* base, jeBoolean is_far_box, sh_map_t maps_out[5])
{
   int i;
   char name[JE_SHADER_NAME_LEN+1];

   char* suffixes[6] = {
      "_rt.tga",
      "_lf.tga",
      "_ft.tga",
      "_bk.tga",
      "_up.tga",
      "_dn.tga"
   };

   if (((shader->flags & SH_FAR_BOX)  &&  is_far_box) ||
       ((shader->flags & SH_NEAR_BOX) && !is_far_box)) {

      for (i = 0; i < 6; i++) {
         strncpy(name, base, JE_SHADER_NAME_LEN);
         name[JE_SHADER_NAME_LEN] = '\0';
         strncat(name, suffixes[i], JE_SHADER_NAME_LEN+8);
         name[JE_SHADER_NAME_LEN+8] = '\0';
         strcpy(maps_out[i].name, name);

         if (!is_far_box) maps_out[i].flags |= SH_MAP_ALPHA;
      }

   }
}

void finalize_skyparms(shader_t* shader)
{
   if ((shader->stage_count == 0) && (shader->flags & SH_EXPLICIT_SKYGEN))
   {
	   jeErrorLog_Add(JE_ERR_SHADER_SCRIPT, "specified skyparms <cloudheight>, but there are no cloud layers.  specify <cloudheight> as '-' to quiet this warning");
   }
    
   request_sky_box_maps(shader, shader->far_box_basename,  JE_TRUE,  shader->far_box);
   request_sky_box_maps(shader, shader->near_box_basename, JE_FALSE, shader->near_box);
}

//=====================================================================================
//	finalize_cull
//=====================================================================================
void finalize_cull( shader_info_t *info)
{
	assert(info != NULL);

   if (!(info->shader->flags & SH_EXPLICIT_CULL)) info->shader->cull_face = SH_CULL_FRONT;
}


//=====================================================================================
//	finalize_rgbgen
//=====================================================================================
void finalize_rgbgen( shader_info_t *info)
{
	assert(info != NULL);

   if (!(info->stage.flags & SH_STAGE_EXPLICIT_RGBGEN)) {
      if ((info->stage.flags & SH_STAGE_BLENDFUNC) && sh_is_blend_filter(&info->stage)) {
         info->stage.rgbgen.func = SH_RGBAGEN_IDENTITY;
      }
      else {
         info->stage.rgbgen.func = SH_RGBAGEN_IDENTITY_LIGHTING;
      }
   }
}

//=====================================================================================
//	finalize_alphagen
//=====================================================================================
void finalize_alphagen( shader_info_t *info)
{
	assert(info != NULL);

   if (!(info->stage.flags & SH_STAGE_EXPLICIT_ALPHAGEN)) {
      info->stage.alphagen.func  = SH_RGBAGEN_IDENTITY;
   }
}

//=====================================================================================
//	finalize_tcgen
//=====================================================================================
void finalize_tcgen( shader_info_t *info)
{
	assert(info != NULL);

   if (!(info->stage.flags & SH_STAGE_EXPLICIT_TCGEN)) {
      if (info->stage.anim_map_count == 1) {
         if (stricmp(info->stage.maps[0].name, "$lightmap") == 0) {
            info->stage.tcgen.func = SH_TCGEN_LIGHTMAP;
         }
         else {
            info->stage.tcgen.func = SH_TCGEN_BASE;
         }
      }
      else {
         info->stage.tcgen.func = SH_TCGEN_BASE;
      }
   }
}

//=====================================================================================
//	finalize_sort
//=====================================================================================
void finalize_sort( shader_info_t *info)
{
	assert(info != NULL);

   if (!(info->shader->flags & SH_EXPLICIT_SORT)) {
      if (info->shader->flags & (SH_SKYGEN|SH_FAR_BOX|SH_NEAR_BOX)) {
         info->shader->sort_priority = SH_SORT_SKY;
      }
      else if (info->shader->flags & SH_FOGPARMS) {
         info->shader->sort_priority = SH_SORT_FOG;
      }
      else if (info->shader->flags & SH_POLYGON_OFFSET) {
         info->shader->sort_priority = SH_SORT_DECAL;
      }
      else if (info->shader->stage_count > 0) {
         if (info->shader->stages[0].flags & SH_STAGE_BLENDFUNC) {
            info->shader->sort_priority = SH_SORT_ADDITIVE;
         }
         else if (info->shader->stages[0].flags & SH_STAGE_ALPHAFUNC) {
            info->shader->sort_priority = SH_SORT_SEE_THROUGH;
         }
         else {
            info->shader->sort_priority = SH_SORT_OPAQUE;
         }
      }/*
      else {
         info->shader remains undefined, this is for shaders with no stages
      }*/
   }
}

//=====================================================================================
//	finalize_map
//=====================================================================================
void finalize_map( shader_info_t *info)
{
	assert(info != NULL);
}




//=====================================================================================
//	finalize_stage
//=====================================================================================
void finalize_stage( shader_info_t *info)
{
	int i, j;
	assert(info != NULL);

   finalize_rgbgen(info);
   finalize_alphagen(info);
   finalize_tcgen(info);
   finalize_map(info);
   
   info->shader->stage_count++;

   if (sh_is_opaque_stage(&info->stage)) {
      if (info->shader->stage_count > 1) {
         jeShader_Error("stage %d will overwrite previous stages",
            info->shader->stage_count);
      }
      else if (info->shader->flags & SH_FAR_BOX) {
         jeShader_Error("stage 1 will overwrite the sky far box");
      }
   }

   for (i = 0; i < info->shader->stage_count; i++) {
      if (info->shader->stages[i].flags & SH_STAGE_MAP_NEEDS_ALPHA) {
         for (j = 0; j < info->shader->stages[i].anim_map_count; j++) {
            info->shader->stages[i].flags |= SH_MAP_ALPHA;
         }
      }
   }

#ifdef _DEBUG
   if (sh_is_blend_src_only(&info->stage)) {
      jeShader_Error("blendFunc GL_ONE GL_ZERO will look equivalent to no blendfunc, but the Z buffer will not be written");
   }
   else if (sh_is_blend_dst_only(&info->stage)) {
      jeShader_Error("blendFunc GL_ZERO GL_ONE means that no color will be written for this stage, only the Z buffer");
   }
#endif

   //info->stage = NULL;
   //TODO write info->stage destroy() func
}

//=====================================================================================
//	finalize_shader
//=====================================================================================
void finalize_shader( shader_info_t *info)
{
	assert(info != NULL);

   finalize_skyparms(info->shader);
   finalize_sort(info);
   finalize_cull(info);
}

//EOF