From d19dc772db2c9b796c9ad3f5cc8d03e1dad9b407 Mon Sep 17 00:00:00 2001 From: Exynox Date: Sun, 7 Jul 2024 21:09:33 +0300 Subject: [PATCH] Fixed buffer overflow issue in DXTCImage, added nicer error messages. --- bin/.gitignore | 1 + bin/errorlog.exe | Bin 81920 -> 0 bytes bin/pack/metin2_patch_dragon_rock.rdch | Bin 20559 -> 0 bytes bin/pack/metin2_patch_dragon_rock_mobs.rdch | Bin 8222 -> 0 bytes src/EterBase/error.cpp | 121 +-- src/EterImageLib/DXTCImage.cpp | 791 +------------------- src/EterImageLib/DXTCImage.h | 14 +- src/EterLib/GrpImageTexture.cpp | 3 +- 8 files changed, 18 insertions(+), 912 deletions(-) delete mode 100644 bin/errorlog.exe delete mode 100644 bin/pack/metin2_patch_dragon_rock.rdch delete mode 100644 bin/pack/metin2_patch_dragon_rock_mobs.rdch diff --git a/bin/.gitignore b/bin/.gitignore index 12acc70c..e3d4d4f3 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -7,6 +7,7 @@ metin2.cfg BGM/lastplay.inf # Log files +ErrorLog.txt log.txt syserr.txt diff --git a/bin/errorlog.exe b/bin/errorlog.exe deleted file mode 100644 index db598b4e7a6bf914c4682698a34c48b1b8b3aec6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81920 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�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 W-va$D(BA_6EzsWr{Vi}~3;bVxqB)QN diff --git a/bin/pack/metin2_patch_dragon_rock.rdch b/bin/pack/metin2_patch_dragon_rock.rdch deleted file mode 100644 index 8824957478f64ada2db4a4c83139999e8902124e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20559 zcmb_k*>dAH5ZoLO$zQlC4>@-kUz=oeZITaRK@uo&%|iu3t2keu#(yUSm5n8IPUKzD+n~hehTw;`nl_(`*B~FQ0iBuw1Vil{2 zmD)FT+1Y*Dl4=T&l$ru0rKSK$sVP88gkDFg$!>PdN*gaD79??DK@t)cB++0&5{U2m zK-Ain%}rjbZ9eQV*^lzd>ar>E|6C#d0K}L0xq#?4YSr$0OccvC&2pXbEH^aEO#;g; z&2pQ-a!0e=C9vGnEcYzSHB`p22!hN$Fr>x=!LyJW0}HJ&U`UM#g7<~g7+7eH0Yhp` z5Tq|Rw8jL%vyd7C3*Ex=!TUmL3@oEQ=5{{!8ti=Gv^lX` zzQOgQ-EtZe_!G$#C@qp{q_s$T{P_FuMm+_+=JBka+=y%!?p+ z7BVkjq4NR^nHNEjzF@8;^CAeIh0F_B=z0N$%!?p+U&y?Gg{~LOd}Lk(LHYs=nHNFu zEM#85Le~p0WL^Y8`ht0g%!?p+7BVkjq3Z=0GB1MQeIfG#7P?+AE0B2+1nCPfWL^Zp zvygcK3tcb3ka-aV>C0O>FM{A%$h?4st`}g)ya`OpUT9WHoA1Ez>f$U3|?kO$F^^^}lP+F4fSq4f= zU?BSv5R{hWde#R@OJE@T5)hP@XMgDvKgV{+ylP($`azx?0V&u{NsfoQ*%z*C96Gk2CW}x*5|hA5dm97t?7K`1Cmz zbT-$cr=U)M=8~g6MHfSJ!nw!&v(ujkGq+Jrop56_lIhskTr@LxH4@+XtLe>170d{6 zZ$_NDsJ`>DaUW)xpYP7LjqXG94$5QHC)nJUl}0T|88{2i_NtLPfrYrZ2Jesz|Hunn zR?!g|BD3Kic`sdQ4i~dLL{6HC>kb#q#8tp~GgJj!G&46-R0W)0&7l8YtfTW*d>zH@ z1(&SM&GxVwXSn1_5))?B_IBPSZ$(`C`BGii_HYB|_*-8{bMd0J8T?W?Gw^pVib;5{ z@^t?_KHYzh7yo}s$)7KbgZs~J49BEr$KP_V<#hKwKHYtf7x#ae+SvZX#+R-1$Fk~j z|Ix?1>?&-k7>DXDKGW6Ma@iW~0`S)y1Noxux_;XHeJT;LE6IzUajW?!!HCf-yD4>% zFLu}^bJMo+IlGkg98DFKTD$ekGO|`yLOi+EUWkmvXMA(_G0e@*_5ps&#>UvZ+qBzU z&LyN!4!tuksy3Oeaq@H)VW6|h?yzaNe9p8X zB|q75o>@oRJm^P!h;r={;nYCHv1pC0yI$LycGvZu{LO_kFw?ZAR#k4>Z9>gWS=y^g zKBh{R@1!Yc-mU8Wj4-uDQ7*Ng+h4$rH0l?yBMtin?8v_DW~fvdb#-Ysk1on&_YV^0 zt@Ohf*(d`;wzaxGRA;JBd+jCYs*|@-=w>Os+BJv-cxiN3t{Wv)Fga44ZxDSfT%Yt! zY6e~!6xnHee(AHmMY)}Z55l(8DH}yk-)+jRuUK-U8RDfj_y&e&~&Hb%Ra=TySj;qbDoCb5Bg*gT!4ZlJ}#D4ErAS2wB>et{*5SbX6 zIIbeygy>=N-qHDT9;{-~`!UOcxG{P6DRvDh2Ll9Q^hF!D^|7h;uJ!^{WuQCDTthvYq1=)I-cXJ%_`W3Ge5o?EIQGq#9JV8^4xFAU}tA4*<0~xK5j-|(8~}5=*TXx8VQLnpT&)j-&Py1Qu-qafOk8)y;_aoBn=^Z@wl1;leyNPy8zE=j{YF*#YJuB? zH+})+sp*9G@UP(dlPRm&E^o4x-2LePajE}0?oy{(clozdK^4pR58fBUu`N6P<^b*! zF76dHLtPYlX|uX*upb&ct5IWD&sU|fva@F%5@L2`Hu)T9u56_`NA>+>*x@diyOZZ2 bP9yFWtS)2<-$y*LU3=tn(BT(#oq+!Xu|OEg diff --git a/bin/pack/metin2_patch_dragon_rock_mobs.rdch b/bin/pack/metin2_patch_dragon_rock_mobs.rdch deleted file mode 100644 index b775f4996a0aa5d87bb65b25d09f77d342302895..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8222 zcmbtZ+iu%13@x^O$euO~+v?TbwYzo0u-^#W#7T`hap1TJ`nW%zDT&gNFEpJNC}0{o zhes4iG0DHPv$HSl|Fiagb(K79i~9Mos_&9*wL3I7jcpC4EI zuX6}`j44rk(o-B`2}gqe)WSFUF0Zo^Dcmcjd8&y-wO$v?yha-LifL2LFm1RWtlfjGy$ zI$~RYBqIbMWTJD$jzfN8as5_h2P6E!@(U1?h|$e=jVaNK#6K-AC>HZ!rsKY!?Jd-_ z&SmPArgM}c%qV@UQhMpVT~0@3Q)DijNq8jKh3G4+O#x>_QgM%`v;}gDh%ELx1-7Ma zp}s4~EyXV8dX6messVEeS+KJROc(ZeD~OhJtT^QfE@#kYSCyr`kisJeO7QAot;_IC zz|ZpWgvAJi+LUvUogF>eOeIue!m&E100M^-`DCy@pU|S+(zQ9|cn}N%CMvf!71FaDF$*9F~Fu_WD!`NlXyAz)s9UB z*J28E06v0_aCR6tpPAR$dLbhOAVi*%I*vn5aGH}8c}|+705NiMY}=c?SXOmz?~mBD zbI4-|Op4QOGG3gq%QSJe6=d*oevIJVj#7xkcQMZb4;M=B4IRv%$C7{`IZuLnTX-GY z9?s(^W`%cHMHq9n;pI*c_T%1Ac(o*4gnt2G8uXFXnjtTp2Z7+oU&|P&T)1e^naEc> zuC`ho4>+d*e0)SS47NPNBRN)tw+jQOiXC$;8MjbIiX9I@=Q-yZG|r*?6wZgB;9Q<5 z>wMMR7Wq20cUEjt*yWirUZ2D!h>%-r3`;vSt}Y)(q3F(2DnhNwBOdY`qrI4_mAi5P za{>0=(5c8bXAc4@`t>N!B!SCTSH~tX*J43;03gK>LXv1B!_^j;p<3npDnR&h0zLeS z_Vib|C&moWz|M3D6PKW|NQ(TahIcdo1_8P=HXNb+tf?7XBN06UQ+v8TGOQp}p4`Sk zMku_N($t-Y}OKuZi$XBIIv9U~!tDK~VWH-D*yX*i?JAN9n-EP%{#OF4e4nA1Sx59*j9J>VpY_Q!Mw7N i3Cun(%Zr8S$OM?w)Kv8@TU7>duJPaiLDy`Q@%0}ayX0>G diff --git a/src/EterBase/error.cpp b/src/EterBase/error.cpp index b815904f..8a453e21 100644 --- a/src/EterBase/error.cpp +++ b/src/EterBase/error.cpp @@ -7,32 +7,13 @@ FILE * fException; -/* -static char __msg[4000], __cmsg[4000]; -static int __idx; -CLZObject __l; -*/ -/* -typedef BOOL -(CALLBACK *PENUMLOADED_MODULES_CALLBACK)( - __in PCSTR ModuleName, - __in ULONG ModuleBase, - __in ULONG ModuleSize, - __in_opt PVOID UserContext - ); -*/ -#if _MSC_VER >= 1400 BOOL CALLBACK EnumerateLoadedModulesProc(PCSTR ModuleName, ULONG ModuleBase, ULONG ModuleSize, PVOID UserContext) -#else -BOOL CALLBACK EnumerateLoadedModulesProc(PSTR ModuleName, ULONG ModuleBase, ULONG ModuleSize, PVOID UserContext) -#endif { DWORD offset = *((DWORD*)UserContext); if (offset >= ModuleBase && offset <= ModuleBase + ModuleSize) { fprintf(fException, "%s", ModuleName); - //__idx += sprintf(__msg+__idx, "%s", ModuleName); return FALSE; } else @@ -56,20 +37,10 @@ LONG __stdcall EterExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo) module_time = (time_t)GetTimestampForLoadedLibrary(hModule); fprintf(fException, "Module Name: %s\n", module_name); - fprintf(fException, "Time Stamp: 0x%08x - %s\n", module_time, ctime(&module_time)); + fprintf(fException, "Time Stamp: %lld - %s\n", module_time, ctime(&module_time)); fprintf(fException, "\n"); fprintf(fException, "Exception Type: 0x%08x\n", pExceptionInfo->ExceptionRecord->ExceptionCode); fprintf(fException, "\n"); - - /* - { - __idx+=sprintf(__msg+__idx,"Module Name: %s\n", module_name); - __idx+=sprintf(__msg+__idx, "Time Stamp: 0x%08x - %s\n", module_time, ctime(&module_time)); - __idx+=sprintf(__msg+__idx, "\n"); - __idx+=sprintf(__msg+__idx, "Exception Type: 0x%08x\n", pExceptionInfo->ExceptionRecord->ExceptionCode); - __idx+=sprintf(__msg+__idx, "\n"); - } - */ CONTEXT& context = *pExceptionInfo->ContextRecord; @@ -78,15 +49,6 @@ LONG __stdcall EterExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo) fprintf(fException, "esi: 0x%08x\tedi: 0x%08x\n", context.Esi, context.Edi); fprintf(fException, "ebp: 0x%08x\tesp: 0x%08x\n", context.Ebp, context.Esp); fprintf(fException, "\n"); - /* - { - __idx+=sprintf(__msg+__idx, "eax: 0x%08x\tebx: 0x%08x\n", context.Eax, context.Ebx); - __idx+=sprintf(__msg+__idx, "ecx: 0x%08x\tedx: 0x%08x\n", context.Ecx, context.Edx); - __idx+=sprintf(__msg+__idx, "esi: 0x%08x\tedi: 0x%08x\n", context.Esi, context.Edi); - __idx+=sprintf(__msg+__idx, "ebp: 0x%08x\tesp: 0x%08x\n", context.Ebp, context.Esp); - __idx+=sprintf(__msg+__idx, "\n"); - } - */ STACKFRAME stackFrame = {0,}; stackFrame.AddrPC.Offset = context.Eip; @@ -101,11 +63,8 @@ LONG __stdcall EterExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo) if (StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &stackFrame, &context, NULL, NULL, NULL, NULL) != FALSE) { fprintf(fException, "0x%08x\t", stackFrame.AddrPC.Offset); - //__idx+=sprintf(__msg+__idx, "0x%08x\t", stackFrame.AddrPC.Offset); EnumerateLoadedModules(hProcess, (PENUMLOADED_MODULES_CALLBACK) EnumerateLoadedModulesProc, &stackFrame.AddrPC.Offset); fprintf(fException, "\n"); - - //__idx+=sprintf(__msg+__idx, "\n"); } else { @@ -114,89 +73,13 @@ LONG __stdcall EterExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo) } fprintf(fException, "\n"); - //__idx+=sprintf(__msg+__idx, "\n"); - - -/* - BYTE* stack = (BYTE*)(context.Esp); - fprintf(fException, "stack %08x - %08x\n", context.Esp, context.Esp+1024); - //__idx+=sprintf(__msg+__idx, "stack %08x - %08x\n", context.Esp, context.Esp+1024); - - for(i=0; i<16; ++i) - { - fprintf(fException, "%08X : ", context.Esp+i*16); - //__idx+=sprintf(__msg+__idx, "%08X : ", context.Esp+i*16); - for(int j=0; j<16; ++j) - { - fprintf(fException, "%02X ", stack[i*16+j]); - //__idx+=sprintf(__msg+__idx, "%02X ", stack[i*16+j]); - } - fprintf(fException, "\n"); - //__idx+=sprintf(__msg+__idx, "\n"); - } - fprintf(fException, "\n"); - //__idx+=sprintf(__msg+__idx, "\n"); -*/ fflush(fException); fclose(fException); fException = NULL; - //WinExec() - /*CreateProcess("cmd.exe",NULL,NULL,NULL,FALSE, - CREATE_NEW_PROCESS_GROUP|DETACHED_PROCESS,NULL,NULL,NULL,NULL); - MessageBox(NULL,"°ÔÀÓ ½ÇÇà¿¡ Ä¡¸íÀûÀÎ ¹®Á¦°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.\n°ÔÀÓÀ» Á¾·áÇÏ°í ¿¡·¯ ·Î±×¸¦ ³²±é´Ï´Ù.\n¿¡·¯ ·Î±×¸¦ ¼­¹ö¿¡ º¸³»½Ã°Ú½À´Ï±î?","¿¡·¯ ¹ß»ý!",MB_YESNO);*/ - - /* - __l.BeginCompressInBuffer(__msg,__idx,__cmsg); - if (__l.Compress()) - { - //fprintf(fException,"Compress printing\n"); - // send this to server - SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - ioctlsocket(s,FIONBIO,0); - - if (s==INVALID_SOCKET) - { - //fprintf(fException,"INVALID %X\n",WSAGetLastError()); - } - - sockaddr_in sa; - sa.sin_family = AF_INET; - sa.sin_port = htons(19294); - sa.sin_addr.s_addr = inet_addr("147.46.127.42"); - if (connect(s,(sockaddr*)&sa,sizeof(sa))) - { - //fprintf(fException,"%X\n",WSAGetLastError()); - } - - int total = 0; - int ret=0; - while(1) - { - //ret = send(s,(char*)__msg+total,__idx-total,0); - ret = send(s,(char*)__l.GetBuffer()+total,__l.GetSize()-total,0); - //fprintf(fException,"send %d\n",ret); - if (ret<0) - { - //fprintf(fException,"%X\n",WSAGetLastError()); - break; - } - total+=ret; - if (total>=__idx) - //if (total>=__l.GetSize()) - break; - } - //__l.GetBuffer(); - Sleep(500); - closesocket(s); - }*/ - - WinExec("errorlog.exe",SW_SHOW); - - + MessageBox(NULL, "A fatal error was encountered while running the game.\nAn error log was saved to ErrorLog.txt.\nPlease consider reporting this issue.", "Error!", MB_OK); } return EXCEPTION_EXECUTE_HANDLER; diff --git a/src/EterImageLib/DXTCImage.cpp b/src/EterImageLib/DXTCImage.cpp index 411a178f..1df791f6 100644 --- a/src/EterImageLib/DXTCImage.cpp +++ b/src/EterImageLib/DXTCImage.cpp @@ -83,51 +83,7 @@ void CDXTCImage::Clear() Initialize(); } -bool CDXTCImage::LoadFromFile(const char * filename) -{ - // only understands .dds files for now - // return true if success - char * exts[] = { ".DDS" }; - int next = 1; - - static char fileupper[MAX_PATH+1]; - - strncpy(fileupper, filename, MAX_PATH); - strupr(fileupper); - - int i; - bool knownformat = false; - - for (i = 0; i < next; ++i) - { - char * found = strstr(fileupper, exts[0]); - - if (found != NULL) - { - knownformat = true; - break; - } - } - - if (knownformat == false) - { - Tracef("Unknown file format encountered! [%s]\n", filename); - return(false); - } - - CMappedFile mappedFile; - LPCVOID pvMap; - - if (!mappedFile.Create(filename, &pvMap, 0, 0)) - { - Tracef("Can't open file for reading! [%s]\n", filename); - return false; - } - - return LoadFromMemory((const BYTE*) pvMap); -} - -bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap) +bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap, int iSize) { ////////////////////////////////////// // start reading the file @@ -135,18 +91,26 @@ bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap) DWORD dwMagic; // Read magic number + if (iSize < sizeof(DWORD)) + return false; + dwMagic = *(DWORD *) c_pbMap; c_pbMap += sizeof(DWORD); + iSize -= sizeof(DWORD); -//!@# -// if (dwMagic != MAKEFOURCC('D','D','S',' ')) -// return false; + // Check whether the magic header is correct + if (dwMagic != MAKEFOURCC('D','D','S',' ')) + return false; DDSURFACEDESC2 ddsd; // read from dds file // Read the surface description + if (iSize < sizeof(DDSURFACEDESC2)) + return false; + memcpy(&ddsd, c_pbMap, sizeof(DDSURFACEDESC2)); c_pbMap += sizeof(DDSURFACEDESC2); + iSize -= sizeof(DDSURFACEDESC2); // Does texture have mipmaps? m_bMipTexture = (ddsd.dwMipMapCount > 0) ? TRUE : FALSE; @@ -211,52 +175,6 @@ bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap) return true; } -////////////////////////////////////////////////////////////////////// -bool CDXTCImage::LoadFromMemory(const BYTE * c_pbMap) -{ - if (!LoadHeaderFromMemory(c_pbMap)) - return false; - - if (m_dwFlags & DDSD_PITCH) - { - DWORD dwBytesPerRow = m_nWidth * m_xddPixelFormat.dwRGBBitCount / 8; - - m_nCompSize = m_lPitch * m_nHeight; - m_nCompLineSz = dwBytesPerRow; - - m_bCompVector[0].resize(m_nCompSize); - BYTE * pDest = &m_bCompVector[0][0]; - - c_pbMap = m_pbCompBufferByLevels[0]; - - for (int yp = 0; yp < m_nHeight; ++yp) - { - memcpy(pDest, c_pbMap, dwBytesPerRow); - pDest += m_lPitch; - c_pbMap += m_lPitch; - } - } - else - { - if (m_dwFlags & DDSD_MIPMAPCOUNT) - { - for (DWORD dwLinearSize = m_lPitch, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2) - { - m_bCompVector[i].resize(dwLinearSize); - Copy(i, &m_bCompVector[i][0], dwLinearSize); - } - } - else - { - m_bCompVector[0].resize(m_lPitch); - Copy(0, &m_bCompVector[0][0], m_lPitch); - } - } - - // done reading file - return true; -} - bool CDXTCImage::Copy(int miplevel, BYTE * pbDest, long lDestPitch) { if (!(m_dwFlags & DDSD_MIPMAPCOUNT)) @@ -959,688 +877,3 @@ VOID CDXTCImage::DecodePixelFormat(CHAR* strPixelFormat, XDDPIXELFORMAT* pxddpf) break; } } - -/* -// Struct to hold various timing values -struct TimingInfo -{ - LARGE_INTEGER m_start_clk; - LARGE_INTEGER m_end_clk; - - int m_nSamples; - LARGE_INTEGER m_interval_sum; // sum of all end-start, nSamples number added in - - CString m_csName; // text desc of what timed -}; - -void CDXTCImage::RunTimingSession() -{ - // Must have a dxt5 texture loaded - // No special reason - just lazy coding - // Functions called to time code are separate from non-timed - // code. It's alogorithm that counts. - ASSERT(m_pCompBytes != NULL); - ASSERT(m_pDecompBytes != NULL); // must already have allocated memory - - switch (m_CompFormat) - { - case PF_DXT1: - case PF_DXT2: - case PF_DXT3: - case PF_DXT4: - case PF_UNKNOWN: - Tracef("You must have a DXT5 texture loaded to RunTimingSession()!!\n"); - Tracef("Now I will be nasty and ASSERT(false)!\n"); - ASSERT(false); - break; - - case PF_DXT5: - Tracef("Running code timing session on DXT5 color decompress\n"); - break; - } - - LARGE_INTEGER start_clk, end_clk; - QueryPerformanceCounter(&start_clk); -#define NMETHOD 4 -#define NBATCHES 4 - int passes[NBATCHES]; - passes[0] = 1; - passes[1] = 10; - passes[2] = 30; - passes[3] = 50; - - TimingInfo method[NMETHOD][NBATCHES]; - - int i, n; - - FILE * pf = fopen("timing.txt", "wt"); - - if (pf == NULL) - { - return; - } - - fprintf(pf, "\n\n"); - - for (i = 0; i < NBATCHES; ++i) - { - Sleep(50); - fprintf(pf,"i: %d passes[i]: %d\n", i, passes[i]); - Time_Decomp5_01(passes[i], &(method[0][i])); - Time_Decomp5_02(passes[i], &(method[1][i])); - Time_Decomp5_03(passes[i], &(method[2][i])); - Time_Decomp5_04(passes[i], &(method[3][i])); - } - - QueryPerformanceCounter(&end_clk); - - // unsigned long total; - // total = (unsigned long) (end_clk - start_clk); - LARGE_INTEGER freq; - QueryPerformanceFrequency(& freq); - - fprintf(pf, "\nCounter freq = %u %d \n", freq.LowPart, freq.HighPart); - fprintf(pf, "start: %u %u end: %u %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart); - - Tracef("\nCounter freq = %u %d \n", freq.LowPart, freq.HighPart); - Tracef("start: %u %u end: %u %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart); - - double dur = ((double)end_clk.LowPart - (double)start_clk.LowPart) / (double)freq.LowPart; - - fprintf(pf, "Total timing session took: %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur); - fprintf(pf, "\n\n"); - - Tracef("Total timing session took: %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur); - Tracef("\n\n"); - - for (n = 0; n < NMETHOD; ++n) - { - for (i = 0; i < NBATCHES; ++i) - { - fprintf(pf, "method %d:\n", n); - fprintf(pf, " %s", method[n][i].m_csName); - fprintf(pf, " tot: %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); - - Tracef("method %d:\n", n); - Tracef(" %s", method[n][i].m_csName); - Tracef(" tot: %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); - - dur = ((double)method[n][i].m_interval_sum.LowPart) / ((double)method[n][i].m_nSamples * (double)freq.LowPart); - - fprintf(pf, " avg: %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples); - fprintf(pf, " avg time: %f sec\n", dur); - - Tracef(" avg: %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples); - Tracef(" avg time: %f sec\n", dur); - } - - fprintf(pf, "\n\n"); - Tracef("\n\n"); - } - - fclose(pf); - - MessageBeep(MB_OK); - //BOOL QueryPerformanceFrequency( - // LARGE_INTEGER *lpFrequency // address of current frequency - //); -} - -inline void GetColorBlockColors_m2(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - // method 2 - // freak variable bit structure method - // normal math - Color565 * pCol; - - pCol = (Color565*) & (pBlock->col0); - - col_0->a = 0xff; - col_0->r = pCol->nRed; - col_0->r <<= 3; // shift to full precision - col_0->g = pCol->nGreen; - col_0->g <<= 2; - col_0->b = pCol->nBlue; - col_0->b <<= 3; - - pCol = (Color565*) & (pBlock->col1); - col_1->a = 0xff; - col_1->r = pCol->nRed; - col_1->r <<= 3; // shift to full precision - col_1->g = pCol->nGreen; - col_1->g <<= 2; - col_1->b = pCol->nBlue; - col_1->b <<= 3; - - if (pBlock->col0 > pBlock->col1) - { - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3; - // no +1 for rounding - // as bits have been shifted to 888 - col_2->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3; - col_2->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3; - col_3->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3; - col_3->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3; - col_3->b = (BYTE)wrd; - col_3->a = 0xff; - - } - else - { - // Three-color block: derive the other color. - // 00 = color_0, 01 = color_1, 10 = color_2, - // 11 = transparent. - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - - // explicit for each component, unlike some refrasts... - - // Tracef("block has alpha\n"); - wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2; - col_2->r = (BYTE)wrd; - wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2; - col_2->g = (BYTE)wrd; - wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - col_3->a = 0x00; - } -} - - - -inline void GetColorBlockColors_m3(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - // method 3 - ////////////////////////////////////////////////////// - // super-freak variable bit structure with - // Cool Math Trick (tm) - - // Do 2/3 1/3 math BEFORE bit shift on the whole DWORD - // as the fields will NEVER carry into the next - // or overflow!! =) - - Color565 * pCol; - - pCol = (Color565*) & (pBlock->col0); - - col_0->a = 0x00; // must set to 0 to avoid overflow in DWORD add - col_0->r = pCol->nRed; - col_0->g = pCol->nGreen; - col_0->b = pCol->nBlue; - - pCol = (Color565*) & (pBlock->col1); - col_1->a = 0x00; - col_1->r = pCol->nRed; - col_1->g = pCol->nGreen; - col_1->b = pCol->nBlue; - - if (pBlock->col0 > pBlock->col1) - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1))); - - *((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2); - - // now shift to appropriate precision & divide by 3. - col_2->r = ((WORD) col_2->r << 3) / (WORD)3; - col_2->g = ((WORD) col_2->g << 2) / (WORD)3; - col_2->b = ((WORD) col_2->b << 3) / (WORD)3; - - col_3->r = ((WORD) col_3->r << 3) / (WORD)3; - col_3->g = ((WORD) col_3->g << 2) / (WORD)3; - col_3->b = ((WORD) col_3->b << 3) / (WORD)3; - - col_0->a = 0xff; // now set appropriate alpha - col_1->a = 0xff; - col_2->a = 0xff; - col_3->a = 0xff; - } - else - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1))); - - // now shift to appropriate precision & divide by 2. - // << 3) / 2 == << 2 - // << 2) / 2 == << 1 - col_2->r = ((WORD) col_2->r << 2); - col_2->g = ((WORD) col_2->g << 1); - col_2->b = ((WORD) col_2->b << 2); - - col_2->a = 0xff; - - col_3->a = 0x00; // - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - } - - // now shift orig color components - col_0->r <<= 3; - col_0->g <<= 2; - col_0->b <<= 3; - - col_1->r <<= 3; - col_1->g <<= 2; - col_1->b <<= 3; -} - - -inline void GetColorBlockColors_m4(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - - // m1 color extraction from 5-6-5 - // m3 color math on DWORD before bit shift to full precision - wrd = pBlock->col0; - col_0->a = 0x00; // must set to 0 to avoid possible overflow & carry to next field in DWORD add - - // extract r,g,b bits - col_0->b = (unsigned char) wrd & 0x1f; // 0x1f = 0001 1111 to mask out upper 3 bits - wrd >>= 5; - col_0->g = (unsigned char) wrd & 0x3f; // 0x3f = 0011 1111 to mask out upper 2 bits - wrd >>= 6; - col_0->r = (unsigned char) wrd & 0x1f; - - - // same for col # 2: - wrd = pBlock->col1; - col_1->a = 0x00; // must set to 0 to avoid possible overflow in DWORD add - - // extract r,g,b bits - col_1->b = (unsigned char) wrd & 0x1f; - wrd >>= 5; - col_1->g = (unsigned char) wrd & 0x3f; - wrd >>= 6; - col_1->r = (unsigned char) wrd & 0x1f; - - if (pBlock->col0 > pBlock->col1) - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1))); - *((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2); - - // shift to appropriate precision & divide by 3. - col_2->r = ((WORD) col_2->r << 3) / (WORD)3; - col_2->g = ((WORD) col_2->g << 2) / (WORD)3; - col_2->b = ((WORD) col_2->b << 3) / (WORD)3; - - col_3->r = ((WORD) col_3->r << 3) / (WORD)3; - col_3->g = ((WORD) col_3->g << 2) / (WORD)3; - col_3->b = ((WORD) col_3->b << 3) / (WORD)3; - - col_0->a = 0xff; // set appropriate alpha - col_1->a = 0xff; - col_2->a = 0xff; - col_3->a = 0xff; - } - else - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1))); - - // shift to appropriate precision & divide by 2. - // << 3) / 2 == << 2 - // << 2) / 2 == << 1 - col_2->r = ((WORD) col_2->r << 2); - col_2->g = ((WORD) col_2->g << 1); - col_2->b = ((WORD) col_2->b << 2); - - col_2->a = 0xff; - - col_3->a = 0x00; // - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - } - - // shift orig color components to full precision - col_0->r <<= 3; - col_0->g <<= 2; - col_0->b <<= 3; - - col_1->r <<= 3; - col_1->g <<= 2; - col_1->b <<= 3; -} - - -inline void GetColorBlockColors_m1(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - - // Method 1: - // Shifty method - wrd = pBlock->col0; - col_0->a = 0xff; - - // extract r,g,b bits - col_0->b = (unsigned char) wrd; - col_0->b <<= 3; // shift to full precision - wrd >>= 5; - col_0->g = (unsigned char) wrd; - col_0->g <<= 2; // shift to full precision - wrd >>= 6; - col_0->r = (unsigned char) wrd; - col_0->r <<= 3; // shift to full precision - - // same for col # 2: - wrd = pBlock->col1; - col_1->a = 0xff; - - // extract r,g,b bits - col_1->b = (unsigned char) wrd; - col_1->b <<= 3; // shift to full precision - wrd >>= 5; - col_1->g = (unsigned char) wrd; - col_1->g <<= 2; // shift to full precision - wrd >>= 6; - col_1->r = (unsigned char) wrd; - col_1->r <<= 3; // shift to full precision - - // use this for all but the super-freak math method - if (pBlock->col0 > pBlock->col1) - { - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - - wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3; - // no +1 for rounding - // as bits have been shifted to 888 - col_2->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3; - col_2->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3; - col_3->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3; - col_3->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3; - col_3->b = (BYTE)wrd; - col_3->a = 0xff; - } - else - { - // Three-color block: derive the other color. - // 00 = color_0, 01 = color_1, 10 = color_2, - // 11 = transparent. - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - - // explicit for each component, unlike some refrasts... - - // Tracef("block has alpha\n"); - - wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2; - col_2->r = (BYTE)wrd; - wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2; - col_2->g = (BYTE)wrd; - wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - col_3->a = 0x00; - } -} // Get color block colors (...) - -void CDXTCImage::Time_Decomp5_01(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 1: bit shift, for %d times\n", ntimes); - - for (n = 0; n < ntimes; n++) - { - QueryPerformanceCounter(& info->m_start_clk); - - int xblocks, yblocks; - - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - - int i,j; - - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m1(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples ++; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - } -} - - -void CDXTCImage::Time_Decomp5_02(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 2: bit field struct, for %d times\n", ntimes); - - for (n = 0; n < ntimes; n++) - { - QueryPerformanceCounter(& info->m_start_clk); - - int xblocks, yblocks; - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - int i,j; - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m2(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples ++; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - } -} - -void CDXTCImage::Time_Decomp5_03(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 3: bit field struct w/ pre-shift math, for %d times\n", ntimes); - - for (n = 0; n < ntimes; n++) - { - QueryPerformanceCounter(& info->m_start_clk); - - int xblocks, yblocks; - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - int i,j; - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m3(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples ++; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - } -} - - -void CDXTCImage::Time_Decomp5_04(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 4: shift extract w/ pre-shift math, for %d times\n", ntimes); - - QueryPerformanceCounter(& info->m_start_clk); - - for (n = 0; n < ntimes; n++) - { - int xblocks, yblocks; - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - int i,j; - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m4(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples = ntimes; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - -} -*/ diff --git a/src/EterImageLib/DXTCImage.h b/src/EterImageLib/DXTCImage.h index 7337fd55..996f6c05 100644 --- a/src/EterImageLib/DXTCImage.h +++ b/src/EterImageLib/DXTCImage.h @@ -114,9 +114,7 @@ class CDXTCImage XDDPIXELFORMAT m_xddPixelFormat; - bool LoadFromFile(const char * filename); // true if success - bool LoadFromMemory(const BYTE * c_pbMap); - bool LoadHeaderFromMemory(const BYTE * c_pbMap); + bool LoadHeaderFromMemory(const BYTE * c_pbMap, int iSize); bool Copy(int miplevel, BYTE * pbDest, long lDestPitch); void Decompress(int miplevel, DWORD * pdwDest); @@ -128,16 +126,6 @@ class CDXTCImage VOID DecodePixelFormat(CHAR* strPixelFormat, XDDPIXELFORMAT* pddpf); void Unextract(BYTE * pbDest, int iWidth, int iHeight, int iPitch); - /* - struct TimingInfo; // defined in Image_DXTC.cpp - void RunTimingSession(); // run a few methods & time the code - - // must use dxt5 texture - void Time_Decomp5_01(int ntimes, TimingInfo * info); - void Time_Decomp5_02(int ntimes, TimingInfo * info); - void Time_Decomp5_03(int ntimes, TimingInfo * info); - void Time_Decomp5_04(int ntimes, TimingInfo * info); - */ }; #endif // #ifndef AFX_IMAGE_DXTC_H__4B89D8D0_7857_11D4_9630_00A0C996DE3D__INCLUDED_ diff --git a/src/EterLib/GrpImageTexture.cpp b/src/EterLib/GrpImageTexture.cpp index 95d72397..e63432fb 100644 --- a/src/EterLib/GrpImageTexture.cpp +++ b/src/EterLib/GrpImageTexture.cpp @@ -209,7 +209,8 @@ bool CGraphicImageTexture::CreateFromMemoryFile(UINT bufSize, const void * c_pvB static CDXTCImage image; - if (image.LoadHeaderFromMemory((const BYTE *) c_pvBuf)) // DDSÀΰ¡ È®ÀÎ + // Check whether the file is a DDS + if (image.LoadHeaderFromMemory((const BYTE *) c_pvBuf, bufSize)) { return (CreateDDSTexture(image, (const BYTE *) c_pvBuf)); }