//-----------------------------------------------------------------------------
//
//  $Logfile:: /Source/gl_sprite.c                                             $
// $Revision:: 3                                                               $
//   $Author:: Burgermac                                                       $
//     $Date:: 8/8/01 4:46 PM                                                  $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
// 
// DESCRIPTION:
// Sin sprite model loading and drawing
//

#include "gl_local.h"


/*
==============================================================================

SIN SPRITE FILES

==============================================================================
*/
#define MAX_ARGS 16
#define MAX_ARG_LENGTH 64
#define MAX_LOAD_FRAMES 64
#define MAX_LOAD_FRAMENAME_LENGTH 64

typedef struct
   {
   char           args[MAX_ARGS][MAX_ARG_LENGTH];
   char           frames[MAX_LOAD_FRAMES][MAX_LOAD_FRAMENAME_LENGTH];
   float          framealpha[MAX_LOAD_FRAMES];
   char           baseframe[MAX_LOAD_FRAMENAME_LENGTH];
   float          basealpha;
   int            numframes;
   int            numargs;
   int            argnum;
   int            type;
   int            flags;
	qboolean			twosided;
   qboolean       hasbase;
   float          origin_x, origin_y;
   float          scale;
   char				com_token[MAX_STRING_CHARS];
   } dloadsprite_t;

/*
============
SPR_ExtractPath
============
*/
static void SPR_ExtractPath (char *in, char *out)
   {
	char *s;
   int len;
	
	s = in + strlen(in) - 1;
	
	while (s != in && *s != '/' && *s != '\\')
		s--;

   len = s-in+1;
   if (len<2)
      {
      strcpy(out,"?model?");
      }
   else
      {
      memcpy(out,in,len);
      out[len] = 0;
      }
   }

/*
=================
SPR_LoadSpriteFile
=================
*/
qboolean SPR_LoadSpriteFile ( model_t * mod, void * load_buffer )
{
   dloadsprite_t  *ld;
   dsprite_t      *psprite;

   char           file[ 128 ];
   char           load_path[ 128 ];
   char           *path;
   char           *buffer;
   
   int            size;
   int            i;
   imagetype_t    type = it_sprite;

   // create our temp space for loading stuff
   ld = ( dloadsprite_t * )malloc( sizeof( *ld ) );
   if (!ld )
      {
      ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: could not create temp space for loading files\n" );
      return false;
      }

   // clear the buffer
   memset( ld, 0, sizeof( *ld ) );
   // set the buffer
   buffer = (char *)load_buffer;
   // skip over the header
   buffer += sizeof( unsigned );

   // initialize some variables
   ld->numframes = 0;
   path = mod->name;
   ld->origin_x = 0.5;
   ld->origin_y = 0.5;
   ld->scale = 1.0f;
   ld->twosided = true;

   // get the original path
   SPR_ExtractPath ( path, load_path );

   // read in all the commands
   while (1)
      {
      ld->numargs = 0;
      // see if we reached the end of the file
      strcpy( ld->com_token, COM_GetToken((const char **) &buffer, true ) );
      if (!ld->com_token[0])
         break;

      if (strlen(ld->com_token) >= MAX_ARG_LENGTH)
         {
         ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: argument too long, truncating in %s\n", path);
         ld->com_token[ MAX_ARG_LENGTH - 1 ] = 0;
         }
      strcpy(ld->args[ld->numargs++], ld->com_token);
      // get the rest of the line
      while( 1 )
         {
         strcpy( ld->com_token, COM_GetToken( (const char **)&buffer, false ) );
         if (!ld->com_token[0])
            break;
         if (strlen(ld->com_token) >= MAX_ARG_LENGTH)
            {
            ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: argument too long, truncating in %s\n", path);
            ld->com_token[ MAX_ARG_LENGTH - 1 ] = 0;
            }
         strcpy(ld->args[ld->numargs++], ld->com_token);
         }

      // now that we have the whole line, process it
      ld->argnum = 0;
      // see if it is a special command
      if (!Q_stricmp (ld->args[ld->argnum], "path"))
         {
         strcpy( load_path, ld->args[ld->argnum+1] );
         size = (int) strlen(load_path);
         if (size > 0 && (load_path[size-1] != '/' || load_path[size-1] != '\\'))
            strcat( load_path, "/");
         continue;
         }
      else if (!Q_stricmp (ld->args[ld->argnum], "type"))
         {
         if (!Q_stricmp (ld->args[ld->argnum+1], "parallel_upright"))
            ld->type = SPR_VP_PARALLEL_UPRIGHT;
         else if (!Q_stricmp (ld->args[ld->argnum+1], "facing_upright"))
            ld->type = SPR_FACING_UPRIGHT;
         else if (!Q_stricmp (ld->args[ld->argnum+1], "parallel_oriented"))
            ld->type = SPR_VP_PARALLEL_ORIENTED;
         else if (!Q_stricmp (ld->args[ld->argnum+1], "parallel"))
            ld->type = SPR_VP_PARALLEL;
         else if (!Q_stricmp (ld->args[ld->argnum+1], "oriented"))
            ld->type = SPR_ORIENTED;
         else if (!Q_stricmp (ld->args[ld->argnum+1], "oriented_cross"))
            ld->type = SPR_ORIENTED_CROSS;
         else if (!Q_stricmp (ld->args[ld->argnum+1], "oriented_star"))
            ld->type = SPR_ORIENTED_STAR;
         else
            {
            ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: illegal sprite type setting to parallel_oriented in %s\n", path);
            ld->type = SPR_VP_PARALLEL_ORIENTED;
            }
         continue;
         }
      else if (!Q_stricmp (ld->args[ld->argnum], "singlesided"))
         {
			ld->twosided = false;
			}
      else if (!Q_stricmp (ld->args[ld->argnum], "luminance"))
         {
			type = it_lum;
			}
      else if (!Q_stricmp (ld->args[ld->argnum], "origin"))
         {
         ld->origin_x = Sinatof( ld->args[ld->argnum+1] );
         ld->origin_y = Sinatof( ld->args[ld->argnum+2] );
         if (ld->origin_x<0 || ld->origin_x>1.0f)
            {
            ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: Bad origin x %f, setting to 0.5 in %s\n", ld->origin_x, path);
            ld->origin_x = 0.5f;
            }
         if (ld->origin_y<0 || ld->origin_y>1.0f)
            {
            ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: Bad origin y %f, setting to 0.5 in %s\n", ld->origin_y, path);
            ld->origin_y = 0.5f;
            }
         continue;
         }
      else if (!Q_stricmp (ld->args[ld->argnum], "worldlit"))
         {
			ld->flags |= SPRITE_WORLDLIT;
			}
      else if (!Q_stricmp (ld->args[ld->argnum], "modulate"))
         {
			ld->flags |= SPRITE_MODULATE;
			}
      else if (!Q_stricmp (ld->args[ld->argnum], "overbright"))
         {
			ld->flags |= SPRITE_OVERBRIGHT;
			}
      else if (!Q_stricmp (ld->args[ld->argnum], "scale"))
         {
			ld->scale = Sinatof( ld->args[ld->argnum+1] );
			}
      else if (!Q_stricmp (ld->args[ld->argnum], "base"))
         {
         ld->hasbase = true;
         strcpy( ld->baseframe, ld->args[ld->argnum+1] );
         ld->basealpha = 1;
         if (ld->argnum+2 < ld->numargs)
            ld->basealpha = 1.0f - Sinatof( ld->args[ld->argnum+2] );
			}
      else
         {
         // it must be a sprite frame, grab and store them
         strcpy( ld->frames[ ld->numframes ], ld->args[ld->argnum] );
         ld->framealpha[ ld->numframes ] = 1.0f;
         if (ld->argnum+1 < ld->numargs)
            ld->framealpha[ ld->numframes ] = 1.0f - Sinatof( ld->args[ld->argnum+1] );
         ld->numframes++;
         }
      }

   if ( (!ld->numframes) )
      {
      // these are too serious to continue loading the rest of the sprite file
      ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: could not load %s, no frames defined.\n", path);
      // free up the temp space
      free(ld);
      return false;
      }
	if ( ld->numframes > MAX_MD2SKINS)
      {
      ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: too many frames %d, setting to MAX_MD2SKINS in %s.\n", ld->numframes, path);
      ld->numframes = MAX_MD2SKINS;
      }
   // allocate the sprite and store the info
   size = sizeof( dsprite_t ) + ( (ld->numframes-1)*sizeof(dsprframe_t) );

	psprite = (dsprite_t*)Hunk_Alloc( size );

   psprite->numframes = ld->numframes;
   psprite->type = ld->type;
	psprite->twosided = ld->twosided;
   psprite->flags    = ld->flags;
   psprite->scale    = ld->scale;
	mod->type = mod_sprite;

   for( i=0; i < psprite->numframes; i++ )
      {
      strcpy( file, load_path );
      strcat( file, ld->frames[i] );
      size = (int) strlen(file);
      if (size > MAX_SKINNAME)
         {
         ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: %s too long, truncating.\n", file);
         file[size - 1] = 0;
         }
      strcpy( psprite->frames[i].name, file );
		mod->skins[i] = GL_FindImage (psprite->frames[i].name,type);
      if (mod->skins[i])
         {
		   psprite->frames[i].width = mod->skins[i]->width;
		   psprite->frames[i].height = mod->skins[i]->height;
         psprite->frames[i].alpha = ld->framealpha[i];
         }
      else
         {
         ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: Failed to load %s.\n", file);
         free(ld);
         return false;
         }
		psprite->frames[i].origin_x = ld->origin_x * (float)mod->skins[i]->width;
		psprite->frames[i].origin_y = ld->origin_y * (float)mod->skins[i]->height;
      }
   if ( ld->hasbase )
      {
      psprite->flags |= SPRITE_HASBASE;
      strcpy( file, load_path );
      strcat( file, ld->baseframe );
      size = (int) strlen(file);
      if (size > MAX_SKINNAME)
         {
         ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: %s too long, truncating.\n", file);
         file[size - 1] = 0;
         }
      strcpy( psprite->base.name, file );
		mod->skins[psprite->numframes] = GL_FindImage (psprite->base.name,it_sprite);
      if (mod->skins[psprite->numframes])
         {
		   psprite->base.width = mod->skins[psprite->numframes]->width;
		   psprite->base.height = mod->skins[psprite->numframes]->height;
         psprite->base.origin_x = ld->origin_x * (float)mod->skins[psprite->numframes]->width;
		   psprite->base.origin_y = ld->origin_x * (float)mod->skins[psprite->numframes]->height;
         psprite->base.alpha = ld->basealpha;
         }
      else
         {
         ri.Con_Printf (PRINT_ALL,  "SPR_LoadSpriteFile: Failed to load %s.\n", file);
         }
      }
   // free up the temp space
   free(ld);

   return true;
}

/*
=================
SPR_RegisterSpriteFile
=================
*/
void SPR_RegisterSprite ( model_t * mod )
   {
   dsprite_t *sprout;
   int i;

	sprout = (dsprite_t *)mod->extradata;
	for (i=0 ; i<sprout->numframes ; i++)
		mod->skins[i] = GL_FindImage (sprout->frames[i].name, it_sprite);
   if ( sprout->flags & SPRITE_HASBASE )
		mod->skins[sprout->numframes] = GL_FindImage( sprout->base.name, it_sprite );
   }
