Beispiel #1
0
void list_pak(struct paki_args* args)
{
    result_t r;
    struct pak_file pak;
    r = pak_open(&pak, mem_heap(), args->pakfile, 0);
    if (IS_FAIL(r))     {
        err_sendtolog(FALSE);
        return;
    }

    uint cnt = INVALID_INDEX;
    char* filelist = pak_createfilelist(&pak, mem_heap(), &cnt);
    pak_close(&pak);
    if (cnt == 0)	{
        printf(TERM_BOLDWHITE "There are no files in the pak '%s'.\n" TERM_RESET, args->pakfile);
        return;
    }

    if (filelist == NULL)	{
        printf(TERM_BOLDRED "Not enough memory.\n" TERM_RESET);
        return;
    }

    for (uint i = 0; i < cnt; i++)	{
        printf(TERM_WHITE "%s\n" TERM_RESET, filelist + i*DH_PATH_MAX);
    }
    printf(TERM_BOLDWHITE "Total %d files in '%s'.\n" TERM_RESET, cnt, args->pakfile);
    FREE(filelist);
}
Beispiel #2
0
void GLSL_LoadShader(GLuint *shader_id,char *filename, int type)
{
    PFILE *f;
    int filesize;
    int bytes;
    char * buffer;
    int wasok;

    if(!EXTGL_shading_language)
    {
     *shader_id=0;
     sprintf (FANTASY_DEBUG_STRING, "Sorry, this card does not support GLSL\n");
     Debug(DEBUG_LEVEL_WARNING);
     return;
    } 

    f = pak_open(filename, "rb");
    if (f == NULL)
    {
     sprintf (FANTASY_DEBUG_STRING, "Shader file %s not found\n",filename);
     Debug(DEBUG_LEVEL_ERROR);
     *shader_id=0;     
     return;
    }

    // Find file size.
    pak_fseek(f, 0, SEEK_END);
    filesize = pak_ftell(f);
    pak_fseek(f, 0, SEEK_SET);

    buffer = (char *)malloc(filesize*sizeof(char)+1);
    if(!buffer) return;
    // Leemos el shader en memoria y lo almacenamos
    bytes = pak_read(buffer,1,filesize,f);
    pak_close(f);
    buffer[filesize*sizeof(char)] = '\0';

    // Create shader
    if(type == GLSL_VERTEX_SHADER)
       *shader_id = f_glCreateShaderObjectARB( GL_VERTEX_SHADER_ARB );
    else if (type == GLSL_FRAGMENT_SHADER)
       *shader_id = f_glCreateShaderObjectARB( GL_FRAGMENT_SHADER_ARB );
    
    // Compile shader
    f_glShaderSourceARB( *shader_id, 1, (const char **)&buffer, NULL );
    f_glCompileShaderARB( *shader_id);
    // Check for errors
    f_glGetObjectParameterivARB( *shader_id, GL_OBJECT_COMPILE_STATUS_ARB,&wasok);
    if( !wasok )
    {
	f_glGetInfoLogARB(*shader_id, sizeof(errorString), NULL, errorString);
        sprintf (FANTASY_DEBUG_STRING, "Error compiling shader %s\n",filename);
        Debug(DEBUG_LEVEL_ERROR);	
        sprintf (FANTASY_DEBUG_STRING, "%s\n",errorString);
        Debug(DEBUG_LEVEL_ERROR);	
	*shader_id=0;
	return;
    }
    free(buffer);
}
Beispiel #3
0
void load_pak(struct paki_args* args)
{
    result_t r;
    struct pak_file pak;
    char filename[DH_PATH_MAX];

    path_norm(args->pakfile, args->pakfile);
    path_tounix(args->path, args->path);

    r = pak_open(&pak, mem_heap(), args->pakfile, 0);
    if (IS_FAIL(r))     {
        err_sendtolog(FALSE);
        return;
    }

    uint file_id = pak_findfile(&pak, args->path);
    if (file_id == INVALID_INDEX)   {
        printf(TERM_BOLDRED "Extract failed: file '%s' not found in pak.\n" TERM_RESET, args->path);
        pak_close(&pak);
        return;
    }

    path_getfullfilename(filename, args->path);
    file_t f = fio_createdisk(filename);
    if (f == NULL)     {
        printf(TERM_BOLDRED "Extract failed: could not create '%s' for writing.\n" TERM_RESET,
               filename);
        pak_close(&pak);
        err_sendtolog(FALSE);
        return;
    }

    file_t src_file = pak_getfile(&pak, mem_heap(), mem_heap(), file_id, 0);
    if (src_file == NULL)   {
        pak_close(&pak);
        fio_close(f);
        err_sendtolog(FALSE);
        return;
    }

    size_t size;
    struct allocator* alloc;
    void* buffer = fio_detachmem(src_file, &size, &alloc);
    fio_write(f, buffer, size, 1);
    A_FREE(alloc, buffer);
    fio_close(f);

    pak_close(&pak);

    if (BIT_CHECK(args->usage, PAKI_USAGE_VERBOSE)) {
        printf(TERM_WHITE "%s -> %s\n" TERM_RESET, args->path, filename);
    }
    args->file_cnt ++;

    // report
    printf(TERM_BOLDWHITE "Finished: total %d file(s) - %d error(s), %d warning(s)\n" TERM_RESET,
           args->file_cnt, args->err_cnt, args->warn_cnt);
}
Beispiel #4
0
TSpline *SPLINE_New (char *filename)
{
    int      i;
    PFILE   *fp;
    TSpline *spl;
    char     magic[5];

    fp = pak_open (filename, "rb");
    assert (fp != NULL);

    // Check magic
    pak_read (magic, 1, 4, fp);
    magic[4] = '\0';
    assert (!strcmp (magic, magic_binpoly));

    spl = (TSpline *) malloc (sizeof (TSpline));
    assert (spl != NULL);
    spl->tfactor = 1.0f;

    // Number of nodes => number of polynomials = nodes + 1
    pak_read (&spl->nkeys, 4, 1, fp);
    assert (spl->nkeys != 0);

    spl->p = (TKey *) malloc ((spl->nkeys + 1) * sizeof (TKey));
    assert (spl->p != NULL);

    for (i=0; i<spl->nkeys; i++)
    {
        // Read time
        pak_read (&spl->p[i].t, 4, 1, fp);

        // Read polynomial coefficients
        pak_read (spl->p[i].c, 4, 4, fp);
    }

    // Last polynomial
    spl->p[i].c[0] = 0.0f;
    spl->p[i].c[1] = 0.0f;
    spl->p[i].c[2] = 0.0f;
    pak_read (&spl->p[i].t, 4, 1, fp);
    pak_read (&spl->p[i].c[3], 4, 1, fp);

    spl->nkeys ++;

    pak_close (fp);

    spl->t0 = spl->p[0].t;
    spl->t1 = spl->p[i].t;

    //spl->loop_mode = SPLINE_LOOP_CONSTANT;
    //spl->loop_mode = SPLINE_LOOP_CONTINUITY;
    spl->loop_mode = SPLINE_LOOP_MOD;

    return spl;
}
Beispiel #5
0
static vfs_archive pak_plugin_archive_open(const VFS_CHAR* archive,const VFS_CHAR* prefix,const VFS_CHAR* passwd)
{
    return (vfs_archive)pak_open(archive,prefix);
}
Beispiel #6
0
int main(int argc, char **argv) {
    bool          extract   = true;
    char         *redirout  = (char*)stdout;
    char         *redirerr  = (char*)stderr;
    char         *file      = NULL;
    char        **files     = NULL;
    pak_file_t   *pak       = NULL;
    size_t        iter      = 0;

    con_init();

    /*
     * Command line option parsing commences now We only need to support
     * a few things in the test suite.
     */
    while (argc > 1) {
        ++argv;
        --argc;

        if (argv[0][0] == '-') {
            if (parsecmd("redirout",  &argc, &argv, &redirout,  1, false))
                continue;
            if (parsecmd("redirerr",  &argc, &argv, &redirerr,  1, false))
                continue;
            if (parsecmd("file",      &argc, &argv, &file,      1, false))
                continue;

            con_change(redirout, redirerr);

            switch (argv[0][1]) {
                case 'e': extract = true;  continue;
                case 'c': extract = false; continue;
            }

            if (!strcmp(argv[0]+1, "debug")) {
                OPTS_OPTION_BOOL(OPTION_DEBUG) = true;
                continue;
            }
            if (!strcmp(argv[0]+1, "memchk")) {
                OPTS_OPTION_BOOL(OPTION_MEMCHK) = true;
                continue;
            }
            if (!strcmp(argv[0]+1, "nocolor")) {
                con_color(0);
                continue;
            }
        }

        vec_push(files, argv[0]);
    }
    con_change(redirout, redirerr);


    if (!file) {
        con_err("-file must be specified for output/input PAK file\n");
        vec_free(files);
        return EXIT_FAILURE;
    }

    if (extract) {
        if (!(pak = pak_open(file, "r"))) {
            con_err("failed to open PAK file %s\n", file);
            vec_free(files);
            return EXIT_FAILURE;
        }

        if (!pak_extract_all(pak, "./")) {
            con_err("failed to extract PAK %s (files may be missing)\n", file);
            pak_close(pak);
            vec_free(files);
            return EXIT_FAILURE;
        }

        /* not possible */
        pak_close(pak);
        vec_free(files);
        stat_info();

        return EXIT_SUCCESS;
    }

    if (!(pak = pak_open(file, "w"))) {
        con_err("failed to open PAK %s for writing\n", file);
        vec_free(files);
        return EXIT_FAILURE;
    }

    for (iter = 0; iter < vec_size(files); iter++) {
        if (!(pak_insert_one(pak, files[iter]))) {
            con_err("failed inserting %s for PAK %s\n", files[iter], file);
            pak_close(pak);
            vec_free(files);
            return EXIT_FAILURE;
        }
    }

    /* not possible */
    pak_close(pak);
    vec_free(files);

    stat_info();
    return EXIT_SUCCESS;
}
Beispiel #7
0
result_t eng_init(const struct init_params* params)
{
    result_t r = RET_OK;

    ASSERT(g_eng == NULL);
    g_eng = (struct engine*)ALLOC(sizeof(struct engine), 0);
    if (g_eng == 0)
        return err_printn(__FILE__, __LINE__, RET_OUTOFMEMORY);
    memset(g_eng, 0x00, sizeof(struct engine));

    eng_zero();

    memcpy(&g_eng->params, params, sizeof(struct init_params));

    hw_getinfo(&g_eng->hwinfo, HWINFO_ALL);

    /* console (before anything else) */
    if (BIT_CHECK(params->flags, ENG_FLAG_CONSOLE))	{
		r |= con_init(params->console_lines_max);
		if (IS_FAIL(r))
			return RET_FAIL;
		log_outputfunc(TRUE, con_log, NULL);
    }

    /* show build options */
#if !defined(FULL_VERSION)
#error "must define FULL_VERSION macro"
#endif

    time_t raw_tm;
    time(&raw_tm);

    log_printf(LOG_TEXT, "init darkhammer engine v%s build[%s, %s, %s, %s], time: %s", 
        FULL_VERSION,
#if defined(_DEBUG_)
    		"debug"
#else
    		"release"
#endif
    		,
#if defined(_PROFILE_)
    		"profile"
#else
    		"no-profile"
#endif
    		,
#if defined(_X86_)
    		"x86"
#elif defined(_X64_)
    		"x64"
#endif
    		,
#if defined(_ENABLEASSERT_)
    		"assert"
#else
    		"no-assert"
#endif
            , asctime(localtime(&raw_tm)));

    /* hardware info */
    hw_printinfo(&g_eng->hwinfo, HWINFO_ALL);

    size_t tmp_sz = params->dev.buffsize_tmp;
    size_t data_sz = data_sz = params->dev.buffsize_data;
    tmp_sz = tmp_sz != 0 ? ((size_t)tmp_sz*1024) : FRAME_STACK_SIZE;
    data_sz = data_sz != 0 ? ((size_t)data_sz*1024) : DATA_SIZE;

    /* allocators */
    /* dynamic allocator for data in dev (editor) mode, stack allocator in game (normal) mode */
    if (BIT_CHECK(params->flags, ENG_FLAG_OPTIMIZEMEMORY))   {
        /* lsr (load-stay-resident) allocator for essential engine data */
        r |= mem_stack_create(mem_heap(), &g_eng->lsr_stack, LSR_SIZE, MID_DATA);
        mem_stack_bindalloc(&g_eng->lsr_stack, &g_eng->lsr_alloc);

        r |= mem_freelist_create(mem_heap(), &g_eng->data_freelist, data_sz, MID_DATA);
        mem_freelist_bindalloc(&g_eng->data_freelist, &g_eng->data_alloc);
    }   else    {
        mem_heap_bindalloc(&g_eng->data_alloc);
        mem_heap_bindalloc(&g_eng->lsr_alloc);

        g_eng->data_alloc.alloc_fn = eng_allocfn_data;
        g_eng->data_alloc.alignedalloc_fn = eng_alignedallocfn_data;
        g_eng->lsr_alloc.alloc_fn = eng_allocfn_lsr;
        g_eng->lsr_alloc.alignedalloc_fn = eng_alignedallocfn_lsr;

        r = RET_OK;
    }

    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: out of memory for allocators");
        return RET_FAIL;
    }

    /* timer manager and frame timer */
    g_eng->timer = timer_createinstance(TRUE);

    /* add engine's own data path to file-mgr */
    if (params->data_path != NULL)   {
        char data_path_ext[DH_PATH_MAX];
        path_getfileext(data_path_ext, params->data_path);
        if (str_isequal_nocase(data_path_ext, "pak"))    {
            if (IS_FAIL(pak_open(&g_eng->data_pak, mem_heap(), params->data_path, 0)))    {
                err_print(__FILE__, __LINE__, "engine init: could not open data pak");
                return RET_FAIL;
            }
        }   else   {
            if (!util_pathisdir(params->data_path)) {
                err_print(__FILE__, __LINE__, "engine init: data path is not valid");
                return RET_FAIL;
            }
            fio_addvdir(params->data_path, FALSE);
        }
        /* assume that share directory is same as data dir */
        path_getdir(g_eng->share_dir, params->data_path);
    }   else    {
        char data_path[DH_PATH_MAX];
        char share_dir[DH_PATH_MAX];
#ifndef SHARE_DIR
        char exe_dir[DH_PATH_MAX];
        path_join(share_dir, util_getexedir(exe_dir), "..", NULL);
        path_norm(share_dir, share_dir);
#else
        path_norm(share_dir, SHARE_DIR);
#endif
        path_join(data_path, share_dir, "data", NULL);
        if (!util_pathisdir(data_path)) {
            err_print(__FILE__, __LINE__, "engine init: data path is not valid");
            return RET_FAIL;
        }

        fio_addvdir(data_path, FALSE);  /* set default (config.h configured on build) data dir */
        strcpy(g_eng->share_dir, share_dir);
    }

    uint rs_flags = 0;
    /* activate hot loading in DEV mode */
    rs_flags |= BIT_CHECK(params->flags, ENG_FLAG_DEV) ? RS_FLAG_HOTLOADING : 0;
    if (!BIT_CHECK(params->flags, ENG_FLAG_DISABLEBGLOAD))  {
        rs_flags |= RS_FLAG_PREPARE_BGLOAD;
    }

    /* task manager */
    uint thread_cnt = maxui(g_eng->hwinfo.cpu_core_cnt - 1, 1);
    r = tsk_initmgr(thread_cnt, 0, tmp_sz, 0);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init task-mgr");
        return RET_FAIL;
    }
    struct allocator* tmp_alloc = tsk_get_tmpalloc(0);
    A_SAVE(tmp_alloc);

    /* resource manager (with only 1 thread for multi-thread loading) */
    r = rs_initmgr(rs_flags, 1);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init res-mgr");
        return RET_FAIL;
    }
    rs_set_dataalloc(&g_eng->lsr_alloc);

    /* graphics renderer */
    r = gfx_init(&params->gfx);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init gfx");
        return RET_FAIL;
    }

    /* debug HUD */
    r = hud_init(BIT_CHECK(params->flags, ENG_FLAG_CONSOLE));
    if (IS_FAIL(r))	{
        err_print(__FILE__, __LINE__, "engine init failed: could not init debug-hud");
        return RET_FAIL;
    }

    /* Physics */
    if (!BIT_CHECK(params->flags, ENG_FLAG_DISABLEPHX)) {
        r = phx_init(params);
        if (IS_FAIL(r)) {
            err_print(__FILE__, __LINE__, "engine init failed: could not init physics");
            return RET_FAIL;
        }
    }

    /* component manager */
    r = cmp_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init cmp-mgr");
        return RET_FAIL;
    }
    cmp_set_globalalloc(&g_eng->data_alloc, tsk_get_tmpalloc(0));

    /* world manager */
    r = wld_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init world-mgr");
        return RET_FAIL;
    }

    /* scene manager */
    r = scn_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init scene-mgr");
        return RET_FAIL;
    }

    /* init lua */
    r = sct_init(&params->sct, BIT_CHECK(params->flags, ENG_FLAG_DEV) ? TRUE : FALSE);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init script engine");
        return RET_FAIL;
    }

    /* web-server */
#if defined(_PROFILE_)
    r = prf_initmgr();
    if (IS_FAIL(r))	{
    	log_print(LOG_WARNING, "profiler manager init failed: service will not be available");
    	prf_releasemgr();
    }
#endif

    /* lod-scheme */
    r = lod_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init lod-scheme");
        return RET_FAIL;
    }

    /* init basic resources */
    r = rs_init_resources();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: coult not init res-mgr resources");
        return RET_FAIL;
    }

    /* switch back to normal data allocator */
    rs_set_dataalloc(&g_eng->data_alloc);

    /* enable background-loading if res-mgr is prepared for (see above rs_initmgr) */
    if (gfx_check_feature(GFX_FEATURE_THREADED_CREATES))
        rs_add_flags(RS_FLAG_BGLOADING);
    log_print(LOG_TEXT, "init ok: ready.");

    /* init world vars */
    eng_world_regvars();

    /* engine specific console commnads */
    con_register_cmd("showfps", eng_console_showfps, NULL, "showfps [1*/0]");
    con_register_cmd("showft", eng_console_showft, NULL, "showft [1*/0]");
    con_register_cmd("showgraph", eng_console_showgraph, NULL, "showgraph [ft][fps][drawcalls]");
    con_register_cmd("lockfps", eng_console_lockfps, NULL, "lockfps [fps]");

    /* execute console commands - should be the final stage if initialization */
    if (BIT_CHECK(params->flags, ENG_FLAG_CONSOLE))	{
		for (uint i = 0; i < params->console_cmds_cnt; i++)	{
			con_exec(params->console_cmds + i*128);
		}
    }

    A_LOAD(tmp_alloc);
    return RET_OK;
}
Beispiel #8
0
int Material::MatReader(char *filename)
{
 material *matpointer=NULL;
 PFILE *p;
 char cadena[256];
 char cadena2[256];
 char texname[256];
 char *token;
 char separadores [] = " \t";
 int i,j;
 int nmats=0; 			// Number of materials
 int curmat=0;			// Material currently being loaded
 int ntextures;


 p = pak_open(filename,"r");
 if(!p) return -1;


 while(pak_fgets(cadena,256,p))
 {

  if((cadena[0] == '\n') || (cadena[0] == '#')) continue; // Saltamos comentarios y líneas en blanco
  token = strtok(cadena,separadores);
  token2string(token,cadena2);

   if(!strcmp(cadena2,"nmaterials"))  // Leemos el número de materiales y seguimos
   {
    token = strtok(NULL,separadores);
    token2string(token,cadena2);
    nmats = atoi(cadena2);
    matpointer = (material *) malloc(nmats * sizeof(material));    
    if(!matpointer) return -1;
    
    continue;
   }
   else	  // En este caso hemos cogido el nombre de un material
   {
    if(!nmats)
    {
     sprintf (FANTASY_DEBUG_STRING, "Fallo al leer el fichero %s\n",filename);
     Debug(DEBUG_LEVEL_ERROR);
     return -1;
    }

    if(curmat >= nmats)
    {     
       sprintf (FANTASY_DEBUG_STRING, "Error en el archivo %s. Tenemos más materiales de los definidos en nmats\n",filename);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
    }
    // Inicializamos algunos valores por defecto
    matpointer[curmat].specular[0] = matpointer[curmat].specular[1] = matpointer[curmat].specular[2] = 0.0f;
    matpointer[curmat].emission[0] = matpointer[curmat].emission[1] = matpointer[curmat].emission[2] = 0.0f;
    matpointer[curmat].specular[3] = 1.0f;
    matpointer[curmat].emission[3] = 1.0f;
    matpointer[curmat].shininess = 0.0f;
    // Empezamos con la juerga!     
    
    strcpy(matpointer[curmat].matname,cadena2);
    token = strtok(NULL,separadores);	 // Ahora leemos si es estático o dinámico
    token2string(token,cadena2);

    if(!strcmp(cadena2,"static")) 	// Material estático
    {
     matpointer[curmat].shader_based = 0;
    }
    else if(!strcmp(cadena2,"shader")) // Shader based material 
    {
        matpointer[curmat].shader_based = 1;
    }
    else
    {     
       sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. No es static ni shader\n",matpointer[curmat].matname);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
    }

    // En caso de ser un shader, lo siguiente son los ficheros de los shader
    if(matpointer[curmat].shader_based == 1 )
    {
      token = strtok(NULL,separadores);
      token2string(token,cadena2);
      
      if(strcmp(cadena2,"standard")) // If shader_name == "standard", we are using the opengl pipeline
      	GLSL_LoadShader(&(matpointer[curmat].shader.vertexShader),cadena2, GLSL_VERTEX_SHADER);
      else
        matpointer[curmat].shader.vertexShader = 0;
       
      token = strtok(NULL,separadores);
      token2string(token,cadena2);
      
      // There must always be a fragment shader      
      GLSL_LoadShader(&(matpointer[curmat].shader.fragmentShader),cadena2, GLSL_FRAGMENT_SHADER);
      
      // CompileandLinkShader...	      
      GLSL_CompileAndLinkShader(&(matpointer[curmat].shader.programObj),
      				matpointer[curmat].shader.vertexShader,
      				matpointer[curmat].shader.fragmentShader);      
      // GetBasicUniforms
      GLSL_GetUniforms(&(matpointer[curmat]));
      
      matpointer[curmat].shader.params.used=0; // no custom parameters to the shader

    } 
    else // No shader, so let's fill the variables...
    {
    	matpointer[curmat].shader.vertexShader = 0;
    	matpointer[curmat].shader.fragmentShader = 0;
    	matpointer[curmat].shader.programObj = 0;
    }
     token = strtok(NULL,separadores);	 // Ahora leemos si es opaco o transparente
     token2string(token,cadena2);
     if(!strcmp(cadena2,"opaque"))	// Material opaco
     {
      matpointer[curmat].opaque = 1;
      matpointer[curmat].blend_type=-1;

      token = strtok(NULL,separadores);	 // Ahora leemos si es opaco o transparente
      token2string(token,cadena2);
      if(!strcmp(cadena2,"2sided"))	// Material con 2 caras
      {
       matpointer[curmat].twosided = 1;
      }
      else if(!strcmp(cadena2,"1sided"))	// Material con 2 caras
      {
       matpointer[curmat].twosided = 0;
      }
      else 
      {     
       sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. No tiene 1 ni 2 caras\n",matpointer[curmat].matname);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
      }
     }
     else if(!strcmp(cadena2,"transp")) // Material traslúcido
     {
      matpointer[curmat].opaque=0;

      token = strtok(NULL,separadores);	 // Ahora leemos si es opaco o transparente
      token2string(token,cadena2);
      if(!strcmp(cadena2,"2sided"))	// Material con 2 caras
      {
       matpointer[curmat].twosided = 1;
      }
      else if(!strcmp(cadena2,"1sided"))	// Material con 2 caras
      {
       matpointer[curmat].twosided = 0;
      }
      else
      {     
       sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. No tiene 1 ni 2 caras\n",matpointer[curmat].matname);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
      }

      token = strtok(NULL,separadores);	 // Ahora leemos el tipo de blend
      token2string(token,cadena2);
      if(!strcmp(cadena2,"add"))  	// Blend aditivo
      {
       matpointer[curmat].blend_type=BLEND_ADD;
      }
      else if(!strcmp(cadena2,"blend"))  // Blend normal
      {
       matpointer[curmat].blend_type=BLEND_BLEND;
      }
      else if(!strcmp(cadena2,"multiply"))  // Blend multiplicativo
      {
       matpointer[curmat].blend_type=BLEND_MULTIPLY;
      }
      else if(!strcmp(cadena2,"sub"))  	// Blend sustractivo
      {
       matpointer[curmat].blend_type=BLEND_SUB;      	
      }
      else 
      {     
       sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. El blend no es valido\n",matpointer[curmat].matname);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
      }
     }
     else
     {     
       sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. No es opaque ni transp\n",matpointer[curmat].matname);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
     }       
     // Hasta aquí tenemos el nombre del material, que es estático, su opacidad y el tipo de blend si aplica.
     // Nos falta leer el número de texturas y las texturas

     token = strtok(NULL,separadores);
     token2string(token,cadena2);
     ntextures= atoi(cadena2);

     if(ntextures < 0)
     {     
       sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. No puede tener menos de 0 texturas\n",matpointer[curmat].matname);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
     }
     else if(ntextures == 0)
     {
         matpointer[curmat].textures=NULL;
         matpointer[curmat].multitexblend=NULL;
         matpointer[curmat].texcoordgen=NULL;
     }
     else if(ntextures == 1)
     {
         matpointer[curmat].textures = (int *) malloc (ntextures * sizeof(int));
         matpointer[curmat].multitexblend = (int *) malloc ((ntextures) * sizeof(int));
         matpointer[curmat].texcoordgen = (int *) malloc ((ntextures) * sizeof(int));;
         matpointer[curmat].linearmultiplier = (float *)malloc((ntextures) * sizeof(float));
     }
     else
     {
         matpointer[curmat].textures = (int *) malloc (ntextures * sizeof(int));
         matpointer[curmat].multitexblend = (int *) malloc ((ntextures) * sizeof(int));
         matpointer[curmat].texcoordgen = (int *) malloc ((ntextures) * sizeof(int));
         matpointer[curmat].linearmultiplier = (float *)malloc((ntextures) * sizeof(float));
     }
  
     matpointer[curmat].ntextures = ntextures;

     // Cargamos las texturas
     for(i=0;i<ntextures;i++)
     {
      token = strtok(NULL,separadores);
      token2string(token,cadena2);

      // La carga de la textura la haremos después de conocer si hay cubemap o no!
      
      strcpy(texname,cadena2);
     
      // Carga del tipo de coordenadas de textura
      // En caso de usar shader, aunque se ignoren los tipos de coordenada, lo usamos
      // para saber cuándo una textura es un cubemap...
      token = strtok(NULL,separadores);
      token2string(token,cadena2);

      if((!strcmp(cadena2,"same")) || (!strcmp(cadena2,"uv")))
      {
       matpointer[curmat].texcoordgen[i]=TEXGEN_UV;
      }
      else if(!strcmp(cadena2,"eyelinear"))
      {
       matpointer[curmat].texcoordgen[i]=TEXGEN_EYE_LINEAR;
       if(matpointer[curmat].shader_based == 1 )
       {
        sprintf (FANTASY_DEBUG_STRING, "Warning: el material %s está basado en shader, pero se ha seleccionado texgen tipo eyelinear. Pongo UV\n",matpointer[curmat].matname);
        Debug(DEBUG_LEVEL_ERROR);
        matpointer[curmat].texcoordgen[i]=TEXGEN_UV;
       }
      }
      else if(!strcmp(cadena2,"objectlinear"))
      {
       matpointer[curmat].texcoordgen[i]=TEXGEN_OBJECT_LINEAR;
       if(matpointer[curmat].shader_based == 1 )
       {
        sprintf (FANTASY_DEBUG_STRING, "Warning: el material %s está basado en shader, pero se ha seleccionado texgen tipo objectlinear. Pongo UV\n",matpointer[curmat].matname);
        Debug(DEBUG_LEVEL_ERROR);
        matpointer[curmat].texcoordgen[i]=TEXGEN_UV;
       }
      }
      else if(!strcmp(cadena2,"spheremap"))
      {
       matpointer[curmat].texcoordgen[i]=TEXGEN_SPHERE_MAP;
       if(matpointer[curmat].shader_based == 1 )
       {
        sprintf (FANTASY_DEBUG_STRING, "Warning: el material %s está basado en shader, pero se ha seleccionado texgen tipo spheremap. Pongo UV\n",matpointer[curmat].matname);
        Debug(DEBUG_LEVEL_ERROR);
        matpointer[curmat].texcoordgen[i]=TEXGEN_UV;
       }
      }     	
      else if(!strcmp(cadena2,"cubemap"))
      {
       matpointer[curmat].texcoordgen[i]=TEXGEN_CUBE_MAP;
      }    
      // Ahora podemos cargar la textura
      if(matpointer[curmat].texcoordgen[i] != TEXGEN_CUBE_MAP)
      {
     	matpointer[curmat].textures[i] = ConjuntoTexturas->CargaTextura(texname);
     	        
      }
      else
      {      	
      	matpointer[curmat].textures[i] = ConjuntoTexturas->CargaCubeMap(texname);
      }

      // Si las coordenadas son eyelinear u objectlinear, cogemos el multiplicador
      if((matpointer[curmat].texcoordgen[i]==TEXGEN_OBJECT_LINEAR) ||
      (matpointer[curmat].texcoordgen[i]==TEXGEN_EYE_LINEAR))
      {
       token = strtok(NULL,separadores);
       token2string(token,cadena2);
       matpointer[curmat].linearmultiplier[i]=atof(cadena2);
      }  
      // Finalmente, si no es la primera unidad de textura, vemos qué tipo de blend
      // utiliza esta unidad de textura
      if((i>0) && (matpointer[curmat].shader_based != 1)) // Para tipo shader no se carga
      {
	token = strtok(NULL,separadores);
      	token2string(token,cadena2);

      	if(!strcmp(cadena2,"add"))  	// Blend aditivo
      	{
       	 matpointer[curmat].multitexblend[i]=BLEND_ADD;
      	}
      	else if(!strcmp(cadena2,"modulate"))  // Modulate
      	{
       	 matpointer[curmat].multitexblend[i]=BLEND_MODULATE;
      	}
      	else if(!strcmp(cadena2,"mask"))	// Mask
      	{
	 matpointer[curmat].multitexblend[i]=BLEND_MASK;
      	}
      	else if(!strcmp(cadena2,"mask2"))	// Mask
      	{
      	 matpointer[curmat].multitexblend[i]=BLEND_MASK2;
      	}
      	else if(!strcmp(cadena2,"dot3"))	// Dot3 bump mapping
      	{
	 matpointer[curmat].multitexblend[i]=BLEND_DOT3;
      	}      	
      	else // Por defecto dejamos replace, para darnos cuenta del error
       {     
        sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. Multitex blend no valido\n",matpointer[curmat].matname);
        Debug(DEBUG_LEVEL_ERROR);
        return -1;
       }

      }
      else
        matpointer[curmat].multitexblend[i]=BLEND_MODULATE;
     	
     } // Fin del bucle for

     // Ahora vamos a cargar los parámetros relativos a la iluminación. Ojo, que son opcionales,
     // y pueden ir en cualquier orden!!!
     for(i=0;i<3;i++)
     {
      token = strtok(NULL,separadores);
      if(token == NULL) break;
      token2string(token,cadena2);
      if(!strcmp(cadena2,"specular"))
      {
       	for(j=0;j<3;j++)  // Leemos las 4 componentes
       	{
         token = strtok(NULL,separadores);
         token2string(token,cadena2);
         matpointer[curmat].specular[j]=2.0f*atof(cadena2);
       	}
       	matpointer[curmat].specular[3] = 1.0f;
      }
      else if(!strcmp(cadena2,"emission"))
      {
       	for(j=0;j<3;j++)  // Leemos las 4 componentes
       	{
         token = strtok(NULL,separadores);
         token2string(token,cadena2);
         matpointer[curmat].emission[j]=atof(cadena2);
       	}
       	matpointer[curmat].emission[j] = 1.0f;
      }
      else if((!strcmp(cadena2,"shininess")) || (!strcmp(cadena2,"glossiness")))
      {
         token = strtok(NULL,separadores);
         token2string(token,cadena2);
         matpointer[curmat].shininess=atof(cadena2);
      }
      else 
      {     
       sprintf (FANTASY_DEBUG_STRING, "Material %s no valido. Parámetros de iluminación no válidos\n",matpointer[curmat].matname);
       Debug(DEBUG_LEVEL_ERROR);
       return -1;
      }

     }

     
    }
    curmat++;
   
 }

 materiales = matpointer;
 numero_materiales = nmats;
 pak_close(p);

 if(curmat < nmats)
 {     
   sprintf (FANTASY_DEBUG_STRING, "Fallo al leer el archivo de materiales %s. Hay menos materiales de los definidos en nmats\n",filename);
   Debug(DEBUG_LEVEL_ERROR);
   return -1;
 }
 return nmats;
}