/*---------------------------------------------------------------------------* Copyright (C) Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ // ------------------------------------------------------------------ // TexConvert.cpp // ------------------------------------------------------------------ #include #include #include "ddsReader.h" #include "tgaReader.h" #include "TexConvert.h" void PrintSupportedDstFormats(void) { printf("Supported destination converted formats:\n"); printf(" GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM\n"); printf(" GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB\n"); printf(" GX2_SURFACE_FORMAT_T_BC1_UNORM\n"); printf(" GX2_SURFACE_FORMAT_T_BC1_SRGB\n"); printf(" GX2_SURFACE_FORMAT_T_BC2_UNORM\n"); printf(" GX2_SURFACE_FORMAT_T_BC2_SRGB\n"); printf(" GX2_SURFACE_FORMAT_T_BC3_UNORM\n"); printf(" GX2_SURFACE_FORMAT_T_BC3_SRGB\n"); printf(" GX2_SURFACE_FORMAT_T_BC4_UNORM\n"); printf(" GX2_SURFACE_FORMAT_T_BC4_SNORM\n"); printf(" GX2_SURFACE_FORMAT_T_BC5_UNORM\n"); printf(" GX2_SURFACE_FORMAT_T_BC5_SNORM\n"); printf(" GX2_SURFACE_FORMAT_TC_R8_UNORM\n"); printf(" GX2_SURFACE_FORMAT_TC_R8_G8_UNORM\n"); printf("\n"); printf("Supported source DDS formats for conversion:\n"); printf(" ARGB 8888\n"); printf(" ABGR 8888\n"); printf(" ABGR 32Float\n"); printf("\n"); printf("Supported source DDS formats for passthrough:\n"); printf(" ARGB 1555 -> GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM\n"); printf(" ABGR 2101010 -> GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM\n"); printf(" ARGB 2101010 -> GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM\n"); printf(" ARGB 4444 -> GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM\n"); printf(" ABGR 8888 -> GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM\n"); printf(" ARGB 8888 -> GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM\n"); printf(" ABGR 16161616 -> GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM\n"); printf(" ABGR 16Float -> GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT\n"); printf(" ABGR 32Float -> GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT\n"); printf(" RGB 565 -> GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM\n"); printf(" RGB 888 -> GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM\n"); printf(" XRGB 1555 -> GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM\n"); printf(" XRGB 4444 -> GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM\n"); printf(" XBGR 4444 -> GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM\n"); printf(" XBGR 8888 -> GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM\n"); printf(" XRGB 8888 -> GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM\n"); printf(" BC1 -> GX2_SURFACE_FORMAT_T_BC1_UNORM\n"); printf(" BC2 -> GX2_SURFACE_FORMAT_T_BC2_UNORM\n"); printf(" BC3 -> GX2_SURFACE_FORMAT_T_BC3_UNORM\n"); printf(" BC4 -> GX2_SURFACE_FORMAT_T_BC4_UNORM\n"); printf(" BC5 -> GX2_SURFACE_FORMAT_T_BC5_UNORM\n"); printf("\n"); printf("(Any necessary component reordering is done during input)\n"); printf("\n"); printf("Supported source GTX format file inputs for converting to DDS:\n"); printf(" GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT -> ABGR 32F\n"); printf(" GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM -> ABGR 16161616\n"); printf(" GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT -> ABGR 16F\n"); printf(" GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM -> ABGR 8888\n"); printf(" GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM -> ABGR 2101010\n"); printf(" GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM -> RGB 565\n"); printf(" GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM -> XRGB 1555\n"); printf(" GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM -> XRGB 4444\n"); printf(" GX2_SURFACE_FORMAT_TC_R8_UNORM -> L8\n"); printf(" GX2_SURFACE_FORMAT_T_BC1_UNORM -> BC1\n"); printf(" GX2_SURFACE_FORMAT_T_BC2_UNORM -> BC2\n"); printf(" GX2_SURFACE_FORMAT_T_BC3_UNORM -> BC3\n"); printf(" GX2_SURFACE_FORMAT_T_BC4_UNORM -> BC4\n"); printf(" GX2_SURFACE_FORMAT_T_BC5_UNORM -> BC5\n"); printf("\n"); printf("(Any necessary component reordering is done during input.It does not guarantee data consistency between input file and output file.)\n"); } void PrintUsageMessage(void) { // 1 2 3 4 5 6 7 //345678901234567890123456789012345678901234567890123456789012345678901234567890 printf("\ Example command line params (to .gtx):\n\ -i texture1.dds(.tga) -i texture2.dds(.tga) -o out.gtx -texturearray\n\ -mipFilter box -minmip 1 -f GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM\n\ -tileMode GX2_TILE_MODE_DEFAULT -swizzle 1\n\ \n\ Example command line params (to .dds):\n\ -i texturebin.gtx -o out.dds -printinfo\n\ \n\ -i : Source image file. This can appear more than once on the\n\ command line for texture arrays or when creating multiple\n\ textures in one gtx file. Maximum source file count is %d.\n\ When source file is gtx file, only the first gtx file is converted to dds.\n\ -o : Destination texture binary file (default: out.gtx)\n\ -oa : Destination existing texture binary file to append textures.\n\ -f : Destination texture format (default: if not specified,\n\ a destination format is chosen based on the source format)\n\ -mipFilter : Mip filter for generating mips (only \"box\" supported now)\n\ -minmip : Minimum mipmap size (ie, generate until dimensions <= NxN)\n\ -swizzle : Swizzle value (refer to GX2 Texture documentation)\n\ -tileMode : Tile mode (default: GX2_TILE_MODE_DEFAULT)\n\ -texarray_from_src : Creates a texture array from the source textures.\n\ Source textures should have the same dimensions.\n\ -mips_from_src : Creates mips from the source textures. The order of the\n\ source textures on the command line should be the desired\n\ order of the mip levels: src_1 = lvl_0, src_2 = lvl_1, etc.\n\ Note: This option cannot be used with texarray_from_src.\n\ -align : Adds alignment padding blocks between the header & image.\n\ The amount of padding depends upon hardware requirements.\n\ -weightingRed : The weighting of the Red or X Channel in BC1/2/3 compression.\n\ The default value is 1.0.\n\ -weightingGreen : The weighting of the Green or Y Channel in BC1/2/3 compression.\n\ The default value is 1.0.\n\ -weightingBlue : The weighting of the Blue or Z Channel in BC1/2/3 compression.\n\ The default value is 1.0.\n\ -bc1alpha : Sets alpha threshold to use when converting to BC1 format.\n\ Texels with alpha < N will be considered transparent.\n\ The default value is 127. Use N=0 to disable alpha.\n\ -valuetype : Treats input texture's value as specified type.\n\ (type = unorm or snorm)(default: unorm)\n\ -gbtilingconfig : Value to use in tiling config register (HW debugging only)\n\ -printinfo : Print out useful information about the resulting textures.\n\ -endianbugfix : Performs 8-in-32 byte swap on the output texture data.\n\ This is a bug workaround for the prototype hardware.\n\ Also need to set this option to convert from endianbugfixed gtx file to dds.\n\ -supported : List supported output texture formats.\n\ -? : Show this usage message.\n", MAX_INPUTFILE_COUNT); return; } void PrintCommandLine(s32 argc, char** argv) { for (s32 count = 0; count < argc; count++) { printf("%s ", argv[count]); } } void LoadDLLs(HMODULE *hTexUtilDLL, TC2Func *fpTC2, HMODULE *hGfdDLL, GFDFunc *fpGFD) { // Load DLL *hTexUtilDLL = LoadLibrary(LIB_DLL_TEXUTILS); if ( !*hTexUtilDLL ) { printf("Failed to load DLL %ws. Exiting.", LIB_DLL_TEXUTILS); FreeLibrary(*hTexUtilDLL); exit(1); } *hGfdDLL = LoadLibrary(LIB_DLL_GFD); if ( !*hGfdDLL ) { printf("Failed to load DLL %ws. Exiting.", LIB_DLL_GFD); FreeLibrary(*hGfdDLL); exit(1); } // Get functions fpTC2->Initialize = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2Initialize")); fpTC2->Destroy = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2Destroy")); fpTC2->GX2SurfaceFormatFromStr = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2GX2SurfaceFormatFromStr")); fpTC2->GenerateMipLevels = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2GenerateMipLevels")); fpTC2->ConvertSurfaceFormat = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2ConvertSurfaceFormat")); fpTC2->ConvertTiling = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2ConvertTiling")); fpTC2->DestroyGX2Surface = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2DestroyGX2Surface")); fpTC2->GenerateTexture = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2GenerateTexture")); fpTC2->DestroyGX2Texture = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2DestroyGX2Texture")); fpTC2->ConvertStringToTileMode = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2ConvertStringToTileMode")); fpTC2->GetSourceSurfaceSize = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2GetSourceSurfaceSize")); fpTC2->CombineAsTextureArray = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2CombineAsTextureArray")); fpTC2->CombineAsMips = reinterpret_cast(GetProcAddress(*hTexUtilDLL, "TC2CombineAsMips")); fpGFD->WriteFileTexture = reinterpret_cast(GetProcAddress(*hGfdDLL, "GFDWriteFileTexture")); fpGFD->AppendWriteFileTexture = reinterpret_cast(GetProcAddress(*hGfdDLL, "GFDAppendWriteFileTexture")); fpGFD->ReadFileTexture = reinterpret_cast(GetProcAddress(*hGfdDLL, "GFDReadFileTexture")); fpGFD->FreeFileTexture = reinterpret_cast(GetProcAddress(*hGfdDLL, "GFDFreeFileTexture")); } void FreeDLLs(HMODULE *hTexUtilDLL, HMODULE *hGfdDLL) { FreeLibrary(*hTexUtilDLL); FreeLibrary(*hGfdDLL); } // Convert GX2SurfaceFormat strings to text char * FormatTypeToString(GX2SurfaceFormat eSurfaceFormat) { // Magic macro - Creates: 'case x: "x"' #define A(x) case x: return #x switch(eSurfaceFormat) { default: A(GX2_SURFACE_FORMAT_INVALID); A(GX2_SURFACE_FORMAT_TC_R8_UNORM); A(GX2_SURFACE_FORMAT_TC_R8_UINT); A(GX2_SURFACE_FORMAT_TC_R8_SNORM); A(GX2_SURFACE_FORMAT_TC_R8_SINT); A(GX2_SURFACE_FORMAT_T_R4_G4_UNORM); A(GX2_SURFACE_FORMAT_TCD_R16_UNORM); A(GX2_SURFACE_FORMAT_TC_R16_UINT ); A(GX2_SURFACE_FORMAT_TC_R16_SNORM); A(GX2_SURFACE_FORMAT_TC_R16_SINT); A(GX2_SURFACE_FORMAT_TC_R16_FLOAT); A(GX2_SURFACE_FORMAT_TC_R8_G8_UNORM); A(GX2_SURFACE_FORMAT_TC_R8_G8_UINT); A(GX2_SURFACE_FORMAT_TC_R8_G8_SNORM); A(GX2_SURFACE_FORMAT_TC_R8_G8_SINT ); A(GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM ); A(GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM); A(GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM); A(GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM ); A(GX2_SURFACE_FORMAT_TC_R32_UINT); A(GX2_SURFACE_FORMAT_TC_R32_SINT); A(GX2_SURFACE_FORMAT_TCD_R32_FLOAT); A(GX2_SURFACE_FORMAT_TC_R16_G16_UNORM); A(GX2_SURFACE_FORMAT_TC_R16_G16_UINT ); A(GX2_SURFACE_FORMAT_TC_R16_G16_SNORM); A(GX2_SURFACE_FORMAT_TC_R16_G16_SINT); A(GX2_SURFACE_FORMAT_TC_R16_G16_FLOAT); A(GX2_SURFACE_FORMAT_D_D24_S8_UNORM); // A(GX2_SURFACE_FORMAT_TC_24_8_UNORM); // dup of above A(GX2_SURFACE_FORMAT_TC_R11_G11_B10_FLOAT); A(GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM); A(GX2_SURFACE_FORMAT_TC_A2_B10_G10_R10_UINT); A(GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM); A(GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_UINT); A(GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SNORM); A(GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SINT); A(GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB); A(GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM); A(GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_UINT); A(GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24); // A(GX2_SURFACE_FORMAT_T_R32_FLOAT_X8_X24); // dup of above A(GX2_SURFACE_FORMAT_T_X32_G8_UINT_X24); A(GX2_SURFACE_FORMAT_TC_R32_G32_UINT); A(GX2_SURFACE_FORMAT_TC_R32_G32_SINT); A(GX2_SURFACE_FORMAT_TC_R32_G32_FLOAT); A(GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM ); A(GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UINT ); A(GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SNORM ); A(GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SINT ); A(GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT ); A(GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_UINT ); A(GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_SINT ); A(GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT ); A(GX2_SURFACE_FORMAT_T_BC1_UNORM); A(GX2_SURFACE_FORMAT_T_BC1_SRGB); A(GX2_SURFACE_FORMAT_T_BC2_UNORM); A(GX2_SURFACE_FORMAT_T_BC2_SRGB); A(GX2_SURFACE_FORMAT_T_BC3_UNORM); A(GX2_SURFACE_FORMAT_T_BC3_SRGB ); A(GX2_SURFACE_FORMAT_T_BC4_UNORM ); A(GX2_SURFACE_FORMAT_T_BC4_SNORM ); A(GX2_SURFACE_FORMAT_T_BC5_UNORM ); A(GX2_SURFACE_FORMAT_T_BC5_SNORM ); } } bool FormatsMatch(const char* pFormatStr, GX2SurfaceFormat otherFormat ) { const char* pOtherStr = FormatTypeToString( otherFormat ); if(0 == strcmp(pOtherStr, pFormatStr)) { return( true ); } // Some formats may be interchangeable for( int i = GX2_SURFACE_FORMAT_FIRST; i <= GX2_SURFACE_FORMAT_LAST; ++i ) { if(0 == strcmp(pFormatStr, FormatTypeToString((GX2SurfaceFormat)i))) { switch((GX2SurfaceFormat)i) { case GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM: return( otherFormat == GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM ); case GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM: return( otherFormat == GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM ); // case GX2_SURFACE_FORMAT_TC_R5_G5_B5_UNORM: return( otherFormat == GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM ); } break; } } return( false ); } // Convert path to file char *PathToFileName(char *pPath) { for(char *p = strchr(pPath, '\0' ); p >= pPath; p--) { if (('\\'==*p) || ('/'==*p)) return p + 1; } return (char *)pPath; } void PrintTextureFileInfo(AppConfig *pConfig) { // print information if(pConfig->printinfo) { printf("// ----- File Format Info ----- \n"); printf(" fileName = %s\n", PathToFileName(pConfig->outFileName)); printf(" indexCount = %d\n", pConfig->inFileCount); printf(" alignMode = %d\n", pConfig->alignMode); printf(" endianMode = %d\n", pConfig->endianbugfix); printf(" BC1Alpha = %d\n", pConfig->bc1alphathreshold); printf(" GBTilingCfg = 0x%X\n", pConfig->gbtilingconfig); } } void PrintTextureSurfaceInfo(bool printinfo, u32 id, GX2Texture *pGx2Textures) { // print information if(printinfo) { printf("// ----- GX2Surface Info ----- \n"); printf(" index = %d \n", id); printf(" dim = %d\n", pGx2Textures->surface.dim); printf(" width = %d\n", pGx2Textures->surface.width); printf(" height = %d\n", pGx2Textures->surface.height); printf(" depth = %d\n", pGx2Textures->surface.depth); printf(" numMips = %d\n", pGx2Textures->surface.numMips); printf(" format = %s\n", FormatTypeToString(pGx2Textures->surface.format)); printf(" aa = %d\n", pGx2Textures->surface.aa); printf(" use = %d\n", pGx2Textures->surface.use); printf(" imageSize = %d\n", pGx2Textures->surface.imageSize); printf(" mipSize = %d\n", pGx2Textures->surface.mipSize); printf(" tileMode = %d\n", pGx2Textures->surface.tileMode); printf(" swizzle = %d, 0x%X\n", pGx2Textures->surface.swizzle, pGx2Textures->surface.swizzle); printf(" alignment = %d\n", pGx2Textures->surface.alignment); printf(" pitch = %d\n", pGx2Textures->surface.pitch); printf(" mipOffset = %d\n", pGx2Textures->surface.mipOffset); } } bool InitializeConfig(s32 argc, char** argv, AppConfig* pConfig) { s32 count = 0; memset(pConfig, 0, sizeof(*pConfig)); //setup default values strcpy_s(pConfig->dstFormat, DSTFORMAT_DEFAULT); strcpy_s(pConfig->tileMode, TILEMODE_DEFAULT); pConfig->gpu = GPU_DEFAULT; pConfig->minMipSize = MINMIPSIZE_DEFAULT; pConfig->mipFilter = MIPFILTER_DEFAULT; pConfig->outFileName = NULL; pConfig->inFileCount = INFILECOUNT_DEFAULT; pConfig->textureArray = TEXTUREARRAY_DEFAULT; pConfig->mipsFromSrc = MIPFROMSOURCE_DEFAULT; pConfig->alignMode = ALIGNMODE_DEFAULT; pConfig->appendMode = APPENDMODE_DEFAULT; pConfig->endianbugfix = ENDIANBUGFIX_DEFAULT; pConfig->initialSwizzle = INITIALSWIZZLE_DEFAULT; pConfig->gbtilingconfig = GBTILINGCONFIG_DEFAULT; pConfig->valuetype = VALUETYPE_DEFAULT; pConfig->useWeighting = USEWEIGHTING_DEFAULT; pConfig->weightingRed = WEIGHTINGRED_DEFAULT; pConfig->weightingGreen = WEIGHTINGGREEN_DEFAULT; pConfig->weightingBlue = WEIGHTINGBLUE_DEFAULT; pConfig->useAdaptiveWeighting = USEADAPTIVEWEIGHTING_DEFAULT; pConfig->bc1usealpha = BC1USEALPHA_DEFAULT; pConfig->bc1alphathreshold = BC1ALPHATHRESHOLD_DEFAULT; pConfig->printinfo = PRINTINFO_DEFAULT; pConfig->fix2197 = false; for (count = 0; count < argc; count++) { if (!strcmp(argv[count], "-tileMode")) { if ((count + 1) < argc) { strcpy_s(pConfig->tileMode, argv[count + 1]); count++; } } else if (!strcmp(argv[count], "-gpu")) { if ((count + 1) < argc) { switch(atoi(argv[count + 1])) { case 0: pConfig->gpu = GPU_V1; break; case 1: pConfig->gpu = GPU_V2; break; case 2: pConfig->gpu = GPU_Cafe; break; default: printf("Error: Unsupported GPU version\n"); exit(1); break; } count++; } } // -i source filename else if (!strcmp(argv[count], "-i")) { if ((count + 1) < argc) { pConfig->inFileName[pConfig->inFileCount++] = argv[count + 1]; if (pConfig->inFileCount > MAX_INPUTFILE_COUNT) { printf("Exceeded maximum input file count of %d. Exiting.\n", MAX_INPUTFILE_COUNT); exit(1); } count++; } } // -o destination filename else if (!strcmp(argv[count], "-o")) { if ((count + 1) < argc) { pConfig->outFileName = argv[count + 1]; count++; } } else if (!strcmp(argv[count], "-oa")) { if ((count + 1) < argc) { pConfig->outFileName = argv[count + 1]; pConfig->appendMode = true; count++; } } else if (!strcmp(argv[count], "-mipFilter")) { if ((count + 1) < argc) { if (!strcmp(argv[count + 1], "box")) { pConfig->mipFilter = MF_BOX; } else { printf("Error: Unsupported mip filter mode\n"); exit(1); } count++; } } // -minmip minimum mip size else if (!strcmp(argv[count], "-minmip")) { if ((count + 1) < argc) { pConfig->minMipSize = atoi(argv[count + 1]); count++; } } else if (!strcmp(argv[count], "-swizzle")) { if ((count + 1) < argc) { if((argv[count + 1][0] == '0') && (argv[count + 1][1] == 'x')) { sscanf_s(argv[count + 1],"0x%X", &pConfig->initialSwizzle); } else { pConfig->initialSwizzle = atoi(argv[count + 1]); } count++; } } // -f destination format else if (!strcmp(argv[count], "-f")) { if ((count + 1) < argc) { strcpy_s(pConfig->dstFormat, argv[count + 1]); count++; } } else if (!strcmp(argv[count], "-gbtilingconfig")) { if ((count + 1) < argc) { if((argv[count + 1][0] == '0') && (argv[count + 1][1] == 'x')) { sscanf_s(argv[count + 1],"0x%X", &pConfig->gbtilingconfig); } else { pConfig->gbtilingconfig = atoi(argv[count + 1]); } count++; } } else if (!strcmp(argv[count], "-valuetype")) { if ((count + 1) < argc) { if (!strcmp(argv[count + 1], "snorm")) { pConfig->valuetype = VT_SNORM; } else { pConfig->valuetype = VT_UNORM; } count++; } } else if (!strcmp(argv[count], "-bc1alpha")) { if ((count + 1) < argc) { pConfig->bc1alphathreshold = atoi(argv[count + 1]); pConfig->bc1usealpha = (pConfig->bc1alphathreshold > 0); count++; } } else if (!strcmp(argv[count], "-weightingRed")) { if ((count + 1) < argc) { pConfig->weightingRed = atof(argv[count + 1]); pConfig->useWeighting = (pConfig->weightingRed != 1.0); count++; } } else if (!strcmp(argv[count], "-weightingGreen")) { if ((count + 1) < argc) { pConfig->weightingGreen = atof(argv[count + 1]); pConfig->useWeighting = (pConfig->weightingGreen != 1.0); count++; } } else if (!strcmp(argv[count], "-weightingBlue")) { if ((count + 1) < argc) { pConfig->weightingBlue = atof(argv[count + 1]); pConfig->useWeighting = (pConfig->weightingBlue != 1.0); count++; } } else if (!strcmp(argv[count], "-texarray_from_src")) { if (pConfig->mipsFromSrc) { printf("Error: Cannot use -texarray_from_src with -mips_from_src.\n"); exit(1); } pConfig->textureArray = true; } else if (!strcmp(argv[count], "-mips_from_src")) { if (pConfig->textureArray) { printf("Error: Cannot use -mips_from_src with -texarray_from_src.\n"); exit(1); } pConfig->mipsFromSrc = true; pConfig->minMipSize = 0; pConfig->mipFilter = MF_NONE; } else if (!strcmp(argv[count], "-align")) { pConfig->alignMode = true; } else if (!strcmp(argv[count], "-endianbugfix")) { pConfig->endianbugfix = true; } // -? or -help print help else if (!strcmp(argv[count], "-?") || !strcmp(argv[count], "-help")) { PrintUsageMessage(); exit(0); } // -supported else if (!strcmp(argv[count], "-supported")) { PrintSupportedDstFormats(); exit(0); } else if (!strcmp(argv[count], "-printinfo")) { pConfig->printinfo = true; } // -fix2197 else if(!strcmp(argv[count], "-fix2197")) { pConfig->fix2197 = true; } else if (count != 0) { printf("Unrecognized command line parameter \"%s\". Exiting.", argv[count]); exit(1); } } assert(pConfig->minMipSize >= 0); if ((pConfig->minMipSize > 0) && (pConfig->mipFilter == MF_NONE)) { // use the default in the case where user specifies a minMipSize but no filter mode pConfig->mipFilter = MF_BOX; } // default to 1 when no minmip specified if (pConfig->mipFilter != MF_NONE && pConfig->minMipSize < 1) { printf("Minimum mip size of one or more not specified. Setting minimum size to 1.\n"); pConfig->minMipSize = 1; } if (!pConfig->inFileCount) { return false; } if (pConfig->mipsFromSrc) { pConfig->minMipSize = 0; pConfig->mipFilter = MF_NONE; } return true; } char* StrToLower (char *str) { char *p; for (p = str; *p; p++) { *p = tolower(*p); } return (str); } bool SNORMToUNORM(GX2Surface *pInSurface) { u32 i; u32 count = 0; u32 value = 0; u32* pSurface = (u32*)pInSurface->imagePtr; if (pInSurface->format == GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM) { // assuming dword aligned size so double check u8* pSurface = (u8*)pInSurface->imagePtr; for (count = 0; count < pInSurface->imageSize; count += 4) { for(i = 0; i < 4; i++) { s8 sv = (s8)*(pSurface + count + i) ; u8 uv = (u8)((s32)sv + 128); *(pSurface + count + i) = uv; } } } else { assert(0); return false; } return true; } s32 _tmain(s32 argc, char* argv[]) { HMODULE hTexUtilDLL; HMODULE hGfdDLL; TC2Func fpTC2; GFDFunc fpGFD; TC2Config texConfig; GX2TileMode tileMode; AppConfig config; u32 count = 0; ExtensionType extType = ET_DDS; GFDEndianSwapMode swapMode = GFD_ENDIAN_SWAP_MODE_DEFAULT; GFDAlignMode alignMode = GFD_ALIGN_MODE_DISABLE; TC2ConvertOptions convertOptions; GX2Texture *pGx2Textures = NULL; GX2Surface *pSrcTextures = NULL; GX2Surface *pTiledTextures = NULL; GX2Surface *pMipmapTextures = NULL; GX2Surface **ppTexturesToConvert = NULL; GX2Surface *pConvertedTextures = NULL; // Loade DLLs LoadDLLs(&hTexUtilDLL, &fpTC2, &hGfdDLL, &fpGFD); if (!InitializeConfig(argc, argv, &config)) { PrintUsageMessage(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 1; } memset(&texConfig, 0, sizeof(texConfig)); texConfig.gbTilingConfig = config.gbtilingconfig; texConfig.gpu = config.gpu; texConfig.bugFix2197 = config.fix2197; memset(&convertOptions, 0, sizeof(convertOptions)); convertOptions.useWeighting = config.useWeighting; convertOptions.weightingRed = config.weightingRed; convertOptions.weightingGreen = config.weightingGreen; convertOptions.weightingBlue = config.weightingBlue; convertOptions.useAdaptiveWeighting = config.useAdaptiveWeighting; convertOptions.bc1usealpha = config.bc1usealpha; convertOptions.bc1alphathreshold = config.bc1alphathreshold; convertOptions.bc1alphathreshold = config.bc1alphathreshold; pSrcTextures = (GX2Surface*)malloc(sizeof(*pSrcTextures) * config.inFileCount); memset(pSrcTextures, 0, sizeof(*pSrcTextures) * config.inFileCount); ppTexturesToConvert = (GX2Surface**)malloc(sizeof(*ppTexturesToConvert) * config.inFileCount); memset(ppTexturesToConvert, 0, (sizeof(ppTexturesToConvert) * config.inFileCount)); if (config.mipFilter != MF_NONE && pSrcTextures[0].numMips < 2) { pMipmapTextures = (GX2Surface*)malloc(sizeof(*pMipmapTextures) * config.inFileCount); memset(pMipmapTextures, 0, sizeof(*pMipmapTextures) * config.inFileCount); } pConvertedTextures = (GX2Surface*)malloc(sizeof(*pConvertedTextures) * config.inFileCount); memset(pConvertedTextures, 0, sizeof(*pConvertedTextures) * config.inFileCount); pTiledTextures = (GX2Surface*)malloc(sizeof(*pTiledTextures) * config.inFileCount); memset(pTiledTextures, 0, sizeof(*pTiledTextures) * config.inFileCount); // set align mode if(config.alignMode) { alignMode = GFD_ALIGN_MODE_ENABLE; } // Reset endian swap mode for endian bug fix mode if(config.endianbugfix) { swapMode = GFD_ENDIAN_SWAP_MODE_8_IN_32; } if (!fpTC2.Initialize(&texConfig)) { FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 1; } if (!fpTC2.ConvertStringToTileMode(config.tileMode, &tileMode)) { printf("Error: Unsupported tileMode."); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 1; } for (count = 0; count < config.inFileCount; count++) { GX2SurfaceFormat dstFormat; // read in TGA texture if (strstr(StrToLower(config.inFileName[count]), ".tga")) { extType = ET_TGA; if (config.outFileName == NULL) { config.outFileName = DEFAULT_GTX_FILENAME; } if (!TGAReader::TGALoadFile(config.inFileName[count], &pSrcTextures[count])) { printf("Error loading TGA file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 2; } } // read in DDS texture else if (strstr(StrToLower(config.inFileName[count]), ".dds")) { extType = ET_DDS; if (config.outFileName == NULL) { config.outFileName = DEFAULT_GTX_FILENAME; } if (!DDSReader::DDSLoadFile(config.inFileName[count], &pSrcTextures[count])) { printf("Error loading DDS file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 3; } } // read in GTX texture else if (strstr(StrToLower(config.inFileName[count]), ".gtx")) { FILE* pFile = NULL; GX2Texture gx2Texture; GX2Surface retiledSurface; GFDEndianSwapMode endianSwapMode = GFD_ENDIAN_SWAP_MODE_DEFAULT; int id = 0; extType = ET_GTX; if(config.endianbugfix) endianSwapMode = GFD_ENDIAN_SWAP_MODE_8_IN_32; if (config.outFileName == NULL) { config.outFileName = DEFAULT_DDS_FILENAME; } if(!fpGFD.ReadFileTexture(&gx2Texture, (GFDGPUVersion)config.gpu, endianSwapMode, config.inFileName[count])) { printf("Error loading GTX file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 3; } // Print input config //PrintTextureFileInfo(&config); // Print Information (ID == 0) PrintTextureSurfaceInfo(config.printinfo, 0, &gx2Texture); // retile and store in texture object if (!fpTC2.ConvertTiling(&gx2Texture.surface, GX2_TILE_MODE_LINEAR_SPECIAL, 0, &retiledSurface)) { printf("Error converting tiling. Exiting.\n"); fpGFD.FreeFileTexture(&gx2Texture); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 18; } if (strstr(StrToLower(config.outFileName), ".dds")) { // Save Texture as DDS file if (!DDSReader::DDSSaveFile(config.outFileName, &retiledSurface)) { printf("Error input format %s doesn't supported in DDS file format. Exiting.\n", FormatTypeToString(retiledSurface.format)); fpGFD.FreeFileTexture(&gx2Texture); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 19; } fpGFD.FreeFileTexture(&gx2Texture); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 0; } else { memcpy(&pSrcTextures[count], &retiledSurface, sizeof(GX2Surface)); } } else { printf("Unrecognized texture file type.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 3; } // convert snorm to unorm if (config.valuetype == VT_SNORM) { if (!SNORMToUNORM(&pSrcTextures[count])) { printf("Error converting snorm to unorm. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 4; } } // generate mipmaps if necessary if (config.mipFilter != MF_NONE && pSrcTextures[count].numMips < 2) { if (!fpTC2.GenerateMipLevels(&pSrcTextures[count], config.minMipSize, MF_BOX, &pMipmapTextures[count])) { printf("Error generating mips. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 4; } ppTexturesToConvert[count] = &pMipmapTextures[count]; } else { ppTexturesToConvert[count] = &pSrcTextures[count]; } // make the destination format to match the source format if it was not specified on the command line (passthrough mode) // likewise if the format was specified, but matches the texture format, no conversion is necessary if (!strcmp(config.dstFormat, DSTFORMAT_DEFAULT) || FormatsMatch(config.dstFormat, ppTexturesToConvert[count]->format ) ) { dstFormat = ppTexturesToConvert[count]->format; } else if (!fpTC2.GX2SurfaceFormatFromStr(config.dstFormat, &dstFormat)) { printf("Error: Unsupported destination format. (%s)\n", argv[count + 1]); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 1; } // convert surface to destination format if (!fpTC2.ConvertSurfaceFormat(ppTexturesToConvert[count], dstFormat, &pConvertedTextures[count], &convertOptions)) { printf("Error converting to destination format. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 5; } } if (config.textureArray) { GX2Surface texArray; memset(&texArray, 0, sizeof(texArray)); fpTC2.CombineAsTextureArray(pConvertedTextures, config.inFileCount, &texArray); pGx2Textures = (GX2Texture*)malloc(sizeof(*pGx2Textures)); memset(pGx2Textures, 0, sizeof(*pGx2Textures)); // tile and store in texture object if (!fpTC2.ConvertTiling(&texArray, tileMode, config.initialSwizzle, pTiledTextures)) { printf("Error converting tiling. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 6; } // generate a texture if (!fpTC2.GenerateTexture(pTiledTextures, pGx2Textures)) { printf("Error generating texture. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 7; } if(config.appendMode) { // append textures to gtx file if(!fpGFD.AppendWriteFileTexture(config.outFileName, (GFDGPUVersion)config.gpu, swapMode, alignMode, 1, pGx2Textures)) { printf("Error writing texture to file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 8; } } else { // write gtx file if(!fpGFD.WriteFileTexture(config.outFileName, (GFDGPUVersion)config.gpu, swapMode, alignMode, 1, pGx2Textures)) { printf("Error writing texture to file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 8; } } // print information PrintTextureFileInfo(&config); PrintTextureSurfaceInfo(config.printinfo, 0, pGx2Textures); fpTC2.DestroyGX2Texture(pGx2Textures); free(pGx2Textures); } else if (config.mipsFromSrc) { GX2Surface mipSurface; memset(&mipSurface, 0, sizeof(mipSurface)); fpTC2.CombineAsMips(pConvertedTextures, config.inFileCount, &mipSurface); pGx2Textures = (GX2Texture*)malloc(sizeof(*pGx2Textures)); memset(pGx2Textures, 0, sizeof(*pGx2Textures)); // tile and store in texture object if (!fpTC2.ConvertTiling(&mipSurface, tileMode, config.initialSwizzle, pTiledTextures)) { printf("Error converting tiling. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 6; } // generate a texture if (!fpTC2.GenerateTexture(pTiledTextures, pGx2Textures)) { printf("Error generating texture. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 7; } if(config.appendMode) { // append textures to gtx file if(!fpGFD.AppendWriteFileTexture(config.outFileName, (GFDGPUVersion)config.gpu, swapMode, alignMode, 1, pGx2Textures)) { printf("Error writing texture to file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 8; } } else { // write gtx file if(!fpGFD.WriteFileTexture(config.outFileName, (GFDGPUVersion)config.gpu, swapMode, alignMode, 1, pGx2Textures)) { printf("Error writing texture to file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 8; } } // print information PrintTextureFileInfo(&config); PrintTextureSurfaceInfo(config.printinfo, 0, pGx2Textures); fpTC2.DestroyGX2Texture(pGx2Textures); free(pGx2Textures); } else { pGx2Textures = (GX2Texture*)malloc(sizeof(*pGx2Textures) * config.inFileCount); memset(pGx2Textures, 0, sizeof(*pGx2Textures) * config.inFileCount); for (count = 0; count < config.inFileCount; count++) { // tile and store in texture object if (!fpTC2.ConvertTiling(&pConvertedTextures[count], tileMode, config.initialSwizzle, &pTiledTextures[count])) { printf("Error converting tiling. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 9; } // generate a texture if (!fpTC2.GenerateTexture(&pTiledTextures[count], &pGx2Textures[count])) { printf("Error generating texture. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 10; } } if(config.appendMode) { // append textures to gtx file if(!fpGFD.AppendWriteFileTexture(config.outFileName, (GFDGPUVersion)config.gpu, swapMode, alignMode, config.inFileCount, pGx2Textures)) { printf("Error writing texture to file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 11; } } else { // write gtx file if(!fpGFD.WriteFileTexture(config.outFileName, (GFDGPUVersion)config.gpu, swapMode, alignMode, config.inFileCount, pGx2Textures)) { printf("Error writing texture to file. Exiting.\n"); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 11; } } // print information PrintTextureFileInfo(&config); for (count = 0; count < config.inFileCount; count++) { // print information PrintTextureSurfaceInfo(config.printinfo, count, pGx2Textures); fpTC2.DestroyGX2Texture(&pGx2Textures[count]); } free(pGx2Textures); } for (count = 0; count < config.inFileCount; count++) { if (config.mipFilter != MF_NONE && pSrcTextures[count].numMips < 2) { fpTC2.DestroyGX2Surface(&pMipmapTextures[count]); } if(extType == ET_DDS) { DDSReader::DDSFree(&pSrcTextures[count]); fpTC2.DestroyGX2Surface(&pSrcTextures[count]); fpTC2.DestroyGX2Surface(&pConvertedTextures[count]); } else if(extType == ET_TGA) { TGAReader::TGAFree(&pSrcTextures[count]); fpTC2.DestroyGX2Surface(&pSrcTextures[count]); fpTC2.DestroyGX2Surface(&pConvertedTextures[count]); } if ((count == 0) || (!config.textureArray && !config.mipsFromSrc)) { fpTC2.DestroyGX2Surface(&pTiledTextures[count]); } } free(pSrcTextures); free(pConvertedTextures); free(pTiledTextures); fpTC2.Destroy(); FreeDLLs(&hTexUtilDLL, &hGfdDLL); return 0; }