From 78d1f72f17a22cbcbddb7646a88ad39e77153130 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Mon, 1 Feb 2016 19:27:33 +0700 Subject: [PATCH] Fixed segmentation fault on some SIF TEXBs * The vertex and the image size sometimes mismatched * Image always starts fetch at 0,0 to Width,Height. SIF sometimes starts fetch image from specific Vertex to specific Vertex location * UVs sometimes bigger than 1.0 and that cause segmentation fault Makefile now allows NDK build (all architecture). Just set `NDK_BUILD`=`` --- Makefile | 28 +++- src/Itsudemo.cpp | 326 +++++++++++++++++++++++++++++++++++------------ src/TEXB.h | 3 +- src/TEXBLoad.cpp | 28 +++- src/TEXBSave.cpp | 7 +- 5 files changed, 297 insertions(+), 95 deletions(-) diff --git a/Makefile b/Makefile index 45c418a..11091f0 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,36 @@ WHERE_ZLIB?=./zlib-1.2.8 WHERE_LODEPNG?=./lodepng +WHERE_TCLAP?=./tclap-1.2.1 CFLAGS?= +NDK_BUILD ?= ndk-build all: gcc gcc: - g++ -O3 -I$(WHERE_ZLIB) -I$(WHERE_LODEPNG) $(CFLAGS) -c lodepng/lodepng.cpp src/*.cpp - gcc -O3 -I$(WHERE_ZLIB) -I$(WHERE_LODEPNG) $(CFLAGS) -c zlib-1.2.8/*.c - g++ -O3 -I$(WHERE_ZLIB) -I$(WHERE_LODEPNG) $(CFLAGS) -o test *.o -lws2_32 + g++ -O3 -I$(WHERE_ZLIB) -I$(WHERE_LODEPNG) -I$(WHERE_TCLAP) $(CFLAGS) -c lodepng/lodepng.cpp src/*.cpp + gcc -O3 -I$(WHERE_ZLIB) -I$(WHERE_LODEPNG) -I$(WHERE_TCLAP) $(CFLAGS) -c zlib-1.2.8/*.c + g++ -O3 -I$(WHERE_ZLIB) -I$(WHERE_LODEPNG) -I$(WHERE_TCLAP) $(CFLAGS) -o Itsudemo *.o -lws2_32 -rm *.o +ndk: + $(NDK_BUILD) APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk NDK_PROJECT_PATH=. + -mkdir -p bin/jni/{arm64-v8a,armeabi{,-v7a},mips{,64},x86{,_64}}{,/stripped} + -cp obj/local/arm64-v8a/Itsudemo bin/jni/arm64-v8a/ + -cp obj/local/armeabi/Itsudemo bin/jni/armeabi/ + -cp obj/local/armeabi-v7a/Itsudemo bin/jni/armeabi-v7a/ + -cp obj/local/mips/Itsudemo bin/jni/mips/ + -cp obj/local/mips64/Itsudemo bin/jni/mips64/ + -cp obj/local/x86/Itsudemo bin/jni/x86/ + -cp obj/local/x86_64/Itsudemo bin/jni/x86_64/ + rm -R obj + -cp libs/arm64-v8a/Itsudemo bin/jni/arm64-v8a/stripped/ + -cp libs/armeabi/Itsudemo bin/jni/armeabi/stripped/ + -cp libs/armeabi-v7a/Itsudemo bin/jni/armeabi-v7a/stripped/ + -cp libs/mips/Itsudemo bin/jni/mips/stripped/ + -cp libs/mips64/Itsudemo bin/jni/mips64/stripped/ + -cp libs/x86/Itsudemo bin/jni/x86/stripped/ + -cp libs/x86_64/Itsudemo bin/jni/x86_64/stripped/ + rm -R libs + .PHONY: all diff --git a/src/Itsudemo.cpp b/src/Itsudemo.cpp index 22ca370..463264b 100644 --- a/src/Itsudemo.cpp +++ b/src/Itsudemo.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -34,22 +36,187 @@ struct AppendStringVisitor:public TCLAP::Visitor struct InteractiveVariables { - uint32_t Type; // 0=int; 1=TextureBank; 2=TextureImage + uint32_t Type; // 0=int; 1=TextureBank; 2=TextureImage; 3 = std::string int32_t Value; TextureBank* Bank; TextureImage* Image; + std::string String; }; +inline std::vector getRawImageFromTEXB(TextureBank* texb,std::string& name,uint32_t& w,uint32_t& h) +{ + if(texb->Name==name) + { + w=texb->Width; + h=texb->Height; + return texb->FetchRaw(); + } + TextureImage* timg=texb->FetchImage(name); + w=timg->Width; + h=timg->Height; + return std::vector(timg->RawImage,timg->RawImage+w*h*4); +} + +const char* getBasename(const char* path) +{ + const char* a=strrchr(path,'/'); + const char* b=strrchr(path,'\\'); + return a==b?path:std::max(a,b); +} + +std::vector split_string(const std::string split) +{ + std::stringstream ss; + std::vector splitted; + + + for(uint32_t i=0;i0 && !(str[0]>='0' && str[0] <='9')) + { + for(uint32_t i=0;i='A' && c<='Z') || (c>='a' && c<='z') || c=='_') + continue; + return false; + } + return true; + } + return false; +} + +template bool getVectorIndex(std::vector& v,uint32_t index,T& to) +{ + try + { + T& a=v[index]; + to=a; + return true; + } + catch(...) + { + return false; + } +} + +void dumpTEXB(TextureBank* texb,const std::string path) +{ + uint32_t temp_int=0; + std::vector timg_list=texb->FetchAll(); + std::string temp_string; + std::string fixedPath=""; + const char* charPath=path.c_str(); + const char* basename=getBasename(charPath); + if(basename>charPath) + fixedPath=std::string(path,0,basename-charPath+1); + + TextureImage* temp_timg=NULL; + + std::cout << "File: " << path << std::endl << "Size: " << texb->Width << "x" << texb->Height << " pixels" << std::endl; + std::cout << "Image(s): " << timg_list.size() << std::endl; + for(std::vector::iterator i=timg_list.begin();i!=timg_list.end();i++) + { + temp_timg=*i; + std::cout << " " << temp_timg->Name << ": " << temp_timg->Width << "x" << temp_timg->Height << " pixels" << std::endl; + } + temp_string=std::string(strrchr(texb->Name.c_str(),'/')+1)+".png"; + + std::cout << std::endl; + std::cout << "Writing: " << temp_string << std::endl; + temp_int=lodepng::encode(fixedPath+temp_string,texb->FetchRaw(),texb->Width,texb->Height); + for(std::vector::iterator i=timg_list.begin();i!=timg_list.end();i++) + { + temp_timg=*i; + temp_string=std::string(strrchr(temp_timg->Name.c_str(),'/')+1)+".png"; + std::cout << "Writing: " << temp_string << std::endl; + temp_int=lodepng::encode( + fixedPath+temp_string, + std::vector( + reinterpret_cast(temp_timg->RawImage), + reinterpret_cast(temp_timg->RawImage)+temp_timg->Width*temp_timg->Height*4 + ), + temp_timg->Width, + temp_timg->Height + ); + } +} + int main_interactive() { /* std::vector DelimitedCommand; + std::map Variables; + for(std::string TempString;std::getline(std::cin,TempString);) { - std::cout << "> "; + DelimitedCommand=split_string(TempString); + + // Commands + if(DelimitedCommand.size()==0) break; - } - */ + if(DelimitedCommand[0]=="dump") + { + std::string var; + if(getVectorIndex(DelimitedCommand,1,var)) + { + if(var[0]=='@') + { + // Path to TEXB + TextureBank* texb=NULL; + var=var.substr(1); + + try + { + texb=TextureBank::FromFile(var); + } + catch(int e) + { + std::cerr << "Error: Cannot open " << var << ": " << strerror(e) << std::endl; + continue; + } + + const char* filePath=var.c_str(); + const char* basename=getBasename(filePath); + std::string fileDir; + if(basename>=filePath) + fileDir=std::string(filePath,uint32_t(basename-filePath)+1); + + + } + } + else + { + std::cerr << "Error: Arg #2 missing. Expected TEXB or path" << std::endl; + continue; + } + } + }*/ return 1; } @@ -58,7 +225,7 @@ void parse_timg_path(const std::string& from,std::string* to) const char* a=from.c_str(); const char* b=strchr(a,':'); - to[0]=std::string(a,b-a); + to[0]=std::string(a,uint32_t(b-a)); to[1]=std::string(b+1); } @@ -79,13 +246,13 @@ int main(int argc,char* argv[]) AppendStringVisitor AppendR("r",&CmdLineOrder); CmdLine CommandLine("Command-line",' ',VersionString); SwitchArg SwitchA("a","file-info","Prints TEXB information to stdout",CommandLine,false); - ValueArg SwitchC("c","compress-level","Sets compress level when writing TEXB. 0 - No compression, 9 - Best compression",false,6,"unsigned int"); - SwitchArg SwitchD("d","dump-texb","Dump all images, including the texture to PNG in current directory",CommandLine,false); - MultiArg SwitchE("e","extract-image","Extract specificed TIMG image in TEXB.\n String format: :",false,"string",CommandLine,&AppendE); - MultiArg SwitchN("n","rename","Rename internal name of TIMG in TEXB.\n String format: :",false,"string",CommandLine,&AppendN); - ValueArg SwitchO("o","output","Specify output of the TEXB file. Defaults to input file which means overwrite it",false,"","string",CommandLine); - MultiArg SwitchR("r","replace","Replace TIMG with PNG in TEXB.\n String format: :",false,"string",CommandLine,&AppendR); - UnlabeledValueArg TEXBInput("input","Input TEXB File location",true,"","string",CommandLine); + ValueArg SwitchC("c","compress-level","Sets compress level when writing TEXB. 0 - No compression, 9 - Best compression",false,6,"0-9",CommandLine); + SwitchArg SwitchD("d","dump-texb","Dump all images, including the texture to PNG in the TEXB directory",CommandLine,false); + MultiArg SwitchE("e","extract-image","Extract specificed TIMG image in TEXB.",false,"timg name>:",CommandLine,&AppendE); + MultiArg SwitchN("n","rename","Rename internal name of TIMG in TEXB.",false,"timg name>: SwitchO("o","output","Specify output of the TEXB file. Defaults to input file which means overwrite it",false,"","output texb",CommandLine); + MultiArg SwitchR("r","replace","Replace TIMG with PNG in TEXB.",false,"timg name>: TEXBInput("input","Input TEXB File location",true,"","input texb",CommandLine); std::vector SwitchXOR; try @@ -118,7 +285,7 @@ int main(int argc,char* argv[]) std::vector timg_list=texb->FetchAll(); TextureImage* temp_timg=NULL; - std::cout << "File: " << inputPath.c_str() << std::endl << "Size: " << texb->Width << "x" << texb->Height << " pixels" << std::endl; + std::cout << "File: " << inputPath << std::endl << "Size: " << texb->Width << "x" << texb->Height << " pixels" << std::endl; std::cout << "Image(s): " << timg_list.size() << std::endl; for(std::vector::iterator i=timg_list.begin();i!=timg_list.end();i++) { @@ -130,40 +297,7 @@ int main(int argc,char* argv[]) if(SwitchD.getValue()) { - std::vector timg_list=texb->FetchAll(); - std::string temp_string; - TextureImage* temp_timg=NULL; - - if(SwitchA.isSet()==false) - { - std::cout << "File: " << inputPath.c_str() << std::endl << "Size: " << texb->Width << "x" << texb->Height << " pixels" << std::endl; - std::cout << "Image(s): " << timg_list.size() << std::endl; - for(std::vector::iterator i=timg_list.begin();i!=timg_list.end();i++) - { - temp_timg=*i; - std::cout << " " << temp_timg->Name << ": " << temp_timg->Width << "x" << temp_timg->Height << " pixels" << std::endl; - } - } - temp_string=std::string(strrchr(texb->Name.c_str(),'/')+1)+".png"; - - std::cout << std::endl; - std::cout << "Writing: " << temp_string << std::endl; - temp_int=lodepng::encode(temp_string,texb->FetchRaw(),texb->Width,texb->Height); - for(std::vector::iterator i=timg_list.begin();i!=timg_list.end();i++) - { - temp_timg=*i; - temp_string=std::string(strrchr(temp_timg->Name.c_str(),'/')+1)+".png"; - std::cout << "Writing: " << temp_string.c_str() << std::endl; - temp_int=lodepng::encode( - temp_string.c_str(), - std::vector( - reinterpret_cast(temp_timg->RawImage), - reinterpret_cast(temp_timg->RawImage)+temp_timg->Width*temp_timg->Height*4 - ), - temp_timg->Width, - temp_timg->Height - ); - } + dumpTEXB(texb,inputPath); std::cout << std::endl; return 0; } @@ -195,34 +329,39 @@ int main(int argc,char* argv[]) try { - timg=texb->FetchImage(timg_n_path[0]); + rawImage=getRawImageFromTEXB(texb,timg_n_path[0],temp_int2,temp_int3); } catch(int) { - std::cerr << "Extract: Cannot find " << timg_n_path[0] << " in " << texb->Name << std::endl; + std::cerr << "Extract: cannot find " << timg_n_path[0] << "in " << texb->Name << std::endl; continue; } - - temp_int=lodepng::encode(timg_n_path[1],timg->RawImage,timg->Width,timg->Height); + temp_int=lodepng::encode(timg_n_path[1],rawImage,temp_int2,temp_int3); if(temp_int!=0) std::cerr << "Extract: Cannot write " << timg_n_path[1] << ": " << strerror(temp_int) << std::endl; + rawImage=std::vector(); } else if(type=='n') { indexN++; parse_timg_path(RenameList[indexN],timg_n_path); - try + if(texb->Name==timg_n_path[0]) + texb->Name=timg_n_path[1]; + else { - timg=texb->FetchImage(timg_n_path[0]); - } - catch(int) - { - std::cerr << "Rename: Cannot find " << timg_n_path[0] << " in " << texb->Name << std::endl; - continue; - } + try + { + timg=texb->FetchImage(timg_n_path[0]); + } + catch(int) + { + std::cerr << "Rename: Cannot find " << timg_n_path[0] << " in " << texb->Name << std::endl; + continue; + } - timg->Name=std::string(timg_n_path[1]); + timg->Name=std::string(timg_n_path[1]); + } isTexbModified|=1; } else if(type=='r') @@ -230,33 +369,56 @@ int main(int argc,char* argv[]) indexR++; parse_timg_path(ReplaceList[indexR],timg_n_path); - try + if(texb->Name==timg_n_path[0]) { - timg=texb->FetchImage(timg_n_path[0]); + uint8_t* rw=texb->RawImage; + temp_int=lodepng::decode(rawImage,temp_int2,temp_int3,timg_n_path[1]); + if(temp_int!=0) + { + std::cerr << "Replace: Cannot read " << timg_n_path[1] << ": " << strerror(temp_int) << std::endl; + rawImage=std::vector(); + continue; + } + if(texb->Width!=temp_int2 || texb->Height!=temp_int3) + { + std::cerr << "Replace: Cannot write " << timg_n_path[0] << ": Image size mismatch." << std::endl << + " Expected " << texb->Width << "x" << texb->Height << " pixels, got " << + temp_int2 << "x" << temp_int3 << " pixels." << std::endl; + rawImage=std::vector(); + continue; + } + memcpy(timg->RawImage,&rawImage[0],temp_int2*temp_int3*4); } - catch(int) + else { - std::cerr << "Replace: Cannot find " << timg_n_path[0] << " in " << texb->Name << std::endl; - continue; - } + try + { + timg=texb->FetchImage(timg_n_path[0]); + } + catch(int) + { + std::cerr << "Replace: Cannot find " << timg_n_path[0] << " in " << texb->Name << std::endl; + continue; + } - temp_int=lodepng::decode(rawImage,temp_int2,temp_int3,timg_n_path[1]); - if(temp_int!=0) - { - std::cerr << "Replace: Cannot write " << timg_n_path[1] << ": " << strerror(temp_int) << std::endl; - rawImage=std::vector(); - continue; - } - if(timg->Width!=temp_int2 || timg->Height!=temp_int3) - { - std::cerr << "Replace: Cannot write " << timg_n_path[1] << ": Image size mismatch." << std::endl << - " Expected " << timg->Width << "x" << timg->Height << "pixels, got " << - temp_int2 << "x" << temp_int3 << "pixels." << std::endl; - rawImage=std::vector(); - continue; - } + temp_int=lodepng::decode(rawImage,temp_int2,temp_int3,timg_n_path[1]); + if(temp_int!=0) + { + std::cerr << "Replace: Cannot read " << timg_n_path[1] << ": " << strerror(temp_int) << std::endl; + rawImage=std::vector(); + continue; + } + if(timg->Width!=temp_int2 || timg->Height!=temp_int3) + { + std::cerr << "Replace: Cannot write " << timg_n_path[0] << ": Image size mismatch." << std::endl << + " Expected " << timg->Width << "x" << timg->Height << " pixels, got " << + temp_int2 << "x" << temp_int3 << " pixels." << std::endl; + rawImage=std::vector(); + continue; + } - memcpy(timg->RawImage,&rawImage[0],temp_int2*temp_int3*4); + memcpy(timg->RawImage,&rawImage[0],temp_int2*temp_int3*4); + } rawImage=std::vector(); isTexbModified|=2; } diff --git a/src/TEXB.h b/src/TEXB.h index 0ec3c26..5aa8f43 100644 --- a/src/TEXB.h +++ b/src/TEXB.h @@ -55,7 +55,6 @@ struct TextureImage; struct TextureBank { protected: - uint8_t* RawImage; uint32_t RawImageWidth; uint32_t RawImageHeight; std::vector ImageList_Id; @@ -71,6 +70,8 @@ struct TextureBank const uint32_t& Width; // Texture bank height const uint32_t& Height; + // Texture bank raw image + uint8_t* RawImage; // Creates TextureBank from specificed width and height. // It's recommended that the width and the height is power of 2, but width and height doesn't need to be equal // Example: 1024x512 is acceptable width and height diff --git a/src/TEXBLoad.cpp b/src/TEXBLoad.cpp index 87a3b46..937a118 100644 --- a/src/TEXBLoad.cpp +++ b/src/TEXBLoad.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -261,10 +262,7 @@ TextureBank* TextureBank::FromMemory(uint8_t* _mem,size_t _n) TextureImage* timg=texb->ImageList_Id[i]; texb->ImageList_Names[timg->Name]=i; - uint32_t* rawBmp=LIBTEXB_ALLOC(uint32_t,timg->Width*timg->Height); - uint32_t* texbBmp=reinterpret_cast(texb->RawImage); uint32_t* Vrtx=texb->VertexIndexUVs[i]; - Point v[4]={ {Vrtx[0]/65536,Vrtx[1]/65536}, {Vrtx[4]/65536,Vrtx[5]/65536}, @@ -277,13 +275,31 @@ TextureBank* TextureBank::FromMemory(uint8_t* _mem,size_t _n) {Vrtx[10]/65536.0,Vrtx[11]/65536.0}, {Vrtx[14]/65536.0,Vrtx[15]/65536.0} }; + uint32_t* rawBmp=NULL; + uint32_t* texbBmp=reinterpret_cast(texb->RawImage); + + // Check UV + for(uint32_t j=0;j<4;j++) + { + if(t[j].U>1.0) t[j].U=1; + if(t[j].V>1.0) t[j].V=1; + } + + // Check width & height mismatch. + if(v[2].X-v[0].X>timg->Width) + timg->Width=v[2].X-v[0].X; + if(v[2].Y-v[0].Y>timg->Height) + timg->Height=v[2].Y-v[0].Y; + + rawBmp=LIBTEXB_ALLOC(uint32_t,timg->Width*timg->Height); - for(uint32_t y=0;yHeight;y++) + memset(rawBmp,0,timg->Width*timg->Height*4); + for(uint32_t y=v[0].Y;yWidth;x++) + for(uint32_t x=v[0].X;xWidth]=texbBmp[uint32_t(uv.U*tWidth+0.5)+uint32_t(uv.V*tHeight+0.5)*tWidth]; + rawBmp[x+y*v[2].X]=texbBmp[uint32_t(uv.U*tWidth+0.5)+uint32_t(uv.V*tHeight+0.5)*tWidth]; } } diff --git a/src/TEXBSave.cpp b/src/TEXBSave.cpp index 7bbd07f..6a7069b 100644 --- a/src/TEXBSave.cpp +++ b/src/TEXBSave.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -141,7 +142,7 @@ int32_t TextureBank::SaveToMemory(uint8_t*& Memory,size_t* MemorySize,uint32_t C return 0; } -int32_t TextureBank::SaveToMemory(uint8_t** Memory,size_t* MemorySize,uint32_t CompressLevel) +inline int32_t TextureBank::SaveToMemory(uint8_t** Memory,size_t* MemorySize,uint32_t CompressLevel) { return SaveToMemory(*Memory,MemorySize,CompressLevel); } @@ -150,13 +151,13 @@ int32_t TextureBank::SaveToFile(std::string Filename,uint32_t CompressLevel) { FILE* fptr; uint8_t* temp_buffer; - uint32_t bufsize; + size_t bufsize; uint32_t ret; fptr=fopen(Filename.c_str(),"wb"); if(fptr==NULL) return errno; - ret=SaveToMemory(temp_buffer,&bufsize,CompressLevel); + ret=SaveToMemory(&temp_buffer,&bufsize,CompressLevel); if(ret==0) { fwrite(temp_buffer,1,bufsize,fptr);