MissionEditorPackLib.cpp 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269
  1. /*
  2. FinalSun/FinalAlert 2 Mission Editor
  3. Copyright (C) 1999-2024 Electronic Arts, Inc.
  4. Authored by Matthias Wagner
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. */
  16. #define _HAS_STD_BYTE 0 // see https://developercommunity.visualstudio.com/t/error-c2872-byte-ambiguous-symbol/93889
  17. struct IUnknown;
  18. #include "MissionEditorPackLib.h"
  19. #include <map>
  20. #include <vector>
  21. #include "mix_file.h"
  22. #include "cc_file.h"
  23. #include "xcc_dirs.h"
  24. #include "shp_ts_file.h"
  25. #include "tmp_ts_file.h"
  26. #include "cc_file.h"
  27. #include "pal_file.h"
  28. #include "shp_ts_file.h"
  29. #include "tmp_ts_file.h"
  30. #include <shp_decode.h>
  31. #include <mix_file.h>
  32. #include <ddpf_conversion.h>
  33. #include <vxl_file.h>
  34. #include <math.h>
  35. #include <hva_file.h>
  36. #include "mix_file_write.h"
  37. #include <locale>
  38. #include <windows.h>
  39. #include <windowsx.h>
  40. #include <ddraw.h>
  41. #include <commctrl.h>
  42. #include <regex>
  43. #include "VoxelNormals.h"
  44. Cmix_file mixfiles[2000];
  45. std::string mixfiles_names[2000];
  46. Cshp_ts_file cur_shp; // for now only support one shp at once
  47. Ctmp_ts_file cur_tmp;
  48. DWORD dwMixFileCount = 0;
  49. t_palet ts_palettes[256];
  50. DWORD dwPalCount = 0;
  51. DWORD conv_color[256][256];
  52. DWORD transp_conv_color[256];
  53. DDPIXELFORMAT cur_pf[256];
  54. BOOL bFirstConv[256];
  55. HBRUSH hTranspBrush = (HBRUSH)INVALID_HANDLE_VALUE;
  56. HPEN hTranspPen = (HPEN)INVALID_HANDLE_VALUE;
  57. #define MYASSERT(a,b) if(!a){ FSunPackLib::FSPL_EXCEPTION e; e.err_code=b; throw(e); }
  58. __forceinline void CreateConvLookUpTable(DDPIXELFORMAT& pf, HTSPALETTE hPalette)
  59. {
  60. /*fstream f;
  61. f.open("c:\\convtable.log", ios_base::out | ios_base::trunc );
  62. f << "CreateConvLookUpTable() called" << endl;
  63. f.flush();*/
  64. if (memcmp(&pf, &cur_pf[hPalette - 1], sizeof(DDPIXELFORMAT)) || bFirstConv[hPalette - 1])
  65. {
  66. bFirstConv[hPalette - 1] = FALSE;
  67. cur_pf[hPalette - 1] = pf;
  68. /*f << "Setting Conversion" << endl;
  69. f.flush();*/
  70. Cddpf_conversion conv;
  71. conv.set_pf(pf);
  72. /*f << "Calculating colors" << endl;
  73. f.flush();*/
  74. int i;
  75. for (i = 0;i < 256;i++)
  76. {
  77. conv_color[hPalette - 1][i] = conv.get_color(ts_palettes[hPalette - 1][i].r, ts_palettes[hPalette - 1][i].g, ts_palettes[hPalette - 1][i].b);
  78. }
  79. transp_conv_color[hPalette - 1] = conv.get_color(245, 245, 245);
  80. }
  81. }
  82. namespace FSunPackLib
  83. {
  84. std::wstring utf8ToUtf16(const std::string& utf8)
  85. {
  86. // wstring_convert and codecvt_utf8_utf16 are deprecated in C++17, fallback to Win32
  87. if (utf8.size() == 0)
  88. // MultiByteToWideChar does not support passing in cbMultiByte == 0
  89. return L"";
  90. // unterminatedCountWChars will be the count of WChars NOT including the terminating zero (due to passing in utf8.size() instead of -1)
  91. auto utf8Count = utf8.size();
  92. auto unterminatedCountWChars = MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, nullptr, 0);
  93. if (unterminatedCountWChars == 0)
  94. {
  95. throw std::runtime_error("UTF8 -> UTF16 conversion failed");
  96. }
  97. std::wstring utf16;
  98. utf16.resize(unterminatedCountWChars);
  99. if (MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, utf8.data(), utf8Count, utf16.data(), unterminatedCountWChars) == 0)
  100. {
  101. throw std::runtime_error("UTF8 -> UTF16 conversion failed");
  102. }
  103. return utf16;
  104. }
  105. // XCC uses CreateFileA to load files which does not support UTF8 filenames if you don't opt in through the app manifest (and that's only possible on Win10 1903+)
  106. // so provide some helpers that open the file through Cwin_handle with CreateFileW instead:
  107. template<class F>
  108. int open_write(F& file, const std::string& u8FilePath)
  109. {
  110. try
  111. {
  112. auto u16FilePath = utf8ToUtf16(u8FilePath);
  113. Cwin_handle target_file_handle(CreateFileW(u16FilePath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
  114. if (target_file_handle)
  115. return file.open(target_file_handle);
  116. }
  117. catch (std::runtime_error)
  118. {
  119. return 2;
  120. }
  121. return 1;
  122. }
  123. template<class F>
  124. int open_read(F& file, const std::string& u8FilePath)
  125. {
  126. try
  127. {
  128. auto u16FilePath = utf8ToUtf16(u8FilePath);
  129. Cwin_handle target_file_handle(CreateFileW(u16FilePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
  130. if (target_file_handle)
  131. return file.open(target_file_handle);
  132. }
  133. catch (std::runtime_error)
  134. {
  135. return 2;
  136. }
  137. return 1;
  138. }
  139. extern "C" bool _DEBUG_EnableLogs = 0; // only useable in debug library builds
  140. extern "C" bool _DEBUG_EnableBreakpoints = 0; // only useable in debug library builds
  141. extern "C" int last_succeeded_operation = 0;
  142. BYTE* EncodeBase64(BYTE* sp, UINT len)
  143. {
  144. auto encoded = encode64(data_ref(sp, std::size_t(len)));
  145. // for now make a copy, we might refactor this
  146. auto copy = new BYTE[encoded.size() + 1];
  147. copy[encoded.size()] = 0; // null terminate
  148. memcpy(copy, encoded.data(), encoded.size());
  149. return copy;
  150. }
  151. // dest should be at least as large as sp
  152. INT ConvertToF80(BYTE* sp, UINT len, BYTE* dest)
  153. {
  154. return encode80(sp, dest, len);
  155. }
  156. INT EncodeF80(BYTE* sp, UINT len, UINT nSections, BYTE** dest)
  157. {
  158. *dest = new(BYTE[len * 4]); // as large as sp, to make sure it works
  159. BYTE* data = *dest;
  160. int length = len / nSections;
  161. // each section has this length
  162. #ifdef DBG2
  163. int sections = 0;
  164. AllocConsole();
  165. HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  166. HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
  167. char tmp[50];
  168. string out;
  169. out = "PackData() called\n------------\n\n";
  170. DWORD dw;
  171. WriteFile(hOut, out.data(), out.size(), &dw, NULL);
  172. #endif
  173. UINT i;
  174. UINT DP = 0;
  175. UINT SP = 0;
  176. for (i = 0;i < nSections;i++)
  177. {
  178. UINT packLen = encode80(&sp[SP], &data[DP + 4], length); //ConvertToF80(&sp[SP], length, &data[DP+4]);
  179. memcpy(&data[DP], &packLen, 3);
  180. DP += 3;
  181. data[DP] = 0x20;
  182. DP++;
  183. SP += length;
  184. DP += packLen;
  185. #ifdef DBG2
  186. itoa(i, tmp, 10);
  187. out = "\nHandled section ";
  188. out += tmp;
  189. out += ", packed length: ";
  190. itoa(packLen, tmp, 10);
  191. out += tmp;
  192. out += " bytes, DP=";
  193. itoa(DP, tmp, 10);
  194. out += tmp;
  195. out += "\n";
  196. WriteFile(hOut, out.data(), out.size(), &dw, NULL);
  197. ReadFile(hIn, tmp, 2, &dw, NULL);
  198. #endif
  199. }
  200. return DP;
  201. }
  202. UINT EncodeIsoMapPack5(BYTE* sp, UINT SourceLength, BYTE** dp)
  203. {
  204. *dp = new(BYTE[SourceLength * 2]); // as big as source, makes sure it works!
  205. UINT DP = encode5(sp, *dp, SourceLength, 5);
  206. return DP;
  207. }
  208. bool DecodeF80(const BYTE* const sp, const UINT SourceLength, std::vector<BYTE>& dp, const std::size_t max_size)
  209. {
  210. static_assert(4 == sizeof(t_pack_section_header));
  211. const auto spEnd = sp + SourceLength;
  212. const t_pack_section_header* secHeader = nullptr;
  213. size_t totalSize = 0;
  214. for (auto curSP = sp; curSP < sp + SourceLength;)
  215. {
  216. secHeader = (reinterpret_cast<const t_pack_section_header*>(curSP));
  217. curSP += secHeader->size_in + sizeof(t_pack_section_header);
  218. totalSize += secHeader->size_out;
  219. }
  220. if (totalSize > max_size)
  221. {
  222. return false;
  223. }
  224. dp.resize(totalSize);
  225. decode5(sp, dp.data(), SourceLength, 80);
  226. return true;
  227. }
  228. int DecodeBase64(const char* sp, std::vector<BYTE>& dest)
  229. {
  230. auto len = strlen(reinterpret_cast<const char*>(sp));
  231. auto res = decode64(data_ref(sp, len));
  232. dest.assign(res.data(), res.data() + res.size());
  233. return res.size();
  234. }
  235. UINT DecodeIsoMapPack5(BYTE* sp, UINT SourceLength, BYTE* dp, HWND hProgressBar, BOOL bDebugMode)
  236. {
  237. //if(bDebugMode) k.open("c:\\decode.txt", ios_base::out | ios_base::trunc);
  238. //if(hProgressBar) SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, SourceLength));
  239. //if(hProgressBar) UpdateWindow(hProgressBar);
  240. UINT SP = 0;
  241. UINT DP = 0;
  242. while (SP < SourceLength)
  243. {
  244. WORD wSrcSize;
  245. WORD wExtrSize;
  246. memcpy(&wSrcSize, sp + SP, 2);
  247. SP += 2;
  248. memcpy(&wExtrSize, sp + SP, 2);
  249. SP += 2;
  250. decode5s(sp + SP, dp + DP, wSrcSize);
  251. SP += wSrcSize;
  252. DP += wExtrSize;
  253. //if(hProgressBar) SendMessage(hProgressBar, PBM_SETPOS, (WPARAM) SP, 0);
  254. //if(hProgressBar) UpdateWindow(hProgressBar);
  255. }
  256. return DP;
  257. }
  258. std::int32_t GetFirstPixelColor(IDirectDrawSurface4* pDDS)
  259. {
  260. std::int32_t color = 0;
  261. DDSURFACEDESC2 desc = { 0 };
  262. desc.dwSize = sizeof(DDSURFACEDESC2);
  263. if (pDDS->Lock(nullptr, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, nullptr) != DD_OK)
  264. return color;
  265. if (desc.lpSurface == nullptr)
  266. {
  267. pDDS->Unlock(nullptr);
  268. return color;
  269. }
  270. else
  271. {
  272. auto bytes_per_pixel = (desc.ddpfPixelFormat.dwRGBBitCount + 7) / 8;
  273. memcpy(&color, desc.lpSurface, bytes_per_pixel > 4 ? 4 : bytes_per_pixel);
  274. pDDS->Unlock(nullptr);
  275. return color;
  276. }
  277. }
  278. HRESULT SetColorKey(IDirectDrawSurface4* pDDS, COLORREF rgb)
  279. {
  280. DDPIXELFORMAT pf = { 0 };
  281. pf.dwSize = sizeof(DDPIXELFORMAT);
  282. pDDS->GetPixelFormat(&pf);
  283. ColorConverter c(pf);
  284. auto col = rgb == CLR_INVALID ? GetFirstPixelColor(pDDS) : c.GetColor(rgb);
  285. DDCOLORKEY color_key = { static_cast<DWORD>(col), static_cast<DWORD>(col) };
  286. return pDDS->SetColorKey(DDCKEY_SRCBLT, &color_key);
  287. }
  288. BOOL XCC_Initialize(BOOL bLoadFromRegistry)
  289. {
  290. if (bLoadFromRegistry)
  291. xcc_dirs::load_from_registry();
  292. return TRUE;
  293. }
  294. HMIXFILE XCC_OpenMix(LPCTSTR szMixFile, HMIXFILE hOwner)
  295. {
  296. DWORD i, d = 0xFFFFFFFF;
  297. for (i = 0;i <= dwMixFileCount && i < 2000;i++)
  298. {
  299. if (mixfiles[i].is_open() == false)
  300. {
  301. d = i;
  302. break;
  303. }
  304. }
  305. if (d == 0xFFFFFFFF)
  306. return NULL;
  307. std::string sMixFile = szMixFile;
  308. if (hOwner == NULL)
  309. {
  310. if (open_read(mixfiles[d], sMixFile))
  311. return NULL;
  312. //mixfiles[dwMixFileCount].enable_mix_expansion();
  313. mixfiles_names[d] = szMixFile;
  314. if (d == dwMixFileCount)
  315. dwMixFileCount++;
  316. return d + 1;//dwMixFileCount;
  317. }
  318. else if (hOwner > 0 && (hOwner - 1) < dwMixFileCount)
  319. {
  320. if (szMixFile[0] == L'_' && szMixFile[1] == L'I' && szMixFile[2] == L'D')
  321. {
  322. char id[256];
  323. strcpy_s(id, &sMixFile[3]);
  324. int iId = atoi(id);
  325. if (mixfiles[d].open(iId, mixfiles[hOwner - 1])) return NULL;
  326. }
  327. else
  328. {
  329. if (mixfiles[d].open(sMixFile, mixfiles[hOwner - 1]))
  330. return NULL;
  331. }
  332. mixfiles_names[d] = szMixFile;
  333. if (d == dwMixFileCount)
  334. dwMixFileCount++;
  335. return d + 1;
  336. }
  337. return NULL;
  338. }
  339. BOOL XCC_GetMixName(HMIXFILE hOwner, std::string& sMixFile)
  340. {
  341. if (hOwner == 0)
  342. return FALSE;
  343. if (hOwner > dwMixFileCount)
  344. return FALSE;
  345. sMixFile = mixfiles_names[hOwner - 1];
  346. return TRUE;
  347. }
  348. BOOL XCC_DoesFileExist(LPCSTR szFile, HMIXFILE hOwner)
  349. {
  350. if (hOwner == 0)
  351. return FALSE;
  352. if (hOwner > dwMixFileCount)
  353. return FALSE;
  354. t_game game = mixfiles[hOwner - 1].get_game();
  355. int id = mixfiles[hOwner - 1].get_id(game, szFile);
  356. if (mixfiles[hOwner - 1].get_index(id) < 0)
  357. return FALSE;
  358. return TRUE;
  359. }
  360. BOOL XCC_CloseMix(HMIXFILE hMixFile)
  361. {
  362. if (hMixFile<1 || hMixFile>dwMixFileCount)
  363. return FALSE;
  364. hMixFile--; // -1 to make it to an array index
  365. mixfiles_names[hMixFile].clear();
  366. if (mixfiles[hMixFile].is_open()) mixfiles[hMixFile].close();
  367. else
  368. return FALSE;
  369. return TRUE;
  370. }
  371. BOOL XCC_ExtractFile(const std::string& szFilename, const std::string& szSaveTo, HMIXFILE hOwner)
  372. {
  373. if (hOwner == NULL)
  374. return FALSE; // not supported yet
  375. hOwner--; // -1 to make it to an array index
  376. if (hOwner >= dwMixFileCount)
  377. return FALSE;
  378. if (!mixfiles[hOwner].is_open())
  379. return FALSE;
  380. Ccc_file file(true);
  381. if (szFilename[0] == '_' && szFilename[1] == 'I' && szFilename[2] == 'D')
  382. {
  383. char id[256];
  384. strcpy_s(id, &szFilename[3]);
  385. int iId = atoi(id);
  386. if (file.open(iId, mixfiles[hOwner]))
  387. return NULL;
  388. }
  389. else
  390. {
  391. if (file.open(szFilename, mixfiles[hOwner]) != 0)
  392. return FALSE;
  393. }
  394. Cfile32 target_file;
  395. if (open_write(target_file, szSaveTo))
  396. return FALSE;
  397. const int bufferSize = static_cast<int>(min(file.get_size(), 1024 * 1024));
  398. std::vector<byte> buffer(bufferSize);
  399. for (auto p = 0; p < file.get_size();)
  400. {
  401. const auto toRead = static_cast<int>(min(file.get_size() - p, bufferSize));
  402. if (file.read(buffer.data(), toRead))
  403. return FALSE;
  404. if (target_file.write(buffer.data(), toRead))
  405. return FALSE;
  406. p += toRead;
  407. }
  408. return TRUE;
  409. }
  410. BOOL XCC_ExtractFile(LPCSTR szFilename, LPCSTR szSaveTo, HMIXFILE hOwner)
  411. {
  412. return XCC_ExtractFile(std::string(szFilename), std::string(szSaveTo), hOwner);
  413. }
  414. BOOL XCC_GetSHPHeader(SHPHEADER* pHeader)
  415. {
  416. if (pHeader == NULL)
  417. return FALSE;
  418. if (!cur_shp.is_open())
  419. return FALSE;
  420. auto& head = cur_shp.header();
  421. memcpy(pHeader, &head, sizeof(SHPHEADER));
  422. return TRUE;
  423. }
  424. /*
  425. Returns the SHP image header of a image in a SHP file
  426. */
  427. BOOL XCC_GetSHPImageHeader(int iImageIndex, SHPIMAGEHEADER* pImageHeader)
  428. {
  429. t_shp_ts_image_header imagehead;
  430. if (pImageHeader == NULL || iImageIndex < 0)
  431. return FALSE;
  432. if (!cur_shp.is_open())
  433. return FALSE;
  434. auto& head = cur_shp.header();
  435. if (iImageIndex >= head.c_images)
  436. return FALSE;
  437. imagehead = *cur_shp.get_image_header(iImageIndex);
  438. memcpy(pImageHeader, &imagehead, sizeof(SHPIMAGEHEADER));
  439. return TRUE;
  440. }
  441. BOOL SetCurrentTMP(LPCSTR szTMP, HMIXFILE hOwner)
  442. {
  443. if (cur_tmp.is_open())
  444. cur_tmp.close();
  445. if (hOwner == NULL)
  446. {
  447. if (open_read(cur_tmp, szTMP))
  448. return FALSE;
  449. }
  450. else
  451. {
  452. if (cur_tmp.open(szTMP, mixfiles[hOwner - 1]))
  453. return FALSE;
  454. }
  455. //if(cur_tmp.get_data()==NULL) return FALSE;
  456. //if(!cur_tmp.is_valid()) return FALSE;
  457. return TRUE;
  458. };
  459. BOOL SetCurrentSHP(LPCSTR szSHP, HMIXFILE hOwner)
  460. {
  461. if (cur_shp.is_open()) cur_shp.close();
  462. if (hOwner == NULL)
  463. {
  464. if (open_read(cur_shp, szSHP) != 0)
  465. {
  466. return FALSE;
  467. }
  468. }
  469. else
  470. {
  471. int id = mixfiles[hOwner - 1].get_id(mixfiles[hOwner - 1].get_game(), szSHP);
  472. int size = mixfiles[hOwner - 1].get_size(id);
  473. if (size == 0)
  474. OutputDebugString("NULL size");
  475. BYTE* b = new(BYTE[size]);
  476. mixfiles[hOwner - 1].seek(mixfiles[hOwner - 1].get_offset(id));
  477. mixfiles[hOwner - 1].read(b, size);
  478. cur_shp.load(Cvirtual_binary(b, size));
  479. }
  480. return TRUE;
  481. };
  482. BOOL XCC_GetTMPTileInfo(int iTile, POINT* lpPos, int* lpWidth, int* lpHeight, BYTE* lpDirection, BYTE* lpTileHeight, BYTE* lpTileType, RGBTRIPLE* lpRgbLeft, RGBTRIPLE* lpRgbRight)
  483. {
  484. if (!cur_tmp.is_open()) return FALSE;
  485. if (iTile >= cur_tmp.get_c_tiles() || iTile < 0) return FALSE;
  486. t_tmp_image_header ihead = *cur_tmp.get_image_header(iTile);
  487. if (lpDirection)
  488. *lpDirection = ihead.ramp_type;
  489. if (lpTileHeight)
  490. *lpTileHeight = ihead.height;
  491. if (lpTileType)
  492. *lpTileType = ihead.terrain_type;
  493. if (lpRgbLeft)
  494. {
  495. lpRgbLeft->rgbtRed = ihead.radar_red_left;
  496. lpRgbLeft->rgbtGreen = ihead.radar_green_left;
  497. lpRgbLeft->rgbtBlue = ihead.radar_blue_left;
  498. }
  499. if (lpRgbRight)
  500. {
  501. lpRgbRight->rgbtRed = ihead.radar_red_right;
  502. lpRgbRight->rgbtGreen = ihead.radar_green_right;
  503. lpRgbRight->rgbtBlue = ihead.radar_blue_right;
  504. }
  505. int cx = cur_tmp.get_cx();
  506. int cy = cur_tmp.get_cy();
  507. if (cur_tmp.has_extra_graphics(iTile))
  508. {
  509. int cy_extra = cur_tmp.get_cy_extra(iTile);
  510. int y_extra = cur_tmp.get_y_extra(iTile) - cur_tmp.get_y(iTile);
  511. int cx_extra = cur_tmp.get_cx_extra(iTile);
  512. int x_extra = cur_tmp.get_x_extra(iTile) - cur_tmp.get_x(iTile);
  513. int y_added = 0;//cur_tmp.get_x(iTile);
  514. int x_added = 0;//cur_tmp.get_y(iTile);
  515. if (y_extra < 0)
  516. {
  517. y_added -= y_extra;
  518. cy -= y_extra;
  519. y_extra = 0;
  520. }
  521. if (x_extra < 0)
  522. {
  523. x_added -= x_extra;
  524. cx -= x_extra;
  525. x_extra = 0;
  526. }
  527. if (cy_extra + y_extra > cy) cy = cy_extra + y_extra;
  528. if (cx_extra + x_extra > cx) cx = cx_extra + x_extra;
  529. if (lpPos != NULL)
  530. {
  531. //int xTile, yTile;
  532. //xTile=iTile%cur_tmp.get_cblocks_x();
  533. //yTile=iTile/cur_tmp.get_cblocks_x();
  534. //lpPos->x=-x_added;
  535. //lpPos->y=-y_added;
  536. lpPos->x =/*cur_tmp.get_x(iTile)-(24*xTile-24*yTile)*/-x_added;
  537. lpPos->y =/*cur_tmp.get_y(iTile)-(12*yTile+12*xTile)*/-y_added;
  538. }
  539. if (lpWidth != NULL) *lpWidth = cx;
  540. if (lpHeight != NULL) *lpHeight = cy;
  541. }
  542. else
  543. {
  544. if (lpPos != NULL)
  545. {
  546. lpPos->x = 0;//cur_tmp.get_x(iTile);;
  547. lpPos->y = 0;//cur_tmp.get_y(iTile);
  548. }
  549. if (lpHeight != NULL) *lpHeight = cur_tmp.get_cy();
  550. if (lpWidth != NULL) *lpWidth = cur_tmp.get_cx();
  551. }
  552. return TRUE;
  553. }
  554. BOOL XCC_GetTMPInfo(RECT* lpRect, int* iTileCount, int* iTilesX, int* iTilesY)
  555. {
  556. // if(!cur_tmp.is_open()) return FALSE;
  557. int x, y, cx, cy;
  558. cur_tmp.get_rect(x, y, cx, cy);
  559. if (lpRect != NULL)
  560. {
  561. lpRect->left = x;
  562. lpRect->top = y;
  563. lpRect->right = x + cx;
  564. lpRect->bottom = y + cy;
  565. }
  566. if (iTileCount != NULL) *iTileCount = cur_tmp.get_c_tiles();
  567. if (iTilesX != NULL) *iTilesX = cur_tmp.get_cblocks_y();
  568. if (iTilesY != NULL) *iTilesY = cur_tmp.get_cblocks_x();
  569. return TRUE;
  570. }
  571. BOOL LoadSHPImageInSurface(IDirectDraw4* pdd, HTSPALETTE hPalette, int iImageIndex, int iCount, LPDIRECTDRAWSURFACE4* pdds)
  572. {
  573. RGBTRIPLE rgb_transp;
  574. t_shp_ts_image_header imghead;
  575. DDSURFACEDESC2 ddsd;
  576. BYTE* image;
  577. if (hPalette == NULL || hPalette > dwPalCount) return NULL;
  578. auto& head = cur_shp.header();
  579. if (head.cx == 0 || head.cy == 0)
  580. {
  581. return FALSE;
  582. }
  583. rgb_transp.rgbtRed = 245;
  584. rgb_transp.rgbtGreen = 245;
  585. rgb_transp.rgbtBlue = 245;
  586. int pic;
  587. std::vector<byte> decode_image_buffer;
  588. for (pic = 0;pic < iCount;pic++)
  589. {
  590. if (cur_shp.get_image_header(iImageIndex + pic))
  591. {
  592. imghead = *(cur_shp.get_image_header(iImageIndex + pic));
  593. // if(imghead.offset!=0)
  594. {
  595. ZeroMemory(&ddsd, sizeof(ddsd));
  596. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  597. ddsd.dwWidth = head.cx;
  598. ddsd.dwHeight = head.cy;
  599. ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH /*| DDSD_PIXELFORMAT*/;
  600. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  601. if (pdd->CreateSurface(&ddsd, &pdds[pic], NULL) != DD_OK)
  602. return NULL;
  603. ddsd.dwFlags = DDSD_PITCH;
  604. pdds[pic]->GetSurfaceDesc(&ddsd);
  605. long pitch = ddsd.lPitch;
  606. DDPIXELFORMAT pf;
  607. memset(&pf, 0, sizeof(DDPIXELFORMAT));
  608. pf.dwSize = sizeof(DDPIXELFORMAT);
  609. pdds[pic]->GetPixelFormat(&pf);
  610. if (cur_shp.is_compressed(iImageIndex + pic))
  611. {
  612. decode_image_buffer.resize(imghead.cx * imghead.cy);
  613. image = decode_image_buffer.data();
  614. decode3(cur_shp.get_image(iImageIndex + pic), image, imghead.cx, imghead.cy);
  615. }
  616. else
  617. image = (unsigned char*)cur_shp.get_image(iImageIndex + pic);
  618. if ((pf.dwFlags & DDPF_RGB) && pf.dwRBitMask && pf.dwGBitMask && pf.dwBBitMask)
  619. {
  620. CreateConvLookUpTable(pf, hPalette);
  621. if (pdds[pic]->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) == DD_OK)
  622. {
  623. BYTE* dest = (BYTE*)ddsd.lpSurface;
  624. pitch = ddsd.lPitch;
  625. int bytesize = (pf.dwRGBBitCount + 1) / 8;
  626. if (bytesize < 1) bytesize = 1;
  627. if (pf.dwRGBBitCount <= 8) bytesize = 1;
  628. else if (pf.dwRGBBitCount <= 16) bytesize = 2;
  629. else if (pf.dwRGBBitCount <= 24) bytesize = 3;
  630. else if (pf.dwRGBBitCount <= 32) bytesize = 4;
  631. if (dest)
  632. {
  633. int i, e;
  634. for (i = 0; i < head.cx; i++)
  635. {
  636. for (e = 0;e < head.cy;e++)
  637. {
  638. DWORD dwRead = 0xFFFFFFFF;
  639. DWORD dwWrite = i * bytesize + e * pitch;
  640. if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy)
  641. dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx;
  642. if (dwRead != 0xFFFFFFFF && image[dwRead] != 0)
  643. {
  644. DWORD col = conv_color[hPalette - 1][image[dwRead]];
  645. memcpy(&dest[dwWrite], &col, bytesize);
  646. }
  647. else
  648. {
  649. DWORD col = transp_conv_color[hPalette - 1];
  650. memcpy(&dest[dwWrite], &col, bytesize);
  651. }
  652. }
  653. }
  654. }
  655. pdds[pic]->Unlock(NULL);
  656. }
  657. }
  658. else
  659. {
  660. HDC hDC;
  661. while (pdds[pic]->GetDC(&hDC) == DDERR_WASSTILLDRAWING);
  662. {
  663. int i, e;
  664. for (i = 0; i < head.cx; i++)
  665. {
  666. for (e = 0;e < head.cy;e++)
  667. {
  668. DWORD dwRead = 0xFFFFFFFF;
  669. //DWORD dwWrite=i*bytesize+e*pitch;
  670. if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy)
  671. dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx;
  672. if (dwRead != 0xFFFFFFFF && image[dwRead] != 0)
  673. {
  674. t_palet_entry& p = ts_palettes[hPalette - 1][image[dwRead]];
  675. SetPixel(hDC, i, e, RGB(p.r, p.g, p.b));
  676. }
  677. else
  678. {
  679. SetPixel(hDC, i, e, RGB(245, 245, 245));
  680. }
  681. }
  682. }
  683. }
  684. pdds[pic]->ReleaseDC(hDC);
  685. }
  686. SetColorKey(pdds[pic], -1);
  687. }
  688. }
  689. }
  690. return TRUE;
  691. }
  692. BOOL LoadSHPImage(int iImageIndex, std::vector<BYTE>& pic)
  693. {
  694. t_shp_ts_image_header imghead;
  695. BYTE* image = NULL;
  696. auto& head = cur_shp.header();
  697. if (head.cx == 0 || head.cy == 0)
  698. {
  699. return FALSE;
  700. }
  701. std::vector<byte> decode_image_buffer;
  702. if (cur_shp.get_image_header(iImageIndex))
  703. {
  704. imghead = *(cur_shp.get_image_header(iImageIndex));
  705. // if(imghead.offset!=0)
  706. {
  707. if (cur_shp.is_compressed(iImageIndex))
  708. {
  709. decode_image_buffer.resize(imghead.cx * imghead.cy);
  710. image = decode_image_buffer.data();
  711. decode3(cur_shp.get_image(iImageIndex), image, imghead.cx, imghead.cy);
  712. }
  713. else
  714. image = (unsigned char*)cur_shp.get_image(iImageIndex);
  715. pic.resize(head.cx * head.cy);
  716. int i, e;
  717. for (i = 0; i < head.cx; i++)
  718. {
  719. for (e = 0;e < head.cy;e++)
  720. {
  721. DWORD dwRead = 0xFFFFFFFF;
  722. DWORD dwWrite = i + e * head.cx;
  723. if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy)
  724. dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx;
  725. if (dwRead != 0xFFFFFFFF)
  726. {
  727. pic[dwWrite] = image[dwRead];
  728. }
  729. else
  730. pic[dwWrite] = 0;
  731. }
  732. }
  733. }
  734. }
  735. return TRUE;
  736. }
  737. BOOL LoadSHPImage(int iImageIndex, int iCount, BYTE** lpPics)
  738. {
  739. t_shp_ts_image_header imghead;
  740. BYTE* image = NULL;
  741. auto& head = cur_shp.header();
  742. if (head.cx == 0 || head.cy == 0)
  743. {
  744. return FALSE;
  745. }
  746. int pic;
  747. std::vector<byte> decode_image_buffer;
  748. for (pic = 0;pic < iCount;pic++)
  749. {
  750. if (cur_shp.get_image_header(iImageIndex + pic))
  751. {
  752. imghead = *(cur_shp.get_image_header(iImageIndex + pic));
  753. // if(imghead.offset!=0)
  754. {
  755. if (cur_shp.is_compressed(iImageIndex + pic))
  756. {
  757. decode_image_buffer.resize(imghead.cx * imghead.cy);
  758. image = decode_image_buffer.data();
  759. decode3(cur_shp.get_image(iImageIndex + pic), image, imghead.cx, imghead.cy);
  760. }
  761. else
  762. image = (unsigned char*)cur_shp.get_image(iImageIndex + pic);
  763. lpPics[pic] = new(BYTE[head.cx * head.cy]);
  764. int i, e;
  765. for (i = 0; i < head.cx; i++)
  766. {
  767. for (e = 0;e < head.cy;e++)
  768. {
  769. DWORD dwRead = 0xFFFFFFFF;
  770. DWORD dwWrite = i + e * head.cx;
  771. if (i >= imghead.x && e >= imghead.y && i < imghead.x + imghead.cx && e < imghead.y + imghead.cy)
  772. dwRead = (i - imghead.x) + (e - imghead.y) * imghead.cx;
  773. if (dwRead != 0xFFFFFFFF)
  774. {
  775. lpPics[pic][dwWrite] = image[dwRead];
  776. }
  777. else
  778. lpPics[pic][dwWrite] = 0;
  779. }
  780. }
  781. }
  782. }
  783. }
  784. return TRUE;
  785. }
  786. void tmp_ts_draw(Ctmp_ts_file& f, byte* d, int i)
  787. {
  788. int tile_cx, tile_cy;
  789. int skip_x;
  790. int skip_y;
  791. tile_cx = f.get_cx();
  792. tile_cy = f.get_cy();
  793. int std_cx = tile_cx;
  794. int std_cy = tile_cy;
  795. int cy_extra = 0;
  796. int y_extra = 0;
  797. int cx_extra = 0;
  798. int x_extra = 0;
  799. int y_added = 0;
  800. int x_added = 0;
  801. if (f.has_extra_graphics(i))
  802. {
  803. cy_extra = f.get_cy_extra(i);
  804. y_extra = f.get_y_extra(i) - f.get_y(i);
  805. cx_extra = f.get_cx_extra(i);
  806. x_extra = f.get_x_extra(i) - f.get_x(i);
  807. if (y_extra < 0)
  808. {
  809. y_added = -y_extra;
  810. tile_cy -= y_extra;
  811. y_extra = 0;
  812. }
  813. if (x_extra < 0)
  814. {
  815. x_added = -x_extra;
  816. tile_cx -= x_extra;
  817. x_extra = 0;
  818. }
  819. if (cy_extra + y_extra > tile_cy) tile_cy = cy_extra + y_extra;
  820. if (cx_extra + x_extra > tile_cx) tile_cx = cx_extra + x_extra;
  821. }
  822. memset(d, 0, tile_cx * tile_cy);
  823. const byte* r = f.get_image(i);
  824. byte* w_line = d;
  825. if (f.has_extra_graphics(i))
  826. w_line = d + tile_cx * y_added + x_added;
  827. int x = f.header().cx / 2;
  828. int cx = 0;
  829. int y;
  830. for (y = 0; y < f.header().cy / 2; y++)
  831. {
  832. cx += 4;
  833. x -= 2;
  834. if (w_line + x < d + tile_cx * tile_cy)
  835. memcpy(w_line + x, r, cx);
  836. r += cx;
  837. w_line += tile_cx;
  838. }
  839. for (; y < f.header().cy - 1; y++)
  840. {
  841. cx -= 4;
  842. x += 2;
  843. if (w_line + x < d + tile_cx * tile_cy)
  844. memcpy(w_line + x, r, cx);
  845. r += cx;
  846. w_line += tile_cx;
  847. }
  848. if (f.has_extra_graphics(i))
  849. {
  850. r += std_cx * std_cy / 2;
  851. w_line = d;
  852. skip_x = 0;
  853. skip_y = 0;
  854. int cx, cy;
  855. if (x_extra < 0)
  856. {
  857. cx = cx_extra;
  858. }
  859. else
  860. {
  861. cx = cx_extra;
  862. w_line += x_extra;
  863. }
  864. if (y_extra < 0)
  865. {
  866. cy = cy_extra;
  867. }
  868. else
  869. {
  870. cy = cy_extra;
  871. w_line += y_extra * (tile_cx);
  872. }
  873. for (y = 0; y < cy - skip_y; y++)
  874. {
  875. byte* w = w_line;
  876. for (int x = 0; x < cx - skip_x; x++)
  877. {
  878. int v = *r++;
  879. if (v)
  880. *w = v;
  881. w++;
  882. }
  883. w_line += tile_cx;
  884. }
  885. }
  886. }
  887. BOOL LoadTMPImageInSurface(IDirectDraw4* pdd, int iStart, int iCount, LPDIRECTDRAWSURFACE4* pdds, HTSPALETTE hPalette)
  888. {
  889. last_succeeded_operation = 2100;
  890. DDSURFACEDESC2 ddsd;
  891. RGBTRIPLE rgb_transp;
  892. if (hPalette == NULL || hPalette > dwPalCount) return NULL;
  893. rgb_transp.rgbtRed = 245;
  894. rgb_transp.rgbtGreen = 245;
  895. rgb_transp.rgbtBlue = 245;
  896. int pic;
  897. for (pic = 0;pic < iCount;pic++)
  898. {
  899. int cx, cy;
  900. int z = pic + iStart;
  901. if (!cur_tmp.get_index()[z])
  902. {
  903. pdds[pic] = NULL;
  904. }
  905. else
  906. {
  907. XCC_GetTMPTileInfo(z, NULL, &cx, &cy, NULL, NULL, NULL, NULL, NULL);
  908. if (cx > 0 && cy > 0)
  909. {
  910. //const byte* r = cur_tmp.get_image(iStart+pic); //new byte[cx * cy];
  911. // byte transp=r[0];
  912. ZeroMemory(&ddsd, sizeof(ddsd));
  913. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  914. ddsd.dwWidth = cx;
  915. ddsd.dwHeight = cy;
  916. ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH /*| DDSD_PIXELFORMAT*/;
  917. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  918. byte* image = NULL;
  919. if (pdd->CreateSurface(&ddsd, &pdds[pic], NULL) == DD_OK)
  920. {
  921. last_succeeded_operation = 2101;
  922. DDPIXELFORMAT pf;
  923. memset(&pf, 0, sizeof(DDPIXELFORMAT));
  924. pf.dwSize = sizeof(DDPIXELFORMAT);
  925. pdds[pic]->GetPixelFormat(&pf);
  926. BOOL bFastLoaded = FALSE;
  927. if ((pf.dwFlags & DDPF_RGB) && pf.dwRBitMask && pf.dwGBitMask && pf.dwBBitMask)
  928. {
  929. last_succeeded_operation = 21011;
  930. CreateConvLookUpTable(pf, hPalette);
  931. int i, e;
  932. image = new byte[cx * cy];
  933. tmp_ts_draw(cur_tmp, image, iStart + pic);
  934. int bytesize = 1;//(pf.dwRGBBitCount+1)/8;
  935. if (pf.dwRGBBitCount <= 8) bytesize = 1;
  936. else if (pf.dwRGBBitCount <= 16) bytesize = 2;
  937. else if (pf.dwRGBBitCount <= 24) bytesize = 3;
  938. else if (pf.dwRGBBitCount <= 32) bytesize = 4;
  939. if (bytesize < 1) bytesize = 1;
  940. last_succeeded_operation = 21012;
  941. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  942. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  943. ddsd.dwFlags = DDSD_PITCH | DDSD_LPSURFACE;
  944. RECT lockr;
  945. lockr.left = 0;
  946. lockr.top = 0;
  947. lockr.right = cx;
  948. lockr.bottom = cy;
  949. if (pdds[pic]->Lock(&lockr, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) == DD_OK)
  950. {
  951. last_succeeded_operation = 21013;
  952. BYTE* dest = (BYTE*)ddsd.lpSurface;
  953. int pitch = ddsd.lPitch;
  954. if (ddsd.dwFlags & DDSD_PIXELFORMAT)
  955. {
  956. // pixel format overwritten
  957. CreateConvLookUpTable(ddsd.ddpfPixelFormat, hPalette);
  958. int bytesize = 1;//(pf.dwRGBBitCount+1)/8;
  959. if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 8) bytesize = 1;
  960. else if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 16) bytesize = 2;
  961. else if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 24) bytesize = 3;
  962. else if (ddsd.ddpfPixelFormat.dwRGBBitCount <= 32) bytesize = 4;
  963. if (bytesize < 1) bytesize = 1;
  964. }
  965. if (ddsd.dwFlags & DDSD_LINEARSIZE)
  966. {
  967. pitch = ddsd.dwLinearSize / cy;
  968. }
  969. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  970. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  971. ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
  972. pdds[pic]->GetSurfaceDesc(&ddsd);
  973. last_succeeded_operation = 21016;
  974. if (dest && !IsBadWritePtr(dest, pitch * cy)) // TODO: debug this case when using surfaces
  975. {
  976. bFastLoaded = TRUE;
  977. for (i = 0; i < cx; i++)
  978. {
  979. for (e = 0;e < cy;e++)
  980. {
  981. DWORD dwWrite = i * bytesize + e * pitch;
  982. DWORD dwRead = i + e * cx;
  983. if (image[dwRead] != 0)
  984. {
  985. DWORD col = conv_color[hPalette - 1][image[dwRead]];
  986. memcpy(&dest[dwWrite], &col, bytesize);
  987. }
  988. else
  989. {
  990. DWORD col = transp_conv_color[hPalette - 1];
  991. memcpy(&dest[dwWrite], &col, bytesize);
  992. }
  993. }
  994. }
  995. }
  996. pdds[pic]->Unlock(&lockr);
  997. last_succeeded_operation = 21014;
  998. }
  999. last_succeeded_operation = 21015;
  1000. DDCOLORKEY ddck;
  1001. ddck.dwColorSpaceLowValue = transp_conv_color[hPalette - 1];
  1002. ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
  1003. pdds[pic]->SetColorKey(DDCKEY_SRCBLT, &ddck);
  1004. }
  1005. if (!bFastLoaded) // use GDI
  1006. {
  1007. int i, e;
  1008. image = new byte[cx * cy];
  1009. tmp_ts_draw(cur_tmp, image, iStart + pic);
  1010. HDC hDC;
  1011. while (pdds[pic]->GetDC(&hDC) == DDERR_WASSTILLDRAWING) {};
  1012. for (i = 0; i < cx; i++)
  1013. {
  1014. for (e = 0;e < cy;e++)
  1015. {
  1016. DWORD dwRead = i + e * cx;
  1017. if (image[dwRead] != 0)
  1018. {
  1019. t_palet_entry& p = ts_palettes[hPalette - 1][image[dwRead]];
  1020. SetPixel(hDC, i, e, RGB(p.r, p.g, p.b));
  1021. }
  1022. else
  1023. {
  1024. SetPixel(hDC, i, e, RGB(245, 245, 245));
  1025. }
  1026. }
  1027. }
  1028. pdds[pic]->ReleaseDC(hDC);
  1029. SetColorKey(pdds[pic], RGB(245, 245, 245));
  1030. }
  1031. }
  1032. if (image) delete[] image;
  1033. image = NULL;
  1034. }
  1035. }
  1036. }
  1037. return TRUE;
  1038. }
  1039. BOOL LoadTMPImage(int iStart, int iCount, BYTE** lpTileArray)
  1040. {
  1041. last_succeeded_operation = 2100;
  1042. int pic;
  1043. for (pic = 0;pic < iCount;pic++)
  1044. {
  1045. int cx, cy;
  1046. int z = pic + iStart;
  1047. if (!cur_tmp.get_index()[z])
  1048. {
  1049. lpTileArray[pic] = NULL;
  1050. }
  1051. else
  1052. {
  1053. XCC_GetTMPTileInfo(z, NULL, &cx, &cy, NULL, NULL, NULL, NULL, NULL);
  1054. if (cx > 0 && cy > 0)
  1055. {
  1056. byte* image = NULL;
  1057. last_succeeded_operation = 2101;
  1058. image = new byte[cx * cy];
  1059. tmp_ts_draw(cur_tmp, image, iStart + pic);
  1060. lpTileArray[pic] = image;
  1061. image = NULL;
  1062. }
  1063. }
  1064. }
  1065. return TRUE;
  1066. }
  1067. Cvxl_file cur_vxl;
  1068. Chva_file cur_hva;
  1069. t_palet32bgr_entry color_table[256];
  1070. void load_color_table(const t_palet palet, bool convert_palet)
  1071. {
  1072. t_palet p;
  1073. memcpy(p, palet, sizeof(t_palet));
  1074. if (convert_palet)
  1075. convert_palet_18_to_24(p);
  1076. for (long i = 0; i < 256; i++)
  1077. {
  1078. color_table[i].r = p[i].r;
  1079. color_table[i].g = p[i].g;
  1080. color_table[i].b = p[i].b;
  1081. }
  1082. }
  1083. /*struct t_vector
  1084. {
  1085. double x;
  1086. double y;
  1087. double z;
  1088. };*/
  1089. const double pi = 3.141592654;
  1090. template<class T>
  1091. __forceinline void rotate_x(Vec3<T>& v, T a)
  1092. {
  1093. T l = sqrt(v.y() * v.y() + v.z() * v.z());
  1094. T d_a = atan2(v.y(), v.z()) + a;
  1095. v[1] = l * sin(d_a);
  1096. v[2] = l * cos(d_a);
  1097. }
  1098. template<class T>
  1099. __forceinline void rotate_y(Vec3<T>& v, T a)
  1100. {
  1101. T l = sqrt(v.x() * v.x() + v.z() * v.z());
  1102. T d_a = atan2(v.x(), v.z()) + a;
  1103. v[0] = l * sin(d_a);
  1104. v[2] = l * cos(d_a);
  1105. }
  1106. template<class T>
  1107. __forceinline void rotate_z(Vec3<T>& v, T a)
  1108. {
  1109. T l = sqrt(v.x() * v.x() + v.y() * v.y());
  1110. T d_a = atan2(v.x(), v.y()) + a;
  1111. v[0] = l * sin(d_a);
  1112. v[1] = l * cos(d_a);;
  1113. }
  1114. template<class T>
  1115. __forceinline void rotate_zxy(Vec3<T>& v, const Vec3<T>& r)
  1116. {
  1117. rotate_z(v, r.z());
  1118. rotate_x(v, r.x());
  1119. rotate_y(v, r.y());
  1120. }
  1121. BOOL SetCurrentVXL(LPCSTR lpVXLFile, HMIXFILE hMixFile)
  1122. {
  1123. last_succeeded_operation = 500;
  1124. if (cur_vxl.is_open()) cur_vxl.close();
  1125. if (cur_hva.is_open()) cur_hva.close();
  1126. auto HVA = std::string(lpVXLFile);
  1127. std::transform(HVA.begin(), HVA.end(), HVA.begin(), [](unsigned char c) { return std::tolower(c); });
  1128. HVA = std::regex_replace(HVA, std::regex(".vxl$"), ".hva");
  1129. if (hMixFile == NULL)
  1130. {
  1131. if (open_read(cur_vxl, lpVXLFile))
  1132. return FALSE;
  1133. if (open_read(cur_hva, HVA))
  1134. return FALSE;
  1135. }
  1136. else
  1137. {
  1138. if (cur_vxl.open(lpVXLFile, mixfiles[hMixFile - 1]))
  1139. return FALSE;
  1140. if (cur_hva.open(HVA, mixfiles[hMixFile - 1]))
  1141. return FALSE;
  1142. }
  1143. if (!cur_vxl.is_open())
  1144. return FALSE;
  1145. if (!cur_hva.is_open())
  1146. return FALSE;
  1147. return TRUE;
  1148. }
  1149. BOOL GetVXLInfo(int* cSections)
  1150. {
  1151. if (!cur_vxl.is_open())
  1152. return FALSE;
  1153. if (cSections) *cSections = cur_vxl.get_c_section_headers();
  1154. return TRUE;
  1155. }
  1156. BOOL GetVXLSectionInfo(int section, VoxelNormalClass& normalClass)
  1157. {
  1158. if (!cur_vxl.is_open())
  1159. return FALSE;
  1160. if (section >= cur_vxl.get_c_section_headers())
  1161. return FALSE;
  1162. switch (cur_vxl.get_section_tailer(section)->unknown)
  1163. {
  1164. case 1:
  1165. normalClass = VoxelNormalClass::Gen1;
  1166. break;
  1167. case 2:
  1168. normalClass = VoxelNormalClass::TS;
  1169. break;
  1170. case 3:
  1171. normalClass = VoxelNormalClass::Gen3;
  1172. break;
  1173. case 4:
  1174. normalClass = VoxelNormalClass::RA2;
  1175. break;
  1176. default:
  1177. normalClass = VoxelNormalClass::Unknown;
  1178. }
  1179. return TRUE;
  1180. }
  1181. void GetVXLSectionBounds(int iSection, const Vec3f& rotation, const Vec3f& modelOffset, Vec3f& minVec, Vec3f& maxVec)
  1182. {
  1183. const t_vxl_section_tailer& section_tailer = *cur_vxl.get_section_tailer(iSection);
  1184. auto& header = *cur_vxl.get_section_header(iSection);
  1185. auto& tailer = *cur_vxl.get_section_tailer(iSection);
  1186. //const auto matrix = Matrix3_4f(tailer.transform).scaledColumn(3, tailer.scale);
  1187. const auto matrix = Matrix3_4f(cur_hva.get_transform_matrix(0, iSection)).scaledColumn(3, tailer.scale);
  1188. maxVec = minVec = Vec3f(section_tailer.x_min_scale, section_tailer.y_min_scale, section_tailer.z_min_scale);
  1189. // get projected coordinates of all bounding box corners
  1190. for (int x = 0; x < 2; ++x)
  1191. {
  1192. for (int y = 0; y < 2; ++y)
  1193. {
  1194. for (int z = 0; z < 2; ++z)
  1195. {
  1196. Vec3f cur = matrix * (Vec3f(
  1197. x == 0 ? section_tailer.x_min_scale : section_tailer.x_max_scale,
  1198. y == 0 ? section_tailer.y_min_scale : section_tailer.y_max_scale,
  1199. z == 0 ? section_tailer.z_min_scale : section_tailer.z_max_scale
  1200. ) + modelOffset);
  1201. rotate_zxy(cur, rotation);
  1202. minVec.minimum(cur);
  1203. maxVec.maximum(cur);
  1204. }
  1205. }
  1206. }
  1207. // for Debug, ensure center is visible
  1208. #ifdef _DEBUG
  1209. Vec3f cur = matrix * Vec3f();
  1210. rotate_zxy(cur, rotation);
  1211. minVec.minimum(cur);
  1212. maxVec.maximum(cur);
  1213. #endif
  1214. }
  1215. void RenderVXLSection(const VoxelNormalTable& normalTable, Vec3f lightDirection, const int iSection, int rtWidth, int rtHeight, const Vec3f& modelOffset, const Vec3f& rotation, const Vec3f& postHVAOffset, BYTE* image, BYTE* lighting, char* image_z, int* i_center_x, int* i_center_y, int ZAdjust, int* i_center_x_zmax, int* i_center_y_zmax, int i3dCenterX, int i3dCenterY)
  1216. {
  1217. // normals:
  1218. // - positive x is facing screen right
  1219. // - positive y is facing screen bottom
  1220. // - positive z is facing viewer
  1221. const Vec3f inverseLightDirection = negate(normalize(lightDirection));
  1222. last_succeeded_operation = 10;
  1223. const auto& header = *cur_vxl.get_section_header(iSection);
  1224. const auto& tailer = *cur_vxl.get_section_tailer(iSection);
  1225. const int cx1 = tailer.cx;
  1226. const int cy1 = tailer.cy;
  1227. const int cz1 = tailer.cz;
  1228. //const Matrix3_4f matrix(tailer.transform);
  1229. const Matrix3_4f matrix(cur_hva.get_transform_matrix(0, iSection));
  1230. const Matrix3_4f normalMatrix = Matrix3_4f(matrix).setColumn(3, Vec3f());
  1231. const Matrix3_4f scaledMatrix = matrix.scaleColumn(3, tailer.scale);
  1232. const Vec3f minScale = Vec3f(tailer.x_min_scale, tailer.y_min_scale, tailer.z_min_scale) + postHVAOffset;
  1233. const Vec3f maxScale = Vec3f(tailer.x_max_scale, tailer.y_max_scale, tailer.z_max_scale) + postHVAOffset;
  1234. const Matrix3_4f translateToWorldMatrix = Matrix3_4f::translation(minScale);
  1235. const Matrix3_4f scaleToWorldMatrix = Matrix3_4f::scale((maxScale - minScale) / Vec3f(tailer.cx, tailer.cy, tailer.cz));
  1236. const float _center_x = 0.0f; //(tailer.x_max_scale + tailer.x_min_scale) / 2.f;
  1237. const float _center_y = 0.0f; //(tailer.y_max_scale + tailer.y_min_scale) / 2.f;
  1238. const float _center_z = 0.0f; //(tailer.z_max_scale + tailer.z_min_scale) / 2.f;
  1239. if (i3dCenterX < 0)
  1240. i3dCenterX = static_cast<int>(_center_x);
  1241. if (i3dCenterY < 0)
  1242. i3dCenterY = static_cast<int>(_center_y);
  1243. Vec3f center(_center_x, _center_y, _center_z);
  1244. last_succeeded_operation = 11;
  1245. // output center 2d coordinates
  1246. if (i_center_x || i_center_y)
  1247. {
  1248. Vec3f s_pixel = center + Vec3f(0.0f, 0.f, 0.0f);
  1249. Vec3f d_pixel = scaledMatrix * s_pixel;
  1250. rotate_zxy(d_pixel, rotation);
  1251. d_pixel += modelOffset;
  1252. if (i_center_x)
  1253. *i_center_x = static_cast<int>(d_pixel.x() + 0.5f);
  1254. if (i_center_y)
  1255. *i_center_y = static_cast<int>(d_pixel.y() + 0.5f);
  1256. }
  1257. last_succeeded_operation = 12;
  1258. if (i_center_x_zmax || i_center_y_zmax)
  1259. {
  1260. Vec3f s_pixel = center;
  1261. Vec3f d_pixel = scaledMatrix * s_pixel;
  1262. rotate_zxy(d_pixel, rotation);
  1263. d_pixel += modelOffset;
  1264. if (i_center_x_zmax) *i_center_x_zmax = static_cast<int>(d_pixel.x());
  1265. if (i_center_y_zmax) *i_center_y_zmax = static_cast<int>(d_pixel.y());
  1266. }
  1267. last_succeeded_operation = 13;
  1268. // Vec3f minPixel(1000, 1000, 1000);
  1269. int j = 0;
  1270. for (int y = 0; y < cy1; y++)
  1271. {
  1272. for (int x = 0; x < cx1; x++)
  1273. {
  1274. const byte* r = cur_vxl.get_span_data(iSection, j);
  1275. if (r)
  1276. {
  1277. int z = 0;
  1278. int last_z_reported = -5000;
  1279. while (z < cz1)
  1280. {
  1281. z += *r++;
  1282. int count = *r++;
  1283. while (count--)
  1284. {
  1285. Vec3f s_pixel = Vec3f(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
  1286. Vec3f m_pixel = (translateToWorldMatrix * (scaleToWorldMatrix * s_pixel));
  1287. assert(minimum(m_pixel, minScale).equals(minScale, 0.001f));
  1288. assert(maximum(m_pixel, maxScale).equals(maxScale, 0.001f));
  1289. Vec3f t_pixel = scaledMatrix * m_pixel;
  1290. Vec3f d_pixel = t_pixel;
  1291. rotate_zxy(d_pixel, rotation);
  1292. d_pixel += modelOffset;
  1293. // minPixel.minimum(d_pixel);
  1294. if (x == i3dCenterX && y == i3dCenterY)
  1295. {
  1296. if (z >= last_z_reported)
  1297. {
  1298. last_z_reported = z;
  1299. if (i_center_x_zmax) *i_center_x_zmax = static_cast<int>(d_pixel.x());
  1300. if (i_center_y_zmax) *i_center_y_zmax = static_cast<int>(d_pixel.y());
  1301. }
  1302. }
  1303. int px = static_cast<int>(d_pixel.x() + 0.5f);
  1304. int py = static_cast<int>(d_pixel.y() + 0.5f);
  1305. int ofs = px + rtWidth * py;
  1306. if (px >= 0 && py >= 0 && px < rtWidth && py < rtHeight && d_pixel.z() > image_z[ofs])
  1307. {
  1308. image[ofs] = *r++;
  1309. // lighting calc
  1310. auto normalIndex = *r++;
  1311. auto normal = (normalMatrix * normalTable[normalIndex]);
  1312. rotate_zxy(normal, rotation);
  1313. auto normalDotLightingVec = normal.dot(inverseLightDirection);
  1314. auto lightVal = normalDotLightingVec < 0.0f ? 0.0f : normalDotLightingVec;
  1315. assert(fabs(normal.squaredLength() - 1.0f) < 0.01f);
  1316. lighting[ofs] = max(0, static_cast<BYTE>(lightVal * 255.0f));
  1317. image_z[ofs] = static_cast<char>(d_pixel.z());
  1318. }
  1319. else
  1320. r += 2;;
  1321. z++;
  1322. }
  1323. r++;
  1324. }
  1325. }
  1326. j++;
  1327. }
  1328. }
  1329. }
  1330. VoxelNormalTable emptyNormalTable;
  1331. BOOL LoadVXLImageInSurface(const VoxelNormalTables& normalTables, Vec3f lightDirection, IDirectDraw4* pdd, int iStart, int iCount, const Vec3f rotation, const Vec3f postHVAOffset, LPDIRECTDRAWSURFACE4* pdds, HTSPALETTE hPalette, int* lpXCenter, int* lpYCenter, int ZAdjust, int* lpXCenterZMax, int* lpYCenterZMax, int i3dCenterX, int i3dCenterY)
  1332. {
  1333. if (hPalette == NULL || hPalette > dwPalCount) return NULL;
  1334. last_succeeded_operation = 1;
  1335. int i;
  1336. int cx_max = 0, cy_max = 0, cz_max = 0;
  1337. Vec3f minCoords(10000, 10000, 10000);
  1338. Vec3f maxCoords(-10000, -10000, -10000);
  1339. // Calculate projected bounding box for the virtual render target
  1340. int iBodySection = -1;
  1341. int iLargestSection = 0;
  1342. int iLargestVolume = 0;
  1343. for (i = 0; i < cur_vxl.get_c_section_tailers(); i++)
  1344. {
  1345. const auto& header = cur_vxl.get_section_header(i);
  1346. const auto& tailer = cur_vxl.get_section_tailer(i);
  1347. Vec3f secMinVec, secMaxVec;
  1348. GetVXLSectionBounds(i, rotation, postHVAOffset, secMinVec, secMaxVec);
  1349. auto extent = secMaxVec - secMinVec;
  1350. auto volume = extent.x() * extent.y() * extent.z();
  1351. if (volume >= iLargestVolume)
  1352. {
  1353. iLargestVolume = volume;
  1354. iLargestSection = i;
  1355. }
  1356. if (strstr(header->id, "BODY") == 0)
  1357. iBodySection = i;
  1358. minCoords.minimum(secMinVec);
  1359. maxCoords.maximum(secMaxVec);
  1360. }
  1361. const int iMainSection = iBodySection >= 0 ? iBodySection : iLargestSection;
  1362. const Vec3f renderOffset = negate(minCoords);
  1363. last_succeeded_operation = 2;
  1364. const auto extents = (maxCoords - minCoords);
  1365. int rtWidth = ceil(extents.x());
  1366. int rtHeight = ceil(extents.y());
  1367. const int c_pixels = rtWidth * rtHeight;
  1368. // MYASSERT(c_pixels,1);
  1369. byte* image = new byte[c_pixels];
  1370. byte* image_s = new byte[c_pixels];
  1371. char* image_z = new char[c_pixels];
  1372. memset(image, 0, c_pixels);
  1373. memset(image_s, 0, c_pixels);
  1374. memset(image_z, CHAR_MIN, c_pixels);
  1375. int x_center = 0, y_center = 0;
  1376. int x_center_zmax = 0, y_center_zmax = 0;
  1377. for (i = 0; i < cur_vxl.get_c_section_headers(); i++)
  1378. {
  1379. auto iNormalTable = cur_vxl.get_section_tailer(i)->unknown;
  1380. const auto& normalTable = normalTables.isValidTable(iNormalTable) ? normalTables.getTable(iNormalTable) : emptyNormalTable;
  1381. if (i != iMainSection)
  1382. RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, postHVAOffset, image, image_s, image_z, NULL, NULL, 0, NULL, NULL, -1, -1);
  1383. else
  1384. RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, postHVAOffset, image, image_s, image_z, &x_center, &y_center, ZAdjust, &x_center_zmax, &y_center_zmax, i3dCenterX, i3dCenterY);
  1385. }
  1386. last_succeeded_operation = 3;
  1387. if (lpXCenter) *lpXCenter = x_center;
  1388. if (lpYCenter) *lpYCenter = y_center;
  1389. if (lpXCenterZMax) *lpXCenterZMax = x_center_zmax;
  1390. if (lpYCenterZMax) *lpYCenterZMax = y_center_zmax;
  1391. // calculate x/y values
  1392. int left = 0, right = rtWidth, top = 0, bottom = rtHeight;
  1393. // draw pic
  1394. DDSURFACEDESC2 ddsd;
  1395. ZeroMemory(&ddsd, sizeof(ddsd));
  1396. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1397. ddsd.dwWidth = right - left;
  1398. ddsd.dwHeight = bottom - top;
  1399. ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH /*| DDSD_PIXELFORMAT*/;
  1400. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  1401. if (pdd->CreateSurface(&ddsd, &pdds[0], NULL) != DD_OK)
  1402. return NULL;
  1403. ddsd.dwFlags = DDSD_PITCH;
  1404. pdds[0]->GetSurfaceDesc(&ddsd);
  1405. long pitch = ddsd.lPitch;
  1406. DDPIXELFORMAT pf;
  1407. memset(&pf, 0, sizeof(DDPIXELFORMAT));
  1408. pf.dwSize = sizeof(DDPIXELFORMAT);
  1409. pdds[0]->GetPixelFormat(&pf);
  1410. last_succeeded_operation = 5;
  1411. BOOL bUseGDI = FALSE;
  1412. if (pf.dwFlags & DDPF_RGB && pf.dwRBitMask && pf.dwGBitMask && pf.dwBBitMask)
  1413. {
  1414. CreateConvLookUpTable(pf, hPalette);
  1415. /*DDBLTFX fx;
  1416. memset(&fx, 0, sizeof(DDBLTFX));
  1417. fx.dwSize=sizeof(DDBLTFX);
  1418. pdds[0]->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
  1419. */
  1420. last_succeeded_operation = 6;
  1421. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  1422. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1423. if (pdds[0]->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL) == DD_OK)
  1424. {
  1425. pitch = ddsd.lPitch;
  1426. BYTE* dest = (BYTE*)ddsd.lpSurface;
  1427. if (dest)
  1428. {
  1429. int bytesize = (pf.dwRGBBitCount + 1) / 8;
  1430. if (bytesize < 1) bytesize = 1;
  1431. if (pf.dwRGBBitCount <= 8) bytesize = 1;
  1432. else if (pf.dwRGBBitCount <= 16) bytesize = 2;
  1433. else if (pf.dwRGBBitCount <= 24) bytesize = 3;
  1434. else if (pf.dwRGBBitCount <= 32) bytesize = 4;
  1435. last_succeeded_operation = 7;
  1436. int k, e;
  1437. //HDC dc;
  1438. //pdds[0]->GetDC(&dc);
  1439. for (k = 0;k < rtWidth;k++)
  1440. {
  1441. for (e = 0;e < rtHeight;e++)
  1442. {
  1443. //t_palet_entry p=ts_palettes[hPalette-1][image[k+e*cl_max]];
  1444. if (k >= left && e >= top && k < right && e < bottom)
  1445. {
  1446. //SetPixel(dc, k-left, e-top, RGB(p.r, p.g, p.b) );
  1447. DWORD dwWrite = k * bytesize + e * ddsd.lPitch;
  1448. int pos = k + e * rtWidth;
  1449. if (pos < c_pixels && image[pos] != 0)
  1450. {
  1451. DWORD col = conv_color[hPalette - 1][image[k + e * rtWidth]];
  1452. memcpy(&dest[dwWrite], &col, bytesize);
  1453. }
  1454. else
  1455. {
  1456. DWORD col = transp_conv_color[hPalette - 1];
  1457. memcpy(&dest[dwWrite], &col, bytesize);
  1458. }
  1459. }
  1460. }
  1461. }
  1462. memcpy(&dest[0], &transp_conv_color[hPalette - 1], bytesize);
  1463. //pdds[0]->ReleaseDC(dc);
  1464. }
  1465. pdds[0]->Unlock(NULL);
  1466. }
  1467. else bUseGDI = TRUE;
  1468. }
  1469. else bUseGDI = TRUE;
  1470. if (bUseGDI)
  1471. {
  1472. HDC hDC;
  1473. while (pdds[0]->GetDC(&hDC) == DDERR_WASSTILLDRAWING);
  1474. last_succeeded_operation = 7;
  1475. int k, e;
  1476. //HDC dc;
  1477. //pdds[0]->GetDC(&dc);
  1478. for (k = 0;k < rtWidth;k++)
  1479. {
  1480. for (e = 0;e < rtHeight;e++)
  1481. {
  1482. //t_palet_entry p=ts_palettes[hPalette-1][image[k+e*cl_max]];
  1483. if (k >= left && e >= top && k < right && e < bottom)
  1484. {
  1485. //SetPixel(dc, k-left, e-top, RGB(p.r, p.g, p.b) );
  1486. //DWORD dwWrite=k*bytesize+e*ddsd.lPitch;
  1487. int pos = k + e * rtWidth;
  1488. if (pos < c_pixels && image[pos] != 0)
  1489. {
  1490. t_palet_entry& p = ts_palettes[hPalette - 1][image[k + e * rtWidth]];
  1491. SetPixel(hDC, k, e, RGB(p.r, p.g, p.b));
  1492. }
  1493. else
  1494. {
  1495. SetPixel(hDC, k, e, RGB(245, 245, 245));
  1496. }
  1497. }
  1498. }
  1499. }
  1500. SetPixel(hDC, 0, 0, RGB(245, 245, 245));
  1501. pdds[0]->ReleaseDC(hDC);
  1502. }
  1503. last_succeeded_operation = 70001;
  1504. SetColorKey(pdds[0], -1);
  1505. last_succeeded_operation = 70002;
  1506. if (image) delete[] image;
  1507. if (image_s) delete[] image_s;
  1508. if (image_z) delete[] image_z;
  1509. //pal.close();
  1510. return TRUE;
  1511. }
  1512. BOOL LoadVXLImage(const VoxelNormalTables& normalTables, Vec3f lightDirection, const Vec3f rotation, const Vec3f modelOffset, std::vector<BYTE>& image, std::vector<BYTE>& lighting, int* lpXCenter, int* lpYCenter, int ZAdjust, int* lpXCenterZMax, int* lpYCenterZMax, int i3dCenterX, int i3dCenterY, RECT* vxlrect)
  1513. {
  1514. last_succeeded_operation = 1;
  1515. int i;
  1516. int cx_max = 0, cy_max = 0, cz_max = 0;
  1517. Vec3f minCoords(10000, 10000, 10000);
  1518. Vec3f maxCoords(-10000, -10000, -10000);
  1519. // Calculate projected bounding box for the virtual render target
  1520. int iBodySection = -1;
  1521. int iLargestSection = 0;
  1522. int iLargestVolume = 0;
  1523. for (i = 0; i < cur_vxl.get_c_section_tailers(); i++)
  1524. {
  1525. const auto& header = cur_vxl.get_section_header(i);
  1526. const auto& tailer = cur_vxl.get_section_tailer(i);
  1527. Vec3f secMinVec, secMaxVec;
  1528. GetVXLSectionBounds(i, rotation, modelOffset, secMinVec, secMaxVec);
  1529. auto extent = secMaxVec - secMinVec;
  1530. auto volume = extent.x() * extent.y() * extent.z();
  1531. if (volume >= iLargestVolume)
  1532. {
  1533. iLargestVolume = volume;
  1534. iLargestSection = i;
  1535. }
  1536. if (strcmp(header->id, "BODY") == 0)
  1537. iBodySection = i;
  1538. minCoords.minimum(secMinVec);
  1539. maxCoords.maximum(secMaxVec);
  1540. }
  1541. const int iMainSection = iBodySection >= 0 ? iBodySection : iLargestSection;
  1542. const Vec3f renderOffset = negate(minCoords);
  1543. last_succeeded_operation = 2;
  1544. const auto extents = (maxCoords - minCoords);
  1545. int rtWidth = ceil(extents.x()) + 1;
  1546. int rtHeight = ceil(extents.y()) + 1;
  1547. const int c_pixels = rtWidth * rtHeight;
  1548. MYASSERT(c_pixels, 1);
  1549. image.clear();
  1550. lighting.clear();
  1551. image.resize(c_pixels, 0);
  1552. lighting.resize(c_pixels, 255);
  1553. std::vector<char> image_z(c_pixels, CHAR_MIN);
  1554. int x_center = 0, y_center = 0;
  1555. int x_center_zmax = 0, y_center_zmax = 0;
  1556. for (i = 0; i < cur_vxl.get_c_section_headers(); i++)
  1557. {
  1558. auto iNormalTable = cur_vxl.get_section_tailer(i)->unknown;
  1559. const auto& normalTable = normalTables.isValidTable(iNormalTable) ? normalTables.getTable(iNormalTable) : emptyNormalTable;
  1560. if (i != iMainSection)
  1561. RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, modelOffset, image.data(), lighting.data(), image_z.data(), NULL, NULL, ZAdjust, NULL, NULL, -1, -1);
  1562. else
  1563. RenderVXLSection(normalTable, lightDirection, i, rtWidth, rtHeight, renderOffset, rotation, modelOffset, image.data(), lighting.data(), image_z.data(), &x_center, &y_center, ZAdjust, &x_center_zmax, &y_center_zmax, i3dCenterX, i3dCenterY);
  1564. }
  1565. last_succeeded_operation = 3;
  1566. if (lpXCenter)
  1567. *lpXCenter = x_center;
  1568. if (lpYCenter)
  1569. *lpYCenter = y_center;
  1570. if (lpXCenterZMax)
  1571. *lpXCenterZMax = x_center_zmax;
  1572. if (lpYCenterZMax)
  1573. *lpYCenterZMax = y_center_zmax;
  1574. // calculate x/y values
  1575. int left = 0, right = rtWidth, top = 0, bottom = rtHeight;
  1576. int width = right - left;
  1577. int height = bottom - top;
  1578. if (vxlrect)
  1579. {
  1580. vxlrect->left = 0;
  1581. vxlrect->right = width;
  1582. vxlrect->bottom = height;
  1583. vxlrect->top = 0;
  1584. }
  1585. #ifdef _DEBUG
  1586. // draw lines around RT
  1587. for (i = 0; i < width; ++i)
  1588. {
  1589. lighting[i] = 1;
  1590. lighting[i + (height - 1) * width] = 1;
  1591. image[i] = 1;
  1592. image[i + (height - 1) * width] = 1;
  1593. }
  1594. for (i = 0; i < height; ++i)
  1595. {
  1596. image[i * width + width - 1] = 1;
  1597. image[i * width] = 1;
  1598. }
  1599. // draw center
  1600. if (x_center > 0 && y_center > 0 && x_center < width - 1 && y_center < height - 1)
  1601. {
  1602. image[x_center + y_center * width] = 1;
  1603. image[x_center - 1 + y_center * width] = 1;
  1604. image[x_center + 1 + y_center * width] = 1;
  1605. image[x_center + (y_center + 1) * width] = 1;
  1606. image[x_center + (y_center - 1) * width] = 1;
  1607. }
  1608. #endif
  1609. image.resize(width * height);
  1610. lighting.resize(width * height);
  1611. return TRUE;
  1612. }
  1613. HTSPALETTE LoadTSPalette(const std::string& szPalette, HMIXFILE hPaletteOwner)
  1614. {
  1615. Cpal_file pal;
  1616. RGBTRIPLE* paldata;
  1617. if (dwPalCount > 255)
  1618. return NULL;
  1619. if (hPaletteOwner == NULL)
  1620. {
  1621. if (open_read(pal, szPalette))
  1622. return NULL;
  1623. }
  1624. else
  1625. {
  1626. if (szPalette[0] == '_' && szPalette[1] == 'I' && szPalette[2] == 'D')
  1627. {
  1628. char id[256];
  1629. strcpy_s(id, &szPalette[3]);
  1630. int iId = atoi(id);
  1631. if (pal.open(iId, mixfiles[hPaletteOwner - 1]))
  1632. return NULL;
  1633. }
  1634. else
  1635. {
  1636. if (pal.open(szPalette, mixfiles[hPaletteOwner - 1]) != 0)
  1637. return NULL;
  1638. }
  1639. }
  1640. if (!pal.is_open())
  1641. return NULL;
  1642. dwPalCount++;
  1643. paldata = (RGBTRIPLE*)pal.get_data();
  1644. //t_palet t_p;
  1645. memcpy(ts_palettes[dwPalCount - 1], paldata, 768);
  1646. bFirstConv[dwPalCount - 1] = TRUE;
  1647. convert_palet_18_to_24(ts_palettes[dwPalCount - 1]);
  1648. pal.close();
  1649. return dwPalCount;
  1650. }
  1651. HTSPALETTE LoadTSPalette(LPCSTR szPalette, HMIXFILE hPaletteOwner)
  1652. {
  1653. return LoadTSPalette(std::string(szPalette), hPaletteOwner);
  1654. }
  1655. BOOL SetTSPaletteEntry(HTSPALETTE hPalette, BYTE bIndex, RGBTRIPLE* rgb, RGBTRIPLE* orig)
  1656. {
  1657. if (hPalette == NULL || hPalette > dwPalCount)
  1658. return FALSE;
  1659. if (orig != NULL)
  1660. {
  1661. orig->rgbtRed = ts_palettes[hPalette - 1][bIndex].r;
  1662. orig->rgbtGreen = ts_palettes[hPalette - 1][bIndex].g;
  1663. orig->rgbtBlue = ts_palettes[hPalette - 1][bIndex].b;
  1664. }
  1665. if (rgb != NULL)
  1666. {
  1667. ts_palettes[hPalette - 1][bIndex].r = rgb->rgbtRed;
  1668. ts_palettes[hPalette - 1][bIndex].g = rgb->rgbtGreen;
  1669. ts_palettes[hPalette - 1][bIndex].b = rgb->rgbtBlue;
  1670. bFirstConv[hPalette - 1] = TRUE;
  1671. CreateConvLookUpTable(cur_pf[hPalette - 1], hPalette);
  1672. }
  1673. return TRUE;
  1674. }
  1675. t_game GameToXCCGame(FSunPackLib::Game game)
  1676. {
  1677. t_game xcc_game(game_unknown);
  1678. switch (game)
  1679. {
  1680. case TS:
  1681. xcc_game = game_ts;
  1682. break;
  1683. case RA2:
  1684. xcc_game = game_ra2;
  1685. break;
  1686. case TS_FS:
  1687. xcc_game = game_ts_fs;
  1688. break;
  1689. case RA2_YR:
  1690. xcc_game = game_ra2_yr;
  1691. break;
  1692. }
  1693. return xcc_game;
  1694. }
  1695. BOOL WriteMixFile(LPCTSTR lpMixFile, LPCSTR* lpFiles, DWORD dwFileCount, Game game)
  1696. {
  1697. if (!lpFiles)
  1698. return FALSE;
  1699. if (!lpMixFile)
  1700. return FALSE;
  1701. Cmix_file_write mix(GameToXCCGame(game));
  1702. DWORD i;
  1703. for (i = 0;i < dwFileCount;i++)
  1704. {
  1705. LPCSTR lpFile = lpFiles[i];
  1706. Cvirtual_binary file = Cvirtual_binary(std::string(lpFile));
  1707. if (file.data())
  1708. {
  1709. mix.add_file(lpFile, file);
  1710. }
  1711. }
  1712. auto binary = mix.write();
  1713. return binary.save(lpMixFile) == 0;
  1714. }
  1715. class ColorConverterImpl
  1716. {
  1717. public:
  1718. ColorConverterImpl(const DDPIXELFORMAT& pf)
  1719. {
  1720. m_conf.set_pf(pf);
  1721. }
  1722. int GetColor(int r, int g, int b) const
  1723. {
  1724. return m_conf.get_color(r, g, b);
  1725. }
  1726. int GetColor(int a, int r, int g, int b) const
  1727. {
  1728. return m_conf.get_color(a, r, g, b);
  1729. }
  1730. private:
  1731. mutable Cddpf_conversion m_conf;
  1732. };
  1733. ColorConverter::ColorConverter(const DDPIXELFORMAT& pf) :
  1734. m_impl(new ColorConverterImpl(pf))
  1735. {
  1736. }
  1737. int ColorConverter::GetColor(int r, int g, int b) const
  1738. {
  1739. return m_impl->GetColor(r, g, b);
  1740. }
  1741. int ColorConverter::GetColor(int a, int r, int g, int b) const
  1742. {
  1743. return m_impl->GetColor(a, r, g, b);
  1744. }
  1745. int ColorConverter::GetColor(COLORREF col) const
  1746. {
  1747. return GetColor((LOBYTE((col) >> 24)), GetRValue(col), GetGValue(col), GetBValue(col));
  1748. }
  1749. };