/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#ifdef WIN32#include<io.h>#endif#include"q3data.h"#include"md3lib.h"#include"vfs.h"qbooleang_verbose;qbooleang_stripify=qtrue;qbooleang_release;// don't grab, copy output data to new treecharg_releasedir[1024];// c:\quake2\baseq2, etcqbooleang_archive;// don't grab, copy source data to new treecharg_only[256];// if set, only grab this cdqbooleang_skipmodel;// set true when a cd is not g_only// bogus externs for some TA hacks (common/ using them against q3map)char*moddir=NULL;// some old defined that was in cmdlib lost during mergecharwritedir[1024];#if defined ( __linux__ ) || defined ( __APPLE__ )#define strlwr strlower#endif/* ======================================================= PAK FILES ======================================================= */unsignedCom_BlockChecksum(void*buffer,intlength);typedefstruct{charname[56];intfilepos,filelen;}packfile_t;typedefstruct{charid[4];intdirofs;intdirlen;}packheader_t;packfile_tpfiles[16384];FILE*pakfile;packfile_t*pf;packheader_tpakheader;/* ============== ReleaseFile Filename should be gamedir reletive. Either copies the file to the release dir, or adds it to the pak file. ============== */voidReleaseFile(char*filename){charsource[1024];chardest[1024];if(!g_release){return;}sprintf(source,"%s%s",gamedir,filename);sprintf(dest,"%s/%s",g_releasedir,filename);printf("copying to %s\n",dest);QCopyFile(source,dest);return;}typedefstruct{// shader// opaque// opaque 2// blend// blend 2charnames[5][1024];intnum;}ShaderFiles_t;ShaderFiles_ts_shaderFiles;voidFindShaderFiles(char*filename){charbuffer[1024];charstripped[1024];charlinebuffer[1024];intlen,i;char*buf;char*diffuseExtensions[]={".TGA",".WAL",".PCX",0};char*otherExtensions[]={".specular.TGA",".blend.TGA",".alpha.TGA",0};s_shaderFiles.num=0;strcpy(stripped,filename);if(strrchr(stripped,'.')){*strrchr(stripped,'.')=0;}strcat(stripped,".shader");if(FileExists(stripped)){char*p;charmapa[512],mapb[512];strcpy(s_shaderFiles.names[s_shaderFiles.num],stripped);s_shaderFiles.num++;// load and parselen=LoadFile(stripped,(void**)&buf);p=buf;while(p-buf<len){i=0;// skip spaceswhile(*p==' '||*p=='\n'||*p=='\t')p++;// grab rest of the linewhile(*p!=0&&*p!='\n'){linebuffer[i]=*p;i++;p++;}if(*p=='\n'){p++;}linebuffer[i]=0;strlwr(linebuffer);// see if the line specifies an opaque map or blendmapif(strstr(linebuffer,"opaquemap")==linebuffer||strstr(linebuffer,"blendmap")==linebuffer){intj;i=0;mapa[0]=mapb[0]=0;// skip past the keywordwhile(linebuffer[i]!=' '&&linebuffer[i]!='\t'&&linebuffer[i])i++;// skip past spaceswhile((linebuffer[i]==' '||linebuffer[i]=='\t')&&linebuffer[i])i++;// grab first map namej=0;while(linebuffer[i]!=' '&&linebuffer[i]!='\t'&&linebuffer[i]){mapa[j]=linebuffer[i];j++;i++;}mapa[j]=0;// skip past spaceswhile((linebuffer[i]==' '||linebuffer[i]=='\t')&&linebuffer[i])i++;// grab second map namej=0;while(linebuffer[i]!=' '&&linebuffer[i]!='\t'&&linebuffer[i]){mapb[j]=linebuffer[i];j++;i++;}mapb[j]=0;// store map namesif(mapa[0]!=0&&mapa[0]!='-'){sprintf(s_shaderFiles.names[s_shaderFiles.num],"%s%s",gamedir,mapa);s_shaderFiles.num++;}if(mapb[0]!=0&&mapb[0]!='-'&&mapb[0]!='^'&&mapb[0]!='*'){sprintf(s_shaderFiles.names[s_shaderFiles.num],"%s%s",gamedir,mapb);s_shaderFiles.num++;}}}}else{if(strrchr(stripped,'.')){*strrchr(stripped,'.')=0;}// look for diffuse mapsfor(i=0;i<3;i++){strcpy(buffer,stripped);strcat(buffer,diffuseExtensions[i]);if(FileExists(buffer)){strcpy(s_shaderFiles.names[s_shaderFiles.num],buffer);s_shaderFiles.num++;break;}}for(i=0;i<3;i++){strcpy(buffer,stripped);strcat(buffer,otherExtensions[i]);if(FileExists(buffer)){strcpy(s_shaderFiles.names[s_shaderFiles.num],buffer);s_shaderFiles.num++;}}}}/* ============== ReleaseShader Copies all needed files for a shader to the release directory ============== */voidReleaseShader(char*filename){charfullpath[1024];chardest[1024];charstripped[1024];inti;sprintf(fullpath,"%s%s",gamedir,filename);FindShaderFiles(fullpath);for(i=0;i<s_shaderFiles.num;i++){strcpy(stripped,s_shaderFiles.names[i]);if(strstr(stripped,gamedir)){memmove(stripped,stripped+strlen(gamedir),strlen(stripped));}sprintf(dest,"%s/%s",g_releasedir,stripped);printf("copying to %s\n",dest);QCopyFile(s_shaderFiles.names[i],dest);}}/* =============== Cmd_File This is only used to cause a file to be copied during a release build (default.cfg, maps, etc) =============== */voidCmd_File(void){GetToken(qfalse);ReleaseFile(token);}/* =============== PackDirectory_r =============== */#ifdef _WIN32#include"io.h"voidPackDirectory_r(char*dir){struct_finddata_tfileinfo;inthandle;chardirstring[1024];charfilename[1024];sprintf(dirstring,"%s%s/*.*",gamedir,dir);handle=_findfirst(dirstring,&fileinfo);if(handle==-1){return;}do{sprintf(filename,"%s/%s",dir,fileinfo.name);if(fileinfo.attrib&_A_SUBDIR){// directoryif(fileinfo.name[0]!='.'){// don't pak . and ..PackDirectory_r(filename);}continue;}// copy or pack the fileReleaseFile(filename);}while(_findnext(handle,&fileinfo)!=-1);_findclose(handle);}#else#include<sys/types.h>#ifndef WIN32#include<sys/dir.h>#else#include<sys/dirent.h>#endifvoidPackDirectory_r(char*dir){#ifdef NeXTstructdirect**namelist,*ent;#elsestructdirent**namelist,*ent;#endifintcount;structstatst;inti;intlen;charfullname[1024];chardirstring[1024];char*name;sprintf(dirstring,"%s%s",gamedir,dir);count=scandir(dirstring,&namelist,NULL,NULL);for(i=0;i<count;i++){ent=namelist[i];name=ent->d_name;if(name[0]=='.'){continue;}sprintf(fullname,"%s/%s",dir,name);sprintf(dirstring,"%s%s/%s",gamedir,dir,name);if(stat(dirstring,&st)==-1){Error("fstating %s",pf->name);}if(st.st_mode&S_IFDIR){// directoryPackDirectory_r(fullname);continue;}// copy or pack the fileReleaseFile(fullname);}}#endif/* =============== Cmd_Dir This is only used to cause a directory to be copied during a release build (sounds, etc) =============== */voidCmd_Dir(void){GetToken(qfalse);PackDirectory_r(token);}//========================================================================#define MAX_RTEX 16384intnumrtex;charrtex[MAX_RTEX][64];voidReleaseTexture(char*name){inti;charpath[1024];for(i=0;i<numrtex;i++)if(!Q_stricmp(name,rtex[i])){return;}if(numrtex==MAX_RTEX){Error("numrtex == MAX_RTEX");}strcpy(rtex[i],name);numrtex++;sprintf(path,"textures/%s.wal",name);ReleaseFile(path);}/* =============== Cmd_Maps Only relevent for release and pak files. Releases the .bsp files for the maps, and scans all of the files to build a list of all textures used, which are then released. =============== */voidCmd_Maps(void){charmap[1024];while(TokenAvailable()){GetToken(qfalse);sprintf(map,"maps/%s.bsp",token);ReleaseFile(map);if(!g_release){continue;}// get all the texture referencessprintf(map,"%smaps/%s.bsp",gamedir,token);LoadBSPFile(map);}}//==============================================================/* =============== ParseScript =============== */voidParseScript(void){while(1){do{// look for a line starting with a $ commandGetToken(qtrue);if(endofscript){return;}if(token[0]=='$'){break;}while(TokenAvailable())GetToken(qfalse);}while(1);//// model commands//if(!strcmp(token,"$modelname")){Cmd_Modelname();}elseif(!strcmp(token,"$base")){Cmd_Base();}elseif(!strcmp(token,"$exit")){break;}elseif(!strcmp(token,"$3dsconvert")){Cmd_3DSConvert();}elseif(!strcmp(token,"$spritebase")){Cmd_SpriteBase();}elseif(!strcmp(token,"$cd")){Cmd_Cd();}elseif(!strcmp(token,"$origin")){Cmd_Origin();}elseif(!strcmp(token,"$scale")){Cmd_ScaleUp();}elseif(!strcmp(token,"$frame")){Cmd_Frame();}elseif(!strcmp(token,"$skin")){Cmd_Skin();}elseif(!strcmp(token,"$spriteshader")){Cmd_SpriteShader();}elseif(!strcmp(token,"$aseconvert")){Cmd_ASEConvert(qfalse);}elseif(!strcmp(token,"$aseanimconvert")){Cmd_ASEConvert(qtrue);}//// image commands//elseif(!strcmp(token,"$grab")){Cmd_Grab();}elseif(!strcmp(token,"$raw")){Cmd_Raw();}elseif(!strcmp(token,"$colormap")){Cmd_Colormap();}elseif(!strcmp(token,"$environment")){Cmd_Environment();}//// video//elseif(!strcmp(token,"$video")){Cmd_Video();}//// misc//elseif(!strcmp(token,"$file")){Cmd_File();}elseif(!strcmp(token,"$dir")){Cmd_Dir();}elseif(!strcmp(token,"$maps")){Cmd_Maps();}else{Error("bad command %s\n",token);}}}//=======================================================#include"version.h"/* ============== main ============== */intmain(intargc,char**argv){staticinti;// VC4.2 compiler bug if auto...charpath[1024];// using GtkRadiant's versioning next to Id's versioningprintf("Q3Data - (c) 1999 Id Software Inc.\n");printf("NetRadiant - v"RADIANT_VERSION" "__DATE__"\n");ExpandWildcards(&argc,&argv);for(i=1;i<argc;i++){if(!strcmp(argv[i],"-archive")){archive=qtrue;strcpy(archivedir,argv[i+1]);printf("Archiving source to: %s\n",archivedir);i++;}elseif(!strcmp(argv[i],"-release")){g_release=qtrue;strcpy(g_releasedir,argv[i+1]);printf("Copy output to: %s\n",g_releasedir);i++;}elseif(!strcmp(argv[i],"-nostrips")){g_stripify=qfalse;printf("Not optimizing for strips\n");}elseif(!strcmp(argv[i],"-writedir")){strcpy(writedir,argv[i+1]);printf("Write output to: %s\n",writedir);i++;}elseif(!strcmp(argv[i],"-verbose")){g_verbose=qtrue;}elseif(!strcmp(argv[i],"-dump")){printf("Dumping contents of: '%s'\n",argv[i+1]);if(strstr(argv[i+1],".md3")){MD3_Dump(argv[i+1]);}else{Error("Do not know how to dump the contents of '%s'\n",argv[i+1]);}i++;}elseif(!strcmp(argv[i],"-3dsconvert")){// NOTE TTimo this is broken, tried on a sample .3ds// what happens .. it calls the Convert3DStoMD3,// which calls the scriptlib function in non initialized state .. and crashesprintf("Converting %s.3DS to %s.MD3\n",argv[i+1],argv[i+1]);SetQdirFromPath(argv[i+1]);vfsInitDirectory(gamedir);Convert3DStoMD3(argv[i+1]);i++;}elseif(!strcmp(argv[i],"-only")){strcpy(g_only,argv[i+1]);printf("Only grabbing %s\n",g_only);i++;}elseif(!strcmp(argv[i],"-gamedir")){strcpy(gamedir,argv[i+1]);i++;}elseif(argv[i][0]=='-'){Error("Unknown option \"%s\"",argv[i]);}else{break;}}if(i==argc){Error("usage: q3data [-archive <directory>] [-dump <file.md3>] [-release <directory>] [-only <model>] [-3dsconvert <file.3ds>] [-verbose] [file.qdt]");}for(;i<argc;i++){printf("--------------- %s ---------------\n",argv[i]);// load the scriptstrcpy(path,argv[i]);DefaultExtension(path,".qdt");if(!gamedir[0]){SetQdirFromPath(path);}// NOTE TTimo// q3data went through a partial conversion to use the vfs// it was never actually tested before 1.1.1// the code is still mostly using direct file access callsvfsInitDirectory(gamedir);LoadScriptFile(ExpandArg(path),-1);//// parse it//ParseScript();// write out the last modelFinishModel(TYPE_UNKNOWN);}return0;}