Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2716 lines
76 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #undef fopen
  8. #if !defined( _GAMECONSOLE ) && !defined( _OSX ) && !defined (LINUX)
  9. #include <windows.h> // SRC only!!
  10. #endif
  11. #if defined( POSIX ) && !defined( _PS3 )
  12. #ifdef OSX
  13. #include <copyfile.h>
  14. #endif
  15. #define DeleteFile unlink
  16. #endif
  17. #include "optionssubmultiplayer.h"
  18. #include "multiplayeradvanceddialog.h"
  19. #include <stdio.h>
  20. #include <vgui_controls/Button.h>
  21. #include <vgui_controls/CheckButton.h>
  22. #include "tier1/keyvalues.h"
  23. #include <vgui_controls/Label.h>
  24. #include <vgui/ISystem.h>
  25. #include <vgui/ISurface.h>
  26. #include <vgui/Cursor.h>
  27. #include <vgui_controls/RadioButton.h>
  28. #include <vgui_controls/ComboBox.h>
  29. #include <vgui_controls/ImagePanel.h>
  30. #include <vgui_controls/FileOpenDialog.h>
  31. #include <vgui_controls/MessageBox.h>
  32. #include <vgui/IVGui.h>
  33. #include <vgui/ILocalize.h>
  34. #include <vgui/IPanel.h>
  35. #include <vgui_controls/MessageBox.h>
  36. #include "cvartextentry.h"
  37. #include "cvartogglecheckbutton.h"
  38. #include "cvarslider.h"
  39. #include "labeledcommandcombobox.h"
  40. #include "filesystem.h"
  41. #include "engineinterface.h"
  42. #include "bitmapimagepanel.h"
  43. #include "utlbuffer.h"
  44. #include "modinfo.h"
  45. #include "tier1/convar.h"
  46. #include "materialsystem/imaterial.h"
  47. #include "materialsystem/imesh.h"
  48. #include "materialsystem/imaterialvar.h"
  49. // use the JPEGLIB_USE_STDIO define so that we can read in jpeg's from outside the game directory tree. For Spray Import.
  50. #define JPEGLIB_USE_STDIO
  51. #include "jpeglib/jpeglib.h"
  52. #undef JPEGLIB_USE_STDIO
  53. #include <setjmp.h>
  54. #include "bitmap/tgawriter.h"
  55. #include "ivtex.h"
  56. // dgoodenough - io.h doesn't exist on the PS3
  57. // PS3_BUILDFIX
  58. #if !defined( _PS3 ) && !defined( _OSX ) && !defined (LINUX)
  59. #include <io.h>
  60. #endif
  61. // dgoodenough - select the correct stubs header based on current console
  62. // PS3_BUILDFIX
  63. #if defined( _PS3 )
  64. #include "ps3/ps3_win32stubs.h"
  65. #endif
  66. #if defined( _X360 )
  67. #include "xbox/xbox_win32stubs.h"
  68. #endif
  69. // memdbgon must be the last include file in a .cpp file!!!
  70. #include <tier0/memdbgon.h>
  71. using namespace vgui;
  72. #define DEFAULT_SUIT_HUE 30
  73. #define DEFAULT_PLATE_HUE 6
  74. void UpdateLogoWAD( void *hdib, int r, int g, int b );
  75. struct ColorItem_t
  76. {
  77. char *name;
  78. int r, g, b;
  79. };
  80. static ColorItem_t itemlist[]=
  81. {
  82. { "#Valve_Orange", 255, 120, 24 },
  83. { "#Valve_Yellow", 225, 180, 24 },
  84. { "#Valve_Blue", 0, 60, 255 },
  85. { "#Valve_Ltblue", 0, 167, 255 },
  86. { "#Valve_Green", 0, 167, 0 },
  87. { "#Valve_Red", 255, 43, 0 },
  88. { "#Valve_Brown", 123, 73, 0 },
  89. { "#Valve_Ltgray", 100, 100, 100 },
  90. { "#Valve_Dkgray", 36, 36, 36 },
  91. };
  92. static ColorItem_t s_crosshairColors[] =
  93. {
  94. { "#Valve_Green", 50, 250, 50 },
  95. { "#Valve_Red", 250, 50, 50 },
  96. { "#Valve_Blue", 50, 50, 250 },
  97. { "#Valve_Yellow", 250, 250, 50 },
  98. { "#Valve_Ltblue", 50, 250, 250 }
  99. };
  100. static const int NumCrosshairColors = sizeof( s_crosshairColors ) / sizeof( s_crosshairColors[0] );
  101. //-----------------------------------------------------------------------------
  102. class CrosshairImagePanel : public ImagePanel
  103. {
  104. typedef ImagePanel BaseClass;
  105. public:
  106. CrosshairImagePanel( Panel *parent, const char *name, CCvarToggleCheckButton *pAdditive );
  107. virtual void Paint();
  108. void UpdateCrosshair( int r, int g, int b, int size );
  109. protected:
  110. int m_R, m_G, m_B;
  111. int m_barSize;
  112. int m_barGap;
  113. CCvarToggleCheckButton *m_pAdditive;
  114. int m_iCrosshairTextureID;
  115. };
  116. //-----------------------------------------------------------------------------
  117. CrosshairImagePanel::CrosshairImagePanel( Panel *parent, const char *name, CCvarToggleCheckButton *pAdditive ) : ImagePanel( parent, name )
  118. {
  119. m_pAdditive = pAdditive;
  120. UpdateCrosshair( 50, 250, 50, 0 );
  121. m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
  122. vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, "vgui/white_additive" , true, false);
  123. }
  124. //-----------------------------------------------------------------------------
  125. void CrosshairImagePanel::UpdateCrosshair( int r, int g, int b, int size )
  126. {
  127. m_R = r;
  128. m_G = g;
  129. m_B = b;
  130. int screenWide, screenTall;
  131. surface()->GetScreenSize( screenWide, screenTall );
  132. if ( size == 0 )
  133. {
  134. if (screenWide <= 640)
  135. {
  136. // if the screen width is 640 or less, set the crosshair num to 3 (large)
  137. size = 1;
  138. }
  139. else if (screenWide < 1024)
  140. {
  141. // if the screen width is between 640 and 1024, set the crosshair num to 2 (medium)
  142. size = 2;
  143. }
  144. else
  145. {
  146. // if the screen width is 1024 or greater, set the crosshair num to 1 (small)
  147. size = 3;
  148. }
  149. }
  150. int scaleBase = 1024;
  151. switch( size )
  152. {
  153. case 3:
  154. scaleBase = 640;
  155. break;
  156. case 2:
  157. scaleBase = 800;
  158. break;
  159. default:
  160. scaleBase = 1024;
  161. break;
  162. }
  163. m_barSize = (int) 9 * screenWide / scaleBase;
  164. m_barGap = (int) 5 * screenWide / scaleBase;
  165. }
  166. //-----------------------------------------------------------------------------
  167. static void DrawCrosshairRect( int x, int y, int w, int h, bool additive )
  168. {
  169. if ( additive )
  170. {
  171. vgui::surface()->DrawTexturedRect( x, y, x+w, y+h );
  172. }
  173. else
  174. {
  175. vgui::surface()->DrawFilledRect( x, y, x+w, y+h );
  176. }
  177. }
  178. //-----------------------------------------------------------------------------
  179. void CrosshairImagePanel::Paint()
  180. {
  181. BaseClass::Paint();
  182. if ( !m_pAdditive )
  183. return;
  184. int wide, tall;
  185. GetSize( wide, tall );
  186. bool additive = m_pAdditive->IsSelected();
  187. int a = 200;
  188. if ( !additive )
  189. {
  190. ConVarRef cl_crosshairalpha( "cl_crosshairalpha" );
  191. if ( cl_crosshairalpha.IsValid() )
  192. {
  193. a = clamp( cl_crosshairalpha.GetInt(), 0, 255 );
  194. }
  195. }
  196. vgui::surface()->DrawSetColor( m_R, m_G, m_B, a );
  197. if ( additive )
  198. {
  199. vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
  200. }
  201. DrawCrosshairRect( (wide / 2 - m_barGap - m_barSize) + 1, tall / 2, m_barSize, 1, additive );
  202. DrawCrosshairRect( wide / 2 + m_barGap, tall / 2, m_barSize, 1, additive );
  203. DrawCrosshairRect( wide / 2, tall / 2 - m_barGap - m_barSize, 1, m_barSize, additive );
  204. DrawCrosshairRect( wide / 2, tall / 2 + m_barGap, 1, m_barSize, additive );
  205. }
  206. //-----------------------------------------------------------------------------
  207. class AdvancedCrosshairImagePanel : public ImagePanel
  208. {
  209. typedef ImagePanel BaseClass;
  210. public:
  211. AdvancedCrosshairImagePanel( Panel *parent, const char *name );
  212. virtual ~AdvancedCrosshairImagePanel();
  213. virtual void Paint();
  214. void UpdateCrosshair( int r, int g, int b, float scale, const char *crosshairname );
  215. protected:
  216. int m_R, m_G, m_B;
  217. float m_flScale;
  218. // material
  219. int m_iCrosshairTextureID;
  220. IVguiMatInfo *m_pAdvCrosshair;
  221. // animation
  222. IVguiMatInfoVar *m_pFrameVar;
  223. float m_flNextFrameChange;
  224. int m_nNumFrames;
  225. bool m_bAscending; // animating forward or in reverse?
  226. };
  227. //-----------------------------------------------------------------------------
  228. AdvancedCrosshairImagePanel::AdvancedCrosshairImagePanel( Panel *parent, const char *name ) : ImagePanel( parent, name )
  229. {
  230. m_pAdvCrosshair = NULL;
  231. m_pFrameVar = NULL;
  232. if ( ModInfo().AdvCrosshair() )
  233. {
  234. m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
  235. UpdateCrosshair( 50, 250, 50, 32.0, "vgui/crosshairs/crosshair1" );
  236. }
  237. }
  238. AdvancedCrosshairImagePanel::~AdvancedCrosshairImagePanel()
  239. {
  240. if ( m_pFrameVar )
  241. {
  242. delete m_pFrameVar;
  243. m_pFrameVar = NULL;
  244. }
  245. if ( m_pAdvCrosshair )
  246. {
  247. delete m_pAdvCrosshair;
  248. m_pAdvCrosshair = NULL;
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. void AdvancedCrosshairImagePanel::UpdateCrosshair( int r, int g, int b, float scale, const char *crosshairname )
  253. {
  254. m_R = r;
  255. m_G = g;
  256. m_B = b;
  257. m_flScale = scale;
  258. vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, crosshairname, true, false );
  259. if ( m_pAdvCrosshair )
  260. {
  261. delete m_pAdvCrosshair;
  262. }
  263. m_pAdvCrosshair = vgui::surface()->DrawGetTextureMatInfoFactory( m_iCrosshairTextureID );
  264. Assert(m_pAdvCrosshair);
  265. m_pFrameVar = m_pAdvCrosshair->FindVarFactory( "$frame", NULL );
  266. m_nNumFrames = m_pAdvCrosshair->GetNumAnimationFrames();
  267. m_flNextFrameChange = system()->GetFrameTime() + 0.2;
  268. m_bAscending = true;
  269. }
  270. //-----------------------------------------------------------------------------
  271. void AdvancedCrosshairImagePanel::Paint()
  272. {
  273. BaseClass::Paint();
  274. int wide, tall;
  275. GetSize( wide, tall );
  276. int iClipX0, iClipY0, iClipX1, iClipY1;
  277. ipanel()->GetClipRect(GetVPanel(), iClipX0, iClipY0, iClipX1, iClipY1 );
  278. // scroll through all frames
  279. if ( m_pFrameVar )
  280. {
  281. float curtime = system()->GetFrameTime();
  282. if ( curtime >= m_flNextFrameChange )
  283. {
  284. m_flNextFrameChange = curtime + 0.2;
  285. int frame = m_pFrameVar->GetIntValue();
  286. if ( m_bAscending )
  287. {
  288. frame++;
  289. if ( frame >= m_nNumFrames )
  290. {
  291. m_bAscending = !m_bAscending;
  292. frame--;
  293. }
  294. }
  295. else
  296. {
  297. frame--;
  298. if ( frame < 0 )
  299. {
  300. m_bAscending = !m_bAscending;
  301. frame++;
  302. }
  303. }
  304. m_pFrameVar->SetIntValue(frame);
  305. }
  306. }
  307. float x, y;
  308. // assume square
  309. float flDrawWidth = ( m_flScale/48.0 ) * (float)wide;
  310. int flHalfWidth = (int)( flDrawWidth / 2 );
  311. x = wide/2 - flHalfWidth;
  312. y = tall/2 - flHalfWidth;
  313. vgui::surface()->DrawSetColor( m_R, m_G, m_B, 255 );
  314. vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
  315. vgui::surface()->DrawTexturedRect( x, y, x+flDrawWidth, y+flDrawWidth );
  316. vgui::surface()->DrawSetTexture(0);
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Basic help dialog
  320. //-----------------------------------------------------------------------------
  321. COptionsSubMultiplayer::COptionsSubMultiplayer(vgui::Panel *parent) : vgui::PropertyPage(parent, "OptionsSubMultiplayer")
  322. {
  323. Button *cancel = new Button( this, "Cancel", "#GameUI_Cancel" );
  324. cancel->SetCommand( "Close" );
  325. Button *ok = new Button( this, "OK", "#GameUI_OK" );
  326. ok->SetCommand( "Ok" );
  327. Button *apply = new Button( this, "Apply", "#GameUI_Apply" );
  328. apply->SetCommand( "Apply" );
  329. Button *advanced = new Button( this, "Advanced", "#GameUI_AdvancedEllipsis" );
  330. advanced->SetCommand( "Advanced" );
  331. Button *importSprayImage = new Button( this, "ImportSprayImage", "#GameUI_ImportSprayEllipsis" );
  332. importSprayImage->SetCommand("ImportSprayImage");
  333. m_hImportSprayDialog = NULL;
  334. m_pPrimaryColorSlider = new CCvarSlider( this, "Primary Color Slider", "#GameUI_PrimaryColor",
  335. 0.0f, 255.0f, "topcolor" );
  336. m_pSecondaryColorSlider = new CCvarSlider( this, "Secondary Color Slider", "#GameUI_SecondaryColor",
  337. 0.0f, 255.0f, "bottomcolor" );
  338. m_pHighQualityModelCheckBox = new CCvarToggleCheckButton( this, "High Quality Models", "#GameUI_HighModels", "cl_himodels" );
  339. m_pModelList = new CLabeledCommandComboBox( this, "Player model" );
  340. m_ModelName[0] = 0;
  341. InitModelList( m_pModelList );
  342. m_pLogoList = new CLabeledCommandComboBox( this, "SpraypaintList" );
  343. m_LogoName[0] = 0;
  344. InitLogoList( m_pLogoList );
  345. m_pModelImage = new CBitmapImagePanel( this, "ModelImage", NULL );
  346. m_pModelImage->AddActionSignalTarget( this );
  347. m_pLogoImage = new ImagePanel( this, "LogoImage" );
  348. m_pLogoImage->AddActionSignalTarget( this );
  349. m_nTopColor = DEFAULT_SUIT_HUE;
  350. m_nBottomColor = DEFAULT_PLATE_HUE;
  351. m_nLogoR = 255;
  352. m_nLogoG = 255;
  353. m_nLogoB = 255;
  354. // crosshair controls
  355. m_pCrosshairColorComboBox = new ComboBox(this, "CrosshairColorComboBox", 6, false);
  356. m_pCrosshairSize = new CLabeledCommandComboBox(this, "CrosshairSizeComboBox");
  357. m_pCrosshairTranslucencyCheckbox = new CCvarToggleCheckButton(this, "CrosshairTranslucencyCheckbox", "#GameUI_Translucent", "cl_crosshairusealpha");
  358. m_pCrosshairImage = new CrosshairImagePanel( this, "CrosshairImage", m_pCrosshairTranslucencyCheckbox );
  359. // advanced crosshair controls
  360. //==========
  361. m_pAdvCrosshairRedSlider = new CCvarSlider( this, "Red Color Slider", "#GameUI_CrosshairColor_Red",
  362. 0.0f, 255.0f, "cl_crosshair_red" );
  363. m_pAdvCrosshairGreenSlider = new CCvarSlider( this, "Green Color Slider", "#GameUI_CrosshairColor_Green",
  364. 0.0f, 255.0f, "cl_crosshair_green" );
  365. m_pAdvCrosshairBlueSlider = new CCvarSlider( this, "Blue Color Slider", "#GameUI_CrosshairColor_Blue",
  366. 0.0f, 255.0f, "cl_crosshair_blue" );
  367. m_pAdvCrosshairScaleSlider = new CCvarSlider( this, "Scale Slider", "#GameUI_CrosshairScale",
  368. 16.0f, 48.0f, "cl_crosshair_scale" );
  369. m_pAdvCrosshairRedSlider->AddActionSignalTarget( this );
  370. m_pAdvCrosshairGreenSlider->AddActionSignalTarget( this );
  371. m_pAdvCrosshairBlueSlider->AddActionSignalTarget( this );
  372. m_pAdvCrosshairScaleSlider->AddActionSignalTarget( this );
  373. m_pAdvCrosshairStyle = new CLabeledCommandComboBox( this, "AdvCrosshairList" );
  374. m_pAdvCrosshairImage = new AdvancedCrosshairImagePanel( this, "AdvCrosshairImage" );
  375. InitAdvCrosshairStyleList(m_pAdvCrosshairStyle);
  376. RedrawAdvCrosshairImage();
  377. //=========
  378. m_pDownloadFilterCombo = new ComboBox( this, "DownloadFilterCheck", 3, false );
  379. m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_ALL", NULL );
  380. m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_NoSounds", NULL );
  381. m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_None", NULL );
  382. //=========
  383. LoadControlSettings("Resource/OptionsSubMultiplayer.res");
  384. InitCrosshairColorEntries();
  385. InitCrosshairSizeList(m_pCrosshairSize);
  386. RedrawCrosshairImage();
  387. // turn off the crosshair stuff if the mod specifies "nocrosshair" in the gameinfo.txt file
  388. if ( ModInfo().NoCrosshair() )
  389. {
  390. m_pCrosshairColorComboBox->SetVisible( false );
  391. m_pCrosshairSize->SetVisible( false );
  392. m_pCrosshairTranslucencyCheckbox->SetVisible( false );
  393. m_pCrosshairImage->SetVisible( false );
  394. Panel *pTempPanel = NULL;
  395. // #GameUI_CrosshairDescription (from "Resource/OptionsSubMultiplayer.res")
  396. pTempPanel = FindChildByName( "CrosshairLabel" );
  397. if ( pTempPanel )
  398. {
  399. pTempPanel->SetVisible( false );
  400. }
  401. }
  402. // turn off model selection stuff if the mod specifies "nomodels" in the gameinfo.txt file
  403. if ( ModInfo().NoModels() )
  404. {
  405. Panel *pTempPanel = NULL;
  406. if ( m_pModelImage )
  407. {
  408. m_pModelImage->SetVisible( false );
  409. }
  410. if ( m_pModelList )
  411. {
  412. m_pModelList->SetVisible( false );
  413. }
  414. if ( m_pPrimaryColorSlider )
  415. {
  416. m_pPrimaryColorSlider->SetVisible( false );
  417. }
  418. if ( m_pSecondaryColorSlider )
  419. {
  420. m_pSecondaryColorSlider->SetVisible( false );
  421. }
  422. // #GameUI_PlayerModel (from "Resource/OptionsSubMultiplayer.res")
  423. pTempPanel = FindChildByName( "Label1" );
  424. if ( pTempPanel )
  425. {
  426. pTempPanel->SetVisible( false );
  427. }
  428. // #GameUI_ColorSliders (from "Resource/OptionsSubMultiplayer.res")
  429. pTempPanel = FindChildByName( "Colors" );
  430. if ( pTempPanel )
  431. {
  432. pTempPanel->SetVisible( false );
  433. }
  434. }
  435. // turn off the himodel stuff if the mod specifies "nohimodel" in the gameinfo.txt file
  436. if ( ModInfo().NoHiModel() )
  437. {
  438. if ( m_pHighQualityModelCheckBox )
  439. {
  440. m_pHighQualityModelCheckBox->SetVisible( false );
  441. }
  442. }
  443. // Advanced crosshair selection
  444. if ( !ModInfo().AdvCrosshair() )
  445. {
  446. m_pAdvCrosshairImage->SetVisible( false );
  447. m_pAdvCrosshairRedSlider->SetVisible( false );
  448. m_pAdvCrosshairBlueSlider->SetVisible( false );
  449. m_pAdvCrosshairGreenSlider->SetVisible( false );
  450. m_pAdvCrosshairScaleSlider->SetVisible( false );
  451. m_pAdvCrosshairStyle->SetVisible( false );
  452. Panel *pTempPanel = NULL;
  453. // #GameUI_AdvCrosshairDescription (from "Resource/OptionsSubMultiplayer.res")
  454. pTempPanel = FindChildByName( "AdvCrosshairLabel" );
  455. if ( pTempPanel )
  456. {
  457. pTempPanel->SetVisible( false );
  458. }
  459. }
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Purpose:
  463. //-----------------------------------------------------------------------------
  464. COptionsSubMultiplayer::~COptionsSubMultiplayer()
  465. {
  466. }
  467. //-----------------------------------------------------------------------------
  468. // Purpose:
  469. //-----------------------------------------------------------------------------
  470. void COptionsSubMultiplayer::OnCommand( const char *command )
  471. {
  472. if ( !stricmp( command, "Advanced" ) )
  473. {
  474. if (!m_hMultiplayerAdvancedDialog.Get())
  475. {
  476. m_hMultiplayerAdvancedDialog = new CMultiplayerAdvancedDialog( this );
  477. }
  478. m_hMultiplayerAdvancedDialog->Activate();
  479. }
  480. else if (!stricmp( command, "ImportSprayImage" ) )
  481. {
  482. if (m_hImportSprayDialog == NULL)
  483. {
  484. m_hImportSprayDialog = new FileOpenDialog(NULL, "#GameUI_ImportSprayImage", true);
  485. m_hImportSprayDialog->AddFilter("*.tga,*.jpg,*.bmp,*.vtf", "#GameUI_All_Images", true);
  486. m_hImportSprayDialog->AddFilter("*.tga", "#GameUI_TGA_Images", false);
  487. m_hImportSprayDialog->AddFilter("*.jpg", "#GameUI_JPEG_Images", false);
  488. m_hImportSprayDialog->AddFilter("*.bmp", "#GameUI_BMP_Images", false);
  489. m_hImportSprayDialog->AddFilter("*.vtf", "#GameUI_VTF_Images", false);
  490. m_hImportSprayDialog->AddActionSignalTarget(this);
  491. }
  492. m_hImportSprayDialog->DoModal(false);
  493. m_hImportSprayDialog->Activate();
  494. }
  495. BaseClass::OnCommand( command );
  496. }
  497. // file selected. This can only happen when someone selects an image to be imported as a spray logo.
  498. void COptionsSubMultiplayer::OnFileSelected(const char *fullpath)
  499. {
  500. if ((fullpath == NULL) || (fullpath[0] == 0))
  501. {
  502. return;
  503. }
  504. ConversionErrorType errcode;
  505. // this can take a while, put up a waiting cursor
  506. surface()->SetCursor(dc_hourglass);
  507. // get the extension of the file we're to convert
  508. char extension[MAX_PATH];
  509. const char *constchar = fullpath + strlen(fullpath);
  510. while ((constchar > fullpath) && (*(constchar-1) != '.'))
  511. {
  512. --constchar;
  513. }
  514. Q_strncpy(extension, constchar, MAX_PATH);
  515. bool deleteIntermediateTGA = false;
  516. bool deleteIntermediateVTF = false;
  517. bool convertTGAToVTF = true;
  518. char tgaPath[MAX_PATH*2];
  519. char *c;
  520. bool failed = false;
  521. Q_strncpy(tgaPath, fullpath, sizeof(tgaPath));
  522. if (stricmp(extension, "tga"))
  523. {
  524. // construct a .tga version of this file path.
  525. c = tgaPath + strlen(tgaPath);
  526. while ((c > tgaPath) && (*(c-1) != '\\') && (*(c-1) != '/'))
  527. {
  528. --c;
  529. }
  530. *c = 0;
  531. char origpath[MAX_PATH*2];
  532. Q_strncpy(origpath, tgaPath, sizeof(origpath));
  533. int index = 0;
  534. // dgoodenough - remove this section on PS3 since we don't have a filesystem _access(...) function yet
  535. // PS3_BUILDFIX
  536. // FIXME FIXME FIXME
  537. #if !defined( _PS3 )
  538. do {
  539. Q_snprintf(tgaPath, sizeof(tgaPath), "%stemp%d.tga", origpath, index);
  540. ++index;
  541. } while (_access(tgaPath, 0) != -1);
  542. #endif
  543. if (!stricmp(extension, "jpg") || !stricmp(extension, "jpeg"))
  544. {
  545. // convert from the jpeg file format to the TGA file format
  546. errcode = ConvertJPEGToTGA(fullpath, tgaPath);
  547. if (errcode == CE_SUCCESS)
  548. {
  549. deleteIntermediateTGA = true;
  550. }
  551. else
  552. {
  553. failed = true;
  554. vgui::MessageBox *errorDialog = NULL;
  555. if (errcode == CE_MEMORY_ERROR)
  556. {
  557. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Memory");
  558. }
  559. else if (errcode == CE_CANT_OPEN_SOURCE_FILE)
  560. {
  561. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Reading_Image");
  562. }
  563. else if (errcode == CE_ERROR_PARSING_SOURCE)
  564. {
  565. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Image_File_Corrupt");
  566. }
  567. else if (errcode == CE_ERROR_WRITING_OUTPUT_FILE)
  568. {
  569. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Writing_Temp_Output");
  570. }
  571. else if (errcode == CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED )
  572. {
  573. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Image_Wrong_Size");
  574. }
  575. if (errorDialog != NULL)
  576. {
  577. errorDialog->DoModal();
  578. }
  579. }
  580. }
  581. else if (!stricmp(extension, "bmp"))
  582. {
  583. // convert from the bmp file format to the TGA file format
  584. errcode = ConvertBMPToTGA(fullpath, tgaPath);
  585. if (errcode == CE_SUCCESS)
  586. {
  587. deleteIntermediateTGA = true;
  588. }
  589. else
  590. {
  591. failed = true;
  592. vgui::MessageBox *errorDialog = NULL;
  593. if (errcode == CE_MEMORY_ERROR)
  594. {
  595. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Memory");
  596. }
  597. else if (errcode == CE_CANT_OPEN_SOURCE_FILE)
  598. {
  599. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Reading_Image");
  600. }
  601. else if (errcode == CE_ERROR_PARSING_SOURCE)
  602. {
  603. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Image_File_Corrupt");
  604. }
  605. else if (errcode == CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED)
  606. {
  607. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_BMP_Format_Not_Supported");
  608. }
  609. else if (errcode == CE_ERROR_WRITING_OUTPUT_FILE)
  610. {
  611. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Writing_Temp_Output");
  612. }
  613. if (errorDialog != NULL)
  614. {
  615. errorDialog->DoModal();
  616. }
  617. }
  618. }
  619. else if (!stricmp(extension, "vtf"))
  620. {
  621. // if the file is already in the vtf format there's no need to convert it.
  622. convertTGAToVTF = false;
  623. }
  624. }
  625. if (convertTGAToVTF && !failed)
  626. {
  627. // convert the TGA file to the VTF format.
  628. errcode = ConvertTGA(tgaPath); // resize TGA so that it has power-of-two dimensions with a max size of 256x256.
  629. if (errcode != CE_SUCCESS)
  630. {
  631. failed = true;
  632. vgui::MessageBox *errorDialog = NULL;
  633. if (errcode == CE_MEMORY_ERROR)
  634. {
  635. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Memory");
  636. }
  637. else if (errcode == CE_CANT_OPEN_SOURCE_FILE)
  638. {
  639. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Reading_Image");
  640. }
  641. else if (errcode == CE_ERROR_PARSING_SOURCE)
  642. {
  643. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Image_File_Corrupt");
  644. }
  645. else if (errcode == CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED)
  646. {
  647. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_TGA_Format_Not_Supported");
  648. }
  649. else if (errcode == CE_ERROR_WRITING_OUTPUT_FILE)
  650. {
  651. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Writing_Temp_Output");
  652. }
  653. if (errorDialog != NULL)
  654. {
  655. errorDialog->DoModal();
  656. }
  657. }
  658. if (!failed)
  659. {
  660. char tempPath[MAX_PATH*2];
  661. Q_strncpy(tempPath, tgaPath, sizeof(tempPath));
  662. errcode = ConvertTGAToVTF(tempPath);
  663. if (errcode == CE_SUCCESS)
  664. {
  665. deleteIntermediateVTF = true;
  666. }
  667. else
  668. {
  669. failed = true;
  670. vgui::MessageBox *errorDialog = NULL;
  671. if (errcode == CE_MEMORY_ERROR)
  672. {
  673. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Memory");
  674. }
  675. else if (errcode == CE_CANT_OPEN_SOURCE_FILE)
  676. {
  677. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Reading_Image");
  678. }
  679. else if (errcode == CE_ERROR_PARSING_SOURCE)
  680. {
  681. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Image_File_Corrupt");
  682. }
  683. else if (errcode == CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED)
  684. {
  685. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_TGA_Format_Not_Supported");
  686. }
  687. else if (errcode == CE_ERROR_WRITING_OUTPUT_FILE)
  688. {
  689. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Writing_Temp_Output");
  690. }
  691. else if (errcode == CE_ERROR_LOADING_DLL)
  692. {
  693. errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Cant_Load_VTEX_DLL");
  694. }
  695. if (errorDialog != NULL)
  696. {
  697. errorDialog->DoModal();
  698. }
  699. }
  700. }
  701. }
  702. char finalPath[MAX_PATH*2];
  703. finalPath[0] = 0;
  704. char vtfPath[MAX_PATH*2];
  705. vtfPath[0] = 0;
  706. if (!failed)
  707. {
  708. Q_strncpy(vtfPath, tgaPath, sizeof(vtfPath));
  709. // rename the tga file to be a vtf file.
  710. c = vtfPath + strlen(vtfPath);
  711. while ((c > vtfPath) && (*(c-1) != '.'))
  712. {
  713. --c;
  714. }
  715. *c = 0;
  716. Q_strncat(vtfPath, "vtf", sizeof(vtfPath), COPY_ALL_CHARACTERS);
  717. // get the vtfFilename from the path.
  718. const char *vtfFilename = fullpath + strlen(fullpath);
  719. while ((vtfFilename > fullpath) && (*(vtfFilename-1) != '\\') && (*(vtfFilename-1) != '/'))
  720. {
  721. --vtfFilename;
  722. }
  723. Q_strncpy(finalPath, engine->GetGameDirectory(), sizeof(finalPath));
  724. Q_strncat(finalPath, "\\materials\\VGUI\\logos\\", sizeof(finalPath), COPY_ALL_CHARACTERS);
  725. Q_strncat(finalPath, vtfFilename, sizeof(finalPath), COPY_ALL_CHARACTERS);
  726. c = finalPath + strlen(finalPath);
  727. while ((c > finalPath) && (*(c-1) != '.'))
  728. {
  729. --c;
  730. }
  731. *c = 0;
  732. Q_strncat(finalPath,"vtf", sizeof(finalPath), COPY_ALL_CHARACTERS);
  733. // make sure the directory exists before we try to copy the file.
  734. g_pFullFileSystem->CreateDirHierarchy("materials/VGUI/logos/", "GAME");
  735. // write out the spray VMT file.
  736. errcode = WriteSprayVMT(finalPath);
  737. if (errcode != CE_SUCCESS)
  738. {
  739. failed = true;
  740. vgui::MessageBox *errorDialog = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", "#GameUI_Spray_Import_Error_Writing_Output");
  741. errorDialog->DoModal();
  742. }
  743. if (!failed)
  744. {
  745. // copy vtf file to the final location.
  746. #ifdef WIN32
  747. CopyFile(vtfPath, finalPath, true);
  748. #elif defined( OSX )
  749. copyfile( vtfPath, finalPath, 0, 0 );
  750. #elif !defined( _PS3 )
  751. engine->CopyLocalFile( vtfPath, finalPath );
  752. #endif
  753. // refresh the logo list so the new spray shows up.
  754. InitLogoList(m_pLogoList);
  755. char rootFilename[MAX_PATH];
  756. Q_strncpy(rootFilename, vtfFilename, MAX_PATH);
  757. // get the root filename so we can select in the spray list.
  758. rootFilename[strlen(rootFilename) - 4] = 0;
  759. // automatically select the logo that was just imported.
  760. SelectLogo(rootFilename);
  761. }
  762. }
  763. // delete the intermediate VTF file if one was made.
  764. if (deleteIntermediateVTF)
  765. {
  766. // dgoodenough - DeleteFile is Win32 specific, remove it for PS3 build
  767. // PS3_BUILDFIX
  768. // FIXME - How will this be handled on PS3?
  769. #if !defined( _PS3 )
  770. DeleteFile(vtfPath);
  771. #endif
  772. // the TGA->VTF conversion process generates a .txt file if one wasn't already there.
  773. // in this case, delete the .txt file.
  774. c = vtfPath + strlen(vtfPath);
  775. while ((c > vtfPath) && (*(c-1) != '.'))
  776. {
  777. --c;
  778. }
  779. Q_strncpy(c, "txt", sizeof(vtfPath)-(c-vtfPath));
  780. // dgoodenough - DeleteFile is Win32 specific, remove it for PS3 build
  781. // PS3_BUILDFIX
  782. // FIXME - How will this be handled on PS3?
  783. #if !defined( _PS3 )
  784. DeleteFile(vtfPath);
  785. #endif
  786. }
  787. // delete the intermediate TGA file if one was made.
  788. if (deleteIntermediateTGA)
  789. {
  790. // dgoodenough - DeleteFile is Win32 specific, remove it for PS3 build
  791. // PS3_BUILDFIX
  792. // FIXME - How will this be handled on PS3?
  793. #if !defined( _PS3 )
  794. DeleteFile(tgaPath);
  795. #endif
  796. }
  797. // change the cursor back to normal
  798. surface()->SetCursor(dc_user);
  799. }
  800. struct ValveJpegErrorHandler_t
  801. {
  802. // The default manager
  803. struct jpeg_error_mgr m_Base;
  804. // For handling any errors
  805. jmp_buf m_ErrorContext;
  806. };
  807. //-----------------------------------------------------------------------------
  808. // Purpose: We'll override the default error handler so we can deal with errors without having to exit the engine
  809. //-----------------------------------------------------------------------------
  810. static void ValveJpegErrorHandler( j_common_ptr cinfo )
  811. {
  812. ValveJpegErrorHandler_t *pError = reinterpret_cast< ValveJpegErrorHandler_t * >( cinfo->err );
  813. char buffer[ JMSG_LENGTH_MAX ];
  814. /* Create the message */
  815. ( *cinfo->err->format_message )( cinfo, buffer );
  816. Warning( "%s\n", buffer );
  817. // Bail
  818. longjmp( pError->m_ErrorContext, 1 );
  819. }
  820. // convert the JPEG file given to a TGA file at the given output path.
  821. ConversionErrorType COptionsSubMultiplayer::ConvertJPEGToTGA(const char *jpegpath, const char *tgaPath)
  822. {
  823. #if !defined( _GAMECONSOLE )
  824. struct jpeg_decompress_struct jpegInfo;
  825. struct ValveJpegErrorHandler_t jerr;
  826. JSAMPROW row_pointer[1];
  827. int row_stride;
  828. int cur_row = 0;
  829. // image attributes
  830. int image_height;
  831. int image_width;
  832. // open the jpeg image file.
  833. FILE *infile = fopen(jpegpath, "rb");
  834. if (infile == NULL)
  835. {
  836. return CE_CANT_OPEN_SOURCE_FILE;
  837. }
  838. // setup error to print to stderr.
  839. jpegInfo.err = jpeg_std_error(&jerr.m_Base);
  840. jpegInfo.err->error_exit = &ValveJpegErrorHandler;
  841. // create the decompress struct.
  842. jpeg_create_decompress(&jpegInfo);
  843. if ( setjmp( jerr.m_ErrorContext ) )
  844. {
  845. // Get here if there is any error
  846. jpeg_destroy_decompress( &jpegInfo );
  847. fclose(infile);
  848. return CE_ERROR_PARSING_SOURCE;
  849. }
  850. jpeg_stdio_src(&jpegInfo, infile);
  851. // read in the jpeg header and make sure that's all good.
  852. if (jpeg_read_header(&jpegInfo, TRUE) != JPEG_HEADER_OK)
  853. {
  854. fclose(infile);
  855. return CE_ERROR_PARSING_SOURCE;
  856. }
  857. // start the decompress with the jpeg engine.
  858. if (jpeg_start_decompress(&jpegInfo) != TRUE)
  859. {
  860. jpeg_destroy_decompress(&jpegInfo);
  861. fclose(infile);
  862. return CE_ERROR_PARSING_SOURCE;
  863. }
  864. // Check for valid width and height (ie. power of 2 and print out an error and exit if not).
  865. if ( !IsPowerOfTwo( jpegInfo.image_height ) || !IsPowerOfTwo( jpegInfo.image_width ) )
  866. {
  867. jpeg_destroy_decompress(&jpegInfo);
  868. fclose( infile );
  869. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  870. }
  871. // now that we've started the decompress with the jpeg lib, we have the attributes of the
  872. // image ready to be read out of the decompress struct.
  873. row_stride = jpegInfo.output_width * jpegInfo.output_components;
  874. image_height = jpegInfo.image_height;
  875. image_width = jpegInfo.image_width;
  876. int mem_required = jpegInfo.image_height * jpegInfo.image_width * jpegInfo.output_components;
  877. // allocate the memory to read the image data into.
  878. unsigned char *buf = (unsigned char *)malloc(mem_required);
  879. if (buf == NULL)
  880. {
  881. jpeg_destroy_decompress(&jpegInfo);
  882. fclose(infile);
  883. return CE_MEMORY_ERROR;
  884. }
  885. // read in all the scan lines of the image into our image data buffer.
  886. bool working = true;
  887. while (working && (jpegInfo.output_scanline < jpegInfo.output_height))
  888. {
  889. row_pointer[0] = &(buf[cur_row * row_stride]);
  890. if (jpeg_read_scanlines(&jpegInfo, row_pointer, 1) != TRUE)
  891. {
  892. working = false;
  893. }
  894. ++cur_row;
  895. }
  896. if (!working)
  897. {
  898. free(buf);
  899. jpeg_destroy_decompress(&jpegInfo);
  900. fclose(infile);
  901. return CE_ERROR_PARSING_SOURCE;
  902. }
  903. jpeg_finish_decompress(&jpegInfo);
  904. fclose(infile);
  905. // ok, at this point we have read in the JPEG image to our buffer, now we need to write it out as a TGA file.
  906. CUtlBuffer outBuf;
  907. bool bRetVal = TGAWriter::WriteToBuffer( buf, outBuf, image_width, image_height, IMAGE_FORMAT_RGB888, IMAGE_FORMAT_RGB888 );
  908. if ( bRetVal )
  909. {
  910. if ( !g_pFullFileSystem->WriteFile( tgaPath, NULL, outBuf ) )
  911. {
  912. bRetVal = false;
  913. }
  914. }
  915. free(buf);
  916. return bRetVal ? CE_SUCCESS : CE_ERROR_WRITING_OUTPUT_FILE;
  917. #else
  918. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  919. #endif
  920. }
  921. // convert the bmp file given to a TGA file at the given destination path.
  922. ConversionErrorType COptionsSubMultiplayer::ConvertBMPToTGA(const char *bmpPath, const char *tgaPath)
  923. {
  924. if ( !IsPC() )
  925. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  926. // @wge TODO FIXME - fix OSX build
  927. #if defined( _OSX ) || defined (LINUX)
  928. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  929. #else
  930. HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, bmpPath, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_DEFAULTSIZE);
  931. BITMAP bitmap;
  932. GetObject(hBitmap, sizeof(bitmap), &bitmap);
  933. BITMAPINFO *bitmapInfo;
  934. if (bitmap.bmBitsPixel == 24)
  935. {
  936. bitmapInfo = (BITMAPINFO *)malloc(sizeof(BITMAPINFO));
  937. }
  938. else
  939. {
  940. int colorsUsed = 1 << bitmap.bmBitsPixel;
  941. bitmapInfo = (BITMAPINFO *)malloc(colorsUsed * sizeof(RGBQUAD) + sizeof(BITMAPINFO));
  942. }
  943. memset(bitmapInfo, 0, sizeof(BITMAPINFO));
  944. bitmapInfo->bmiHeader.biSize = sizeof(bitmapInfo->bmiHeader);
  945. if (bitmap.bmBitsPixel != 24)
  946. {
  947. bitmapInfo->bmiHeader.biBitCount = bitmap.bmBitsPixel; // need to specify the bits per pixel so GDI will generate a color table for us.
  948. }
  949. HDC dc = CreateCompatibleDC(NULL);
  950. int retcode = GetDIBits(dc, hBitmap, 0, bitmap.bmHeight, NULL, bitmapInfo, DIB_RGB_COLORS);
  951. DeleteDC(dc);
  952. if (retcode == 0)
  953. {
  954. // error getting the bitmap info for some reason.
  955. free(bitmapInfo);
  956. return CE_ERROR_PARSING_SOURCE;
  957. }
  958. int mem_required = 3 * bitmap.bmWidth * bitmap.bmHeight; // mem required for copying the data out into RGB format.
  959. unsigned char *buf = (unsigned char *)malloc(mem_required);
  960. if (buf == NULL)
  961. {
  962. free(bitmapInfo);
  963. return CE_MEMORY_ERROR;
  964. }
  965. if (bitmapInfo->bmiHeader.biBitCount == 24)
  966. {
  967. if ((bitmap.bmWidth * 3) == bitmap.bmWidthBytes)
  968. {
  969. // 24-bit BGR color bitmap that is word aligned.
  970. memcpy(buf, bitmap.bmBits, mem_required);
  971. }
  972. else
  973. {
  974. // 24-bit BGR color bitmap that is not word aligned.
  975. // need to read it in one row at a time since it isn't word aligned.
  976. int row;
  977. for (row = 0; row < bitmap.bmHeight; ++row)
  978. {
  979. memcpy(buf + (row * 3 * bitmap.bmWidth), (unsigned char *)(bitmap.bmBits) + (row * bitmap.bmWidthBytes), 3 * bitmap.bmWidth);
  980. }
  981. }
  982. // bitmaps are loaded as BGR, need to convert it to RGB.
  983. int numPixels = bitmap.bmHeight * bitmap.bmWidth;
  984. // convert to RGB
  985. int index;
  986. for (index = 0; index < numPixels; ++index)
  987. {
  988. unsigned char blue = buf[3 * index]; // save blue value
  989. buf[3 * index] = buf[3 * index + 2]; // copy red value.
  990. buf[3 * index + 2] = blue; // copy blue value.
  991. }
  992. }
  993. else if (bitmapInfo->bmiHeader.biBitCount == 8)
  994. {
  995. // 8-bit 256 color bitmap.
  996. int y, x, index, colorTableEntry;
  997. for (y = 0; y < bitmap.bmHeight; ++y)
  998. {
  999. for (x = 0; x < bitmap.bmWidth; ++x)
  1000. {
  1001. // compute the color map entry for this pixel
  1002. index = y * bitmap.bmWidthBytes + x;
  1003. colorTableEntry = ((unsigned char *)bitmap.bmBits)[index];
  1004. // get the color for this color map entry.
  1005. RGBQUAD *rgbQuad = &(bitmapInfo->bmiColors[colorTableEntry]);
  1006. // copy the color values for this pixel to the destination buffer.
  1007. buf[(y * bitmap.bmWidth * 3) + (x * 3)] = rgbQuad->rgbRed;
  1008. buf[(y * bitmap.bmWidth * 3) + (x * 3) + 1] = rgbQuad->rgbGreen;
  1009. buf[(y * bitmap.bmWidth * 3) + (x * 3) + 2] = rgbQuad->rgbBlue;
  1010. }
  1011. }
  1012. }
  1013. else if (bitmapInfo->bmiHeader.biBitCount == 4)
  1014. {
  1015. // 4-bit 16 color bitmap.
  1016. int y, x, index, colorTableEntry;
  1017. for (y = 0; y < bitmap.bmHeight; ++y)
  1018. {
  1019. for (x = 0; x < bitmap.bmWidth; x += 2)
  1020. {
  1021. // two color table entries per byte
  1022. index = y * bitmap.bmWidthBytes + x / 2;
  1023. // get the color table entry for this pixel
  1024. colorTableEntry = (0xf0 & ((unsigned char *)bitmap.bmBits)[index]) >> 4;
  1025. // get the color values for this pixel's color table entry.
  1026. RGBQUAD *rgbQuad = &(bitmapInfo->bmiColors[colorTableEntry]);
  1027. // copy the pixel's color values to the destination buffer.
  1028. buf[(y * bitmap.bmWidth * 3) + (x * 3)] = rgbQuad->rgbRed;
  1029. buf[(y * bitmap.bmWidth * 3) + (x * 3) + 1] = rgbQuad->rgbGreen;
  1030. buf[(y * bitmap.bmWidth * 3) + (x * 3) + 2] = rgbQuad->rgbBlue;
  1031. // make sure we haven't reached the end of the row.
  1032. if ((x + 1) > bitmap.bmWidth)
  1033. {
  1034. break;
  1035. }
  1036. // get the color table entry for this pixel.
  1037. colorTableEntry = 0x0f & ((unsigned char *)bitmap.bmBits)[index];
  1038. // get the color values for this pixel's color table entry.
  1039. rgbQuad = &(bitmapInfo->bmiColors[colorTableEntry]);
  1040. // copy the pixel's color values to the destination buffer.
  1041. buf[(y * bitmap.bmWidth * 3) + ((x+1) * 3)] = rgbQuad->rgbRed;
  1042. buf[(y * bitmap.bmWidth * 3) + ((x+1) * 3) + 1] = rgbQuad->rgbGreen;
  1043. buf[(y * bitmap.bmWidth * 3) + ((x+1) * 3) + 2] = rgbQuad->rgbBlue;
  1044. }
  1045. }
  1046. }
  1047. else if (bitmapInfo->bmiHeader.biBitCount == 1)
  1048. {
  1049. // 1-bit monochrome bitmap.
  1050. int y, x, index, bit, bitMask;
  1051. for (y = 0; y < bitmap.bmHeight; ++y)
  1052. {
  1053. x = 0;
  1054. while (x < bitmap.bmWidth)
  1055. {
  1056. RGBQUAD *rgbQuad = NULL;
  1057. bitMask = 0x80;
  1058. // get the index into the bitmap data for the next 8 pixels.
  1059. index = y * bitmap.bmWidthBytes + x / 8;
  1060. // go through all 8 bits in this byte to get all 8 pixel colors.
  1061. do
  1062. {
  1063. // get the value of the bit for this pixel.
  1064. bit = ((unsigned char *)bitmap.bmBits)[index] & bitMask;
  1065. // bit will either be 0 or non-zero since there are only two colors.
  1066. if (bit == 0)
  1067. {
  1068. rgbQuad = &(bitmapInfo->bmiColors[0]);
  1069. }
  1070. else
  1071. {
  1072. rgbQuad = &(bitmapInfo->bmiColors[1]);
  1073. }
  1074. // copy this pixel's color values into the destination buffer.
  1075. buf[(y * bitmap.bmWidth * 3) + (x * 3)] = rgbQuad->rgbRed;
  1076. buf[(y * bitmap.bmWidth * 3) + (x * 3) + 1] = rgbQuad->rgbGreen;
  1077. buf[(y * bitmap.bmWidth * 3) + (x * 3) + 2] = rgbQuad->rgbBlue;
  1078. // go to the next pixel.
  1079. ++x;
  1080. bitMask = bitMask >> 1;
  1081. } while ((x < bitmap.bmWidth) && (bitMask > 0));
  1082. }
  1083. }
  1084. }
  1085. else
  1086. {
  1087. free(bitmapInfo);
  1088. free(buf);
  1089. DeleteObject(hBitmap);
  1090. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1091. }
  1092. free(bitmapInfo);
  1093. // bitmaps are stored upside down, so flip the image vertically
  1094. int index;
  1095. int rowWidth = 3 * bitmap.bmWidth;
  1096. unsigned char *row = (unsigned char *)malloc(rowWidth);
  1097. for (index = 0; index < (bitmap.bmHeight / 2); ++index)
  1098. {
  1099. memcpy(row, buf + (index * rowWidth), rowWidth);
  1100. memcpy(buf + (index * rowWidth), buf + (((bitmap.bmHeight - 1) - index) * rowWidth), rowWidth);
  1101. memcpy(buf + (((bitmap.bmHeight - 1) - index) * rowWidth), row, rowWidth);
  1102. }
  1103. // write out the TGA file using the RGB data buffer.
  1104. CUtlBuffer outBuf;
  1105. bool retval = TGAWriter::WriteToBuffer(buf, outBuf, bitmap.bmWidth, bitmap.bmHeight, IMAGE_FORMAT_RGB888, IMAGE_FORMAT_RGB888);
  1106. if ( retval )
  1107. {
  1108. if ( !g_pFullFileSystem->WriteFile( tgaPath, NULL, outBuf ) )
  1109. {
  1110. retval = false;
  1111. }
  1112. }
  1113. DeleteObject(hBitmap);
  1114. return retval ? CE_SUCCESS : CE_ERROR_WRITING_OUTPUT_FILE;
  1115. #endif // !_OSX
  1116. }
  1117. // read a TGA header from the current point in the file stream.
  1118. static void ReadTGAHeader(FILE *infile, TGAHeader &header)
  1119. {
  1120. if (infile == NULL)
  1121. {
  1122. return;
  1123. }
  1124. fread(&header.identsize, sizeof(header.identsize), 1, infile);
  1125. fread(&header.colourmaptype, sizeof(header.colourmaptype), 1, infile);
  1126. fread(&header.imagetype, sizeof(header.imagetype), 1, infile);
  1127. fread(&header.colourmapstart, sizeof(header.colourmapstart), 1, infile);
  1128. fread(&header.colourmaplength, sizeof(header.colourmaplength), 1, infile);
  1129. fread(&header.colourmapbits, sizeof(header.colourmapbits), 1, infile);
  1130. fread(&header.xstart, sizeof(header.xstart), 1, infile);
  1131. fread(&header.ystart, sizeof(header.ystart), 1, infile);
  1132. fread(&header.width, sizeof(header.width), 1, infile);
  1133. fread(&header.height, sizeof(header.height), 1, infile);
  1134. fread(&header.bits, sizeof(header.bits), 1, infile);
  1135. fread(&header.descriptor, sizeof(header.descriptor), 1, infile);
  1136. }
  1137. // write a TGA header to the current point in the file stream.
  1138. static void WriteTGAHeader(FILE *outfile, TGAHeader &header)
  1139. {
  1140. if (outfile == NULL)
  1141. {
  1142. return;
  1143. }
  1144. fwrite(&header.identsize, sizeof(header.identsize), 1, outfile);
  1145. fwrite(&header.colourmaptype, sizeof(header.colourmaptype), 1, outfile);
  1146. fwrite(&header.imagetype, sizeof(header.imagetype), 1, outfile);
  1147. fwrite(&header.colourmapstart, sizeof(header.colourmapstart), 1, outfile);
  1148. fwrite(&header.colourmaplength, sizeof(header.colourmaplength), 1, outfile);
  1149. fwrite(&header.colourmapbits, sizeof(header.colourmapbits), 1, outfile);
  1150. fwrite(&header.xstart, sizeof(header.xstart), 1, outfile);
  1151. fwrite(&header.ystart, sizeof(header.ystart), 1, outfile);
  1152. fwrite(&header.width, sizeof(header.width), 1, outfile);
  1153. fwrite(&header.height, sizeof(header.height), 1, outfile);
  1154. fwrite(&header.bits, sizeof(header.bits), 1, outfile);
  1155. fwrite(&header.descriptor, sizeof(header.descriptor), 1, outfile);
  1156. }
  1157. // reads in a TGA file and converts it to 32 bit RGBA color values in a memory buffer.
  1158. unsigned char * COptionsSubMultiplayer::ReadTGAAsRGBA(const char *tgaPath, int &width, int &height, ConversionErrorType &errcode, TGAHeader &tgaHeader )
  1159. {
  1160. FILE *tgaFile = fopen(tgaPath, "rb");
  1161. if (tgaFile == NULL)
  1162. {
  1163. errcode = CE_CANT_OPEN_SOURCE_FILE;
  1164. return NULL;
  1165. }
  1166. // read header for TGA file.
  1167. ReadTGAHeader(tgaFile, tgaHeader);
  1168. // image type 2 is RGB, other types not supported.
  1169. if (tgaHeader.imagetype != 2)
  1170. {
  1171. fclose(tgaFile);
  1172. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1173. return NULL;
  1174. }
  1175. int tgaDataSize = tgaHeader.width * tgaHeader.height * tgaHeader.bits / 8;
  1176. unsigned char *tgaData = (unsigned char *)malloc(tgaDataSize);
  1177. if (tgaData == NULL)
  1178. {
  1179. fclose(tgaFile);
  1180. errcode = CE_MEMORY_ERROR;
  1181. return NULL;
  1182. }
  1183. fread(tgaData, 1, tgaDataSize, tgaFile);
  1184. fclose(tgaFile);
  1185. width = tgaHeader.width;
  1186. height = tgaHeader.height;
  1187. if (tgaHeader.bits == 24)
  1188. {
  1189. // image needs to be converted to a 32-bit image.
  1190. int numPixels = tgaHeader.width * tgaHeader.height;
  1191. unsigned char *retBuf = (unsigned char *)malloc(numPixels * 4);
  1192. if (retBuf == NULL)
  1193. {
  1194. free(tgaData);
  1195. errcode = CE_MEMORY_ERROR;
  1196. return NULL;
  1197. }
  1198. // convert from RGB to RGBA color format.
  1199. int index;
  1200. for (index = 0; index < numPixels; ++index)
  1201. {
  1202. retBuf[index * 4] = tgaData[index * 3];
  1203. retBuf[index * 4 + 1] = tgaData[index * 3 + 1];
  1204. retBuf[index * 4 + 2] = tgaData[index * 3 + 2];
  1205. retBuf[index * 4 + 3] = 0xff;
  1206. }
  1207. free(tgaData);
  1208. tgaHeader.bits = 32;
  1209. errcode = CE_SUCCESS;
  1210. return retBuf;
  1211. }
  1212. else if (tgaHeader.bits == 32)
  1213. {
  1214. // already in RGBA format so just return it.
  1215. errcode = CE_SUCCESS;
  1216. return tgaData;
  1217. }
  1218. // format not supported, fail.
  1219. free(tgaData);
  1220. errcode = CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1221. return NULL;
  1222. }
  1223. // resizes the file specified by tgaPath so that it has dimensions that are
  1224. // powers-of-two and is equal to or smaller than 256x256.
  1225. // also converts from 24-bit RGB to 32-bit RGB (with 8-bit alpha)
  1226. ConversionErrorType COptionsSubMultiplayer::ConvertTGA(const char *tgaPath)
  1227. {
  1228. int tgaWidth = 0, tgaHeight = 0;
  1229. ConversionErrorType errcode;
  1230. TGAHeader tgaHeader;
  1231. unsigned char *srcBuffer = ReadTGAAsRGBA(tgaPath, tgaWidth, tgaHeight, errcode, tgaHeader);
  1232. if (srcBuffer == NULL)
  1233. {
  1234. return errcode;
  1235. }
  1236. int paddedImageWidth, paddedImageHeight;
  1237. if ((tgaWidth <= 0) || (tgaHeight <= 0))
  1238. {
  1239. free(srcBuffer);
  1240. return CE_ERROR_PARSING_SOURCE;
  1241. }
  1242. // get the nearest power of two that is greater than the width of the image.
  1243. paddedImageWidth = tgaWidth;
  1244. if (!IsPowerOfTwo(paddedImageWidth))
  1245. {
  1246. // width is not a power of two, calculate the next highest power of two value.
  1247. int i = 1;
  1248. while (paddedImageWidth > 1)
  1249. {
  1250. paddedImageWidth = paddedImageWidth >> 1;
  1251. ++i;
  1252. }
  1253. paddedImageWidth = paddedImageWidth << i;
  1254. }
  1255. // make sure the width is less than or equal to 256
  1256. if (paddedImageWidth > 256)
  1257. {
  1258. paddedImageWidth = 256;
  1259. }
  1260. // get the nearest power of two that is greater than the height of the image
  1261. paddedImageHeight = tgaHeight;
  1262. if (!IsPowerOfTwo(paddedImageHeight))
  1263. {
  1264. // height is not a power of two, calculate the next highest power of two value.
  1265. int i = 1;
  1266. while (paddedImageHeight > 1)
  1267. {
  1268. paddedImageHeight = paddedImageHeight >> 1;
  1269. ++i;
  1270. }
  1271. paddedImageHeight = paddedImageHeight << i;
  1272. }
  1273. // make sure the height is less than or equal to 256
  1274. if (paddedImageHeight > 256)
  1275. {
  1276. paddedImageHeight = 256;
  1277. }
  1278. // compute the amount of stretching that needs to be done to both width and height to get the image to fit.
  1279. float widthRatio = (float)paddedImageWidth / tgaWidth;
  1280. float heightRatio = (float)paddedImageHeight / tgaHeight;
  1281. int finalWidth;
  1282. int finalHeight;
  1283. // compute the final dimensions of the stretched image.
  1284. if (widthRatio < heightRatio)
  1285. {
  1286. finalWidth = paddedImageWidth;
  1287. finalHeight = (int)(tgaHeight * widthRatio + 0.5f);
  1288. // i.e. for 1x1 size pixels in the resized image we will take color from sourceRatio x sourceRatio sized pixels in the source image.
  1289. }
  1290. else if (heightRatio < widthRatio)
  1291. {
  1292. finalHeight = paddedImageHeight;
  1293. finalWidth = (int)(tgaWidth * heightRatio + 0.5f);
  1294. }
  1295. else
  1296. {
  1297. finalHeight = paddedImageHeight;
  1298. finalWidth = paddedImageWidth;
  1299. }
  1300. unsigned char *resizeBuffer = (unsigned char *)malloc(finalWidth * finalHeight * 4);
  1301. // do the actual stretching
  1302. StretchRGBAImage(srcBuffer, tgaWidth, tgaHeight, resizeBuffer, finalWidth, finalHeight);
  1303. free(srcBuffer); // don't need this anymore.
  1304. ///////////////////////////////////////////////////////////////////////
  1305. ///// need to pad the image so both dimensions are power of two's /////
  1306. ///////////////////////////////////////////////////////////////////////
  1307. unsigned char *finalBuffer = (unsigned char *)malloc(paddedImageWidth * paddedImageHeight * 4);
  1308. PadRGBAImage(resizeBuffer, finalWidth, finalHeight, finalBuffer, paddedImageWidth, paddedImageHeight);
  1309. FILE *outfile = fopen(tgaPath, "wb");
  1310. if (outfile == NULL)
  1311. {
  1312. free(resizeBuffer);
  1313. free(finalBuffer);
  1314. return CE_ERROR_WRITING_OUTPUT_FILE;
  1315. }
  1316. tgaHeader.width = paddedImageWidth;
  1317. tgaHeader.height = paddedImageHeight;
  1318. WriteTGAHeader(outfile, tgaHeader);
  1319. fwrite(finalBuffer, 1, paddedImageWidth * paddedImageHeight * 4, outfile);
  1320. fclose(outfile);
  1321. free(resizeBuffer);
  1322. free(finalBuffer);
  1323. return CE_SUCCESS;
  1324. }
  1325. // resize by stretching (or compressing) an RGBA image pointed to by srcBuf into the buffer pointed to by destBuf.
  1326. // the buffers are assumed to be sized appropriately to accomidate RGBA images of the given widths and heights.
  1327. ConversionErrorType COptionsSubMultiplayer::StretchRGBAImage(const unsigned char *srcBuf, const int srcWidth, const int srcHeight,
  1328. unsigned char *destBuf, const int destWidth, const int destHeight)
  1329. {
  1330. if ((srcBuf == NULL) || (destBuf == NULL))
  1331. {
  1332. return CE_CANT_OPEN_SOURCE_FILE;
  1333. }
  1334. int destRow,destColumn;
  1335. float ratioX = (float)srcWidth / (float)destWidth;
  1336. float ratioY = (float)srcHeight / (float)destHeight;
  1337. // loop through all the pixels in the destination image.
  1338. for (destRow = 0; destRow < destHeight; ++destRow)
  1339. {
  1340. for (destColumn = 0; destColumn < destWidth; ++destColumn)
  1341. {
  1342. // calculate the center of the pixel in the source image.
  1343. float srcCenterX = ratioX * (destColumn + 0.5f);
  1344. float srcCenterY = ratioY * (destRow + 0.5f);
  1345. // calculate the starting and ending coords for this destination pixel in the source image.
  1346. float srcStartX = srcCenterX - (ratioX / 2.0f);
  1347. if (srcStartX < 0.0f)
  1348. {
  1349. srcStartX = 0.0f; // this should never happen, but just in case.
  1350. }
  1351. float srcStartY = srcCenterY - (ratioY / 2.0f);
  1352. if (srcStartY < 0.0f)
  1353. {
  1354. srcStartY = 0.0f; // this should never happen, but just in case.
  1355. }
  1356. float srcEndX = srcCenterX + (ratioX / 2.0f);
  1357. if (srcEndX > srcWidth)
  1358. {
  1359. srcEndX = srcWidth; // this should never happen, but just in case.
  1360. }
  1361. float srcEndY = srcCenterY + (ratioY / 2.0f);
  1362. if (srcEndY > srcHeight)
  1363. {
  1364. srcEndY = srcHeight; // this should never happen, but just in case.
  1365. }
  1366. // Calculate the percentage of each source pixels' contribution to the destination pixel color.
  1367. float srcCurrentX; // initialized at the start of the y loop.
  1368. float srcCurrentY = srcStartY;
  1369. float destRed = 0.0f;
  1370. float destGreen = 0.0f;
  1371. float destBlue = 0.0f;
  1372. float destAlpha = 0.0f;
  1373. //// loop for the parts of the source image that will contribute color to the destination pixel.
  1374. while (srcCurrentY < srcEndY)
  1375. {
  1376. float srcCurrentEndY = (float)((int)srcCurrentY + 1);
  1377. if (srcCurrentEndY > srcEndY)
  1378. {
  1379. srcCurrentEndY = srcEndY;
  1380. }
  1381. float srcCurrentHeight = srcCurrentEndY - srcCurrentY;
  1382. srcCurrentX = srcStartX;
  1383. while (srcCurrentX < srcEndX)
  1384. {
  1385. float srcCurrentEndX = (float)((int)srcCurrentX + 1);
  1386. if (srcCurrentEndX > srcEndX)
  1387. {
  1388. srcCurrentEndX = srcEndX;
  1389. }
  1390. float srcCurrentWidth = srcCurrentEndX - srcCurrentX;
  1391. // compute the percentage of the destination pixel's color this source pixel will contribute.
  1392. float srcColorPercentage = (srcCurrentWidth / ratioX) * (srcCurrentHeight / ratioY);
  1393. int srcCurrentPixelX = (int)srcCurrentX;
  1394. int srcCurrentPixelY = (int)srcCurrentY;
  1395. // get the color values for this source pixel.
  1396. unsigned char srcCurrentRed = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4)];
  1397. unsigned char srcCurrentGreen = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4) + 1];
  1398. unsigned char srcCurrentBlue = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4) + 2];
  1399. unsigned char srcCurrentAlpha = srcBuf[(srcCurrentPixelY * srcWidth * 4) + (srcCurrentPixelX * 4) + 3];
  1400. // add the color contribution from this source pixel to the destination pixel.
  1401. destRed += srcCurrentRed * srcColorPercentage;
  1402. destGreen += srcCurrentGreen * srcColorPercentage;
  1403. destBlue += srcCurrentBlue * srcColorPercentage;
  1404. destAlpha += srcCurrentAlpha * srcColorPercentage;
  1405. srcCurrentX = srcCurrentEndX;
  1406. }
  1407. srcCurrentY = srcCurrentEndY;
  1408. }
  1409. // assign the computed color to the destination pixel, round to the nearest value. Make sure the value doesn't exceed 255.
  1410. destBuf[(destRow * destWidth * 4) + (destColumn * 4)] = MIN((int)(destRed + 0.5f), 255);
  1411. destBuf[(destRow * destWidth * 4) + (destColumn * 4) + 1] = MIN((int)(destGreen + 0.5f), 255);
  1412. destBuf[(destRow * destWidth * 4) + (destColumn * 4) + 2] = MIN((int)(destBlue + 0.5f), 255);
  1413. destBuf[(destRow * destWidth * 4) + (destColumn * 4) + 3] = MIN((int)(destAlpha + 0.5f), 255);
  1414. } // column loop
  1415. } // row loop
  1416. return CE_SUCCESS;
  1417. }
  1418. ConversionErrorType COptionsSubMultiplayer::PadRGBAImage(const unsigned char *srcBuf, const int srcWidth, const int srcHeight,
  1419. unsigned char *destBuf, const int destWidth, const int destHeight)
  1420. {
  1421. if ((srcBuf == NULL) || (destBuf == NULL))
  1422. {
  1423. return CE_CANT_OPEN_SOURCE_FILE;
  1424. }
  1425. memset(destBuf, 0, destWidth * destHeight * 4);
  1426. if ((destWidth < srcWidth) || (destHeight < srcHeight))
  1427. {
  1428. return CE_ERROR_PARSING_SOURCE;
  1429. }
  1430. if ((srcWidth == destWidth) && (srcHeight == destHeight))
  1431. {
  1432. // no padding is needed, just copy the buffer straight over and call it done.
  1433. memcpy(destBuf, srcBuf, destWidth * destHeight * 4);
  1434. return CE_SUCCESS;
  1435. }
  1436. if (destWidth == srcWidth)
  1437. {
  1438. // only the top and bottom of the image need padding.
  1439. // do this separately since we can do this more efficiently than the other cases.
  1440. int numRowsToPad = (destHeight - srcHeight) / 2;
  1441. memcpy(destBuf + (numRowsToPad * destWidth * 4), srcBuf, srcWidth * srcHeight * 4);
  1442. }
  1443. else
  1444. {
  1445. int numColumnsToPad = (destWidth - srcWidth) / 2;
  1446. int numRowsToPad = (destHeight - srcHeight) / 2;
  1447. int lastRow = numRowsToPad + srcHeight;
  1448. int row;
  1449. for (row = numRowsToPad; row < lastRow; ++row)
  1450. {
  1451. unsigned char * destOffset = destBuf + (row * destWidth * 4) + (numColumnsToPad * 4);
  1452. const unsigned char * srcOffset = srcBuf + ((row - numRowsToPad) * srcWidth * 4);
  1453. memcpy(destOffset, srcOffset, srcWidth * 4);
  1454. }
  1455. }
  1456. return CE_SUCCESS;
  1457. }
  1458. // convert TGA file at the given location to a VTF file of the same root name at the same location.
  1459. ConversionErrorType COptionsSubMultiplayer::ConvertTGAToVTF(const char *tgaPath)
  1460. {
  1461. FILE *infile = fopen(tgaPath, "rb");
  1462. if (infile == NULL)
  1463. {
  1464. return CE_CANT_OPEN_SOURCE_FILE;
  1465. }
  1466. // read out the header of the image.
  1467. TGAHeader header;
  1468. ReadTGAHeader(infile, header);
  1469. // check to make sure that the TGA has the proper dimensions and size.
  1470. if (!IsPowerOfTwo(header.width) || !IsPowerOfTwo(header.height))
  1471. {
  1472. fclose(infile);
  1473. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1474. }
  1475. // check to make sure that the TGA isn't too big.
  1476. if ((header.width > 256) || (header.height > 256))
  1477. {
  1478. fclose(infile);
  1479. return CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED;
  1480. }
  1481. int imageMemoryFootprint = header.width * header.height * header.bits / 8;
  1482. CUtlBuffer inbuf(0, imageMemoryFootprint);
  1483. // read in the image
  1484. int nBytesRead = fread(inbuf.Base(), imageMemoryFootprint, 1, infile);
  1485. fclose(infile);
  1486. inbuf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );
  1487. // load vtex_dll.dll and get the interface to it.
  1488. CSysModule *vtexmod = Sys_LoadModule("vtex_dll");
  1489. if (vtexmod == NULL)
  1490. {
  1491. return CE_ERROR_LOADING_DLL;
  1492. }
  1493. CreateInterfaceFn factory = Sys_GetFactory(vtexmod);
  1494. if (factory == NULL)
  1495. {
  1496. Sys_UnloadModule(vtexmod);
  1497. return CE_ERROR_LOADING_DLL;
  1498. }
  1499. IVTex *vtex = (IVTex *)factory(IVTEX_VERSION_STRING, NULL);
  1500. if (vtex == NULL)
  1501. {
  1502. Sys_UnloadModule(vtexmod);
  1503. return CE_ERROR_LOADING_DLL;
  1504. }
  1505. char *vtfParams[4];
  1506. // the 0th entry is skipped cause normally thats the program name.
  1507. vtfParams[0] = "";
  1508. vtfParams[1] = "-quiet";
  1509. vtfParams[2] = "-dontusegamedir";
  1510. vtfParams[3] = (char *)tgaPath;
  1511. // call vtex to do the conversion.
  1512. vtex->VTex(4, vtfParams);
  1513. Sys_UnloadModule(vtexmod);
  1514. return CE_SUCCESS;
  1515. }
  1516. // write a VMT file for the spray VTF file at the given path.
  1517. ConversionErrorType COptionsSubMultiplayer::WriteSprayVMT(const char *vtfPath)
  1518. {
  1519. if (vtfPath == NULL)
  1520. {
  1521. return CE_ERROR_WRITING_OUTPUT_FILE;
  1522. }
  1523. // make the vmt filename
  1524. char vmtPath[MAX_PATH*4];
  1525. Q_strncpy(vmtPath, vtfPath, sizeof(vmtPath));
  1526. char *c = vmtPath + strlen(vmtPath);
  1527. while ((c > vmtPath) && (*(c-1) != '.'))
  1528. {
  1529. --c;
  1530. }
  1531. Q_strncpy(c, "vmt", sizeof(vmtPath) - (c - vmtPath));
  1532. // get the root filename for the vtf file
  1533. char filename[MAX_PATH];
  1534. while ((c > vmtPath) && (*(c-1) != '/') && (*(c-1) != '\\'))
  1535. {
  1536. --c;
  1537. }
  1538. int i = 0;
  1539. while ((*c != 0) && (*c != '.'))
  1540. {
  1541. filename[i++] = *(c++);
  1542. }
  1543. filename[i] = 0;
  1544. // create the vmt file.
  1545. FILE *vmtFile = fopen(vmtPath, "w");
  1546. if (vmtFile == NULL)
  1547. {
  1548. return CE_ERROR_WRITING_OUTPUT_FILE;
  1549. }
  1550. // write the contents of the file.
  1551. fprintf(vmtFile, "LightmappedGeneric\n{\n\t\"$basetexture\" \"vgui\\logos\\%s\"\n\t\"$translucent\" \"1\"\n\t\"$decal\" \"1\"\n\t\"$decalscale\" \"0.250\"\n}\n", filename);
  1552. fclose(vmtFile);
  1553. return CE_SUCCESS;
  1554. }
  1555. //-----------------------------------------------------------------------------
  1556. // Purpose: Builds the list of logos
  1557. //-----------------------------------------------------------------------------
  1558. void COptionsSubMultiplayer::InitLogoList( CLabeledCommandComboBox *cb )
  1559. {
  1560. // Find out images
  1561. FileFindHandle_t fh;
  1562. char directory[ 512 ];
  1563. // NOTE: <<vitaliy>> this feature is obsolete in CS:GO
  1564. ConVarRef cl_logofile( "cl_logofile" );
  1565. if ( !cl_logofile.IsValid() )
  1566. return;
  1567. cb->DeleteAllItems();
  1568. const char *logofile = cl_logofile.GetString();
  1569. Q_snprintf( directory, sizeof( directory ), "materials/vgui/logos/*.vtf" );
  1570. const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
  1571. int i = 0, initialItem = 0;
  1572. while (fn)
  1573. {
  1574. char filename[ 512 ];
  1575. Q_snprintf( filename, sizeof(filename), "materials/vgui/logos/%s", fn );
  1576. if ( strlen( filename ) >= 4 )
  1577. {
  1578. filename[ strlen( filename ) - 4 ] = 0;
  1579. Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
  1580. if ( g_pFullFileSystem->FileExists( filename ) )
  1581. {
  1582. // strip off the extension
  1583. Q_strncpy( filename, fn, sizeof( filename ) );
  1584. filename[ strlen( filename ) - 4 ] = 0;
  1585. cb->AddItem( filename, "" );
  1586. // check to see if this is the one we have set
  1587. Q_snprintf( filename, sizeof(filename), "materials/vgui/logos/%s", fn );
  1588. if (!Q_stricmp(filename, logofile))
  1589. {
  1590. initialItem = i;
  1591. }
  1592. ++i;
  1593. }
  1594. }
  1595. fn = g_pFullFileSystem->FindNext( fh );
  1596. }
  1597. g_pFullFileSystem->FindClose( fh );
  1598. cb->SetInitialItem(initialItem);
  1599. }
  1600. //-----------------------------------------------------------------------------
  1601. // Purpose: Selects the given logo in the logo list.
  1602. //-----------------------------------------------------------------------------
  1603. void COptionsSubMultiplayer::SelectLogo(const char *logoName)
  1604. {
  1605. int numEntries = m_pLogoList->GetItemCount();
  1606. int index;
  1607. wchar_t itemText[MAX_PATH];
  1608. wchar_t itemToSelectText[MAX_PATH];
  1609. // convert the logo filename to unicode
  1610. g_pVGuiLocalize->ConvertANSIToUnicode(logoName, itemToSelectText, sizeof(itemToSelectText));
  1611. // find the index of the spray we want.
  1612. for (index = 0; index < numEntries; ++index)
  1613. {
  1614. m_pLogoList->GetItemText(index, itemText, sizeof(itemText));
  1615. if (!wcscmp(itemText, itemToSelectText))
  1616. {
  1617. break;
  1618. }
  1619. }
  1620. if (index < numEntries)
  1621. {
  1622. // select the logo.
  1623. m_pLogoList->ActivateItem(index);
  1624. }
  1625. }
  1626. #define MODEL_MATERIAL_BASE_FOLDER "materials/vgui/playermodels/"
  1627. void StripStringOutOfString( const char *pPattern, const char *pIn, char *pOut )
  1628. {
  1629. int iLengthBase = strlen( pPattern );
  1630. int iLengthString = strlen( pIn );
  1631. int k = 0;
  1632. for ( int j = iLengthBase; j < iLengthString; j++ )
  1633. {
  1634. pOut[k] = pIn[j];
  1635. k++;
  1636. }
  1637. pOut[k] = 0;
  1638. }
  1639. void FindVMTFilesInFolder( const char *pFolder, const char *pFolderName, CLabeledCommandComboBox *cb, int &iCount, int &iInitialItem )
  1640. {
  1641. ConVarRef cl_modelfile( "cl_playermodel" );
  1642. if ( !cl_modelfile.IsValid() )
  1643. return;
  1644. char directory[ 512 ];
  1645. Q_snprintf( directory, sizeof( directory ), "%s/*.*", pFolder );
  1646. FileFindHandle_t fh;
  1647. const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
  1648. const char *modelfile = cl_modelfile.GetString();
  1649. while ( fn )
  1650. {
  1651. if ( !stricmp( fn, ".") || !stricmp( fn, "..") )
  1652. {
  1653. fn = g_pFullFileSystem->FindNext( fh );
  1654. continue;
  1655. }
  1656. if ( g_pFullFileSystem->FindIsDirectory( fh ) )
  1657. {
  1658. char folderpath[512];
  1659. Q_snprintf( folderpath, sizeof( folderpath ), "%s/%s", pFolder, fn );
  1660. FindVMTFilesInFolder( folderpath, fn, cb, iCount, iInitialItem );
  1661. fn = g_pFullFileSystem->FindNext( fh );
  1662. continue;
  1663. }
  1664. if ( !strstr( fn, ".vmt" ) )
  1665. {
  1666. fn = g_pFullFileSystem->FindNext( fh );
  1667. continue;
  1668. }
  1669. char filename[ 512 ];
  1670. Q_snprintf( filename, sizeof(filename), "%s/%s", pFolder, fn );
  1671. if ( strlen( filename ) >= 4 )
  1672. {
  1673. filename[ strlen( filename ) - 4 ] = 0;
  1674. Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
  1675. if ( g_pFullFileSystem->FileExists( filename ) )
  1676. {
  1677. char displayname[ 512 ];
  1678. char texturepath[ 512 ];
  1679. // strip off the extension
  1680. Q_strncpy( displayname, fn, sizeof( displayname ) );
  1681. StripStringOutOfString( MODEL_MATERIAL_BASE_FOLDER, filename, texturepath );
  1682. displayname[ strlen( displayname ) - 4 ] = 0;
  1683. cb->AddItem( displayname, texturepath + 1 ); // ignore the initial "/" in texture path
  1684. char realname[ 512 ];
  1685. Q_FileBase( modelfile, realname, sizeof( realname ) );
  1686. Q_FileBase( filename, filename, sizeof( filename ) );
  1687. if (!stricmp(filename, realname))
  1688. {
  1689. iInitialItem = iCount;
  1690. }
  1691. ++iCount;
  1692. }
  1693. }
  1694. fn = g_pFullFileSystem->FindNext( fh );
  1695. }
  1696. }
  1697. //-----------------------------------------------------------------------------
  1698. // Purpose: Builds model list
  1699. //-----------------------------------------------------------------------------
  1700. void COptionsSubMultiplayer::InitModelList( CLabeledCommandComboBox *cb )
  1701. {
  1702. // Find out images
  1703. int i = 0, initialItem = 0;
  1704. cb->DeleteAllItems();
  1705. FindVMTFilesInFolder( MODEL_MATERIAL_BASE_FOLDER, "", cb, i, initialItem );
  1706. cb->SetInitialItem( initialItem );
  1707. }
  1708. //-----------------------------------------------------------------------------
  1709. // Purpose:
  1710. //-----------------------------------------------------------------------------
  1711. void COptionsSubMultiplayer::InitCrosshairColorEntries()
  1712. {
  1713. // parse the string for the custom color settings and get the initial settings.
  1714. ConVarRef cl_crosshaircolor( "cl_crosshaircolor" );
  1715. int index = 0;
  1716. if ( cl_crosshaircolor.IsValid() )
  1717. {
  1718. index = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors );
  1719. }
  1720. if (m_pCrosshairColorComboBox != NULL)
  1721. {
  1722. KeyValues *data = new KeyValues("data");
  1723. // add in the "Default" selection
  1724. data->Clear();
  1725. // add in the colors for the color list
  1726. for ( int i = 0; i < NumCrosshairColors; i++ )
  1727. {
  1728. data->SetInt("color", i);
  1729. m_pCrosshairColorComboBox->AddItem( s_crosshairColors[ i ].name, data);
  1730. }
  1731. m_pCrosshairColorComboBox->ActivateItemByRow(index);
  1732. data->deleteThis();
  1733. }
  1734. // force the crosshair to redraw.
  1735. RedrawCrosshairImage(); // don't need to do this since we're not drawing anything.
  1736. }
  1737. //-----------------------------------------------------------------------------
  1738. // Purpose: takes the settings from the crosshair settings combo boxes and sliders
  1739. // and apply it to the crosshair illustrations.
  1740. //-----------------------------------------------------------------------------
  1741. void COptionsSubMultiplayer::RedrawCrosshairImage()
  1742. {
  1743. if (m_pCrosshairColorComboBox == NULL)
  1744. {
  1745. return;
  1746. }
  1747. bool enableApplyButton = false;
  1748. // get the color selected in the combo box.
  1749. KeyValues *data = m_pCrosshairColorComboBox->GetActiveItemUserData();
  1750. int colorIndex = data->GetInt("color");
  1751. colorIndex = clamp( colorIndex, 0, NumCrosshairColors );
  1752. int selectedVal = 0;
  1753. int actualVal = 0;
  1754. if (m_pCrosshairColorComboBox != NULL)
  1755. {
  1756. selectedVal = m_pCrosshairColorComboBox->GetActiveItem();
  1757. }
  1758. ConVarRef cl_crosshaircolor( "cl_crosshaircolor" );
  1759. if ( cl_crosshaircolor.IsValid() )
  1760. {
  1761. actualVal = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors );
  1762. }
  1763. if ( selectedVal != actualVal )
  1764. {
  1765. enableApplyButton = true;
  1766. }
  1767. if (enableApplyButton)
  1768. {
  1769. OnApplyButtonEnable();
  1770. }
  1771. if ( m_pCrosshairImage && m_pCrosshairSize )
  1772. {
  1773. int size = m_pCrosshairSize->GetActiveItem();
  1774. m_pCrosshairImage->UpdateCrosshair(
  1775. s_crosshairColors[selectedVal].r,
  1776. s_crosshairColors[selectedVal].g,
  1777. s_crosshairColors[selectedVal].b,
  1778. size );
  1779. }
  1780. }
  1781. //-----------------------------------------------------------------------------
  1782. // Purpose: takes the settings from the crosshair settings combo boxes and sliders
  1783. // and apply it to the crosshair illustrations.
  1784. //-----------------------------------------------------------------------------
  1785. void COptionsSubMultiplayer::RedrawAdvCrosshairImage()
  1786. {
  1787. if ( !ModInfo().AdvCrosshair() )
  1788. {
  1789. return;
  1790. }
  1791. // get the color selected in the combo box.
  1792. int r,g,b;
  1793. r = clamp( m_pAdvCrosshairRedSlider->GetSliderValue(), 0, 255 );
  1794. g = clamp( m_pAdvCrosshairGreenSlider->GetSliderValue(), 0, 255 );
  1795. b = clamp( m_pAdvCrosshairBlueSlider->GetSliderValue(), 0, 255 );
  1796. float scale = m_pAdvCrosshairScaleSlider->GetSliderValue();
  1797. if ( m_pAdvCrosshairImage && m_pAdvCrosshairStyle )
  1798. {
  1799. char crosshairname[256];
  1800. m_pAdvCrosshairStyle->GetText( crosshairname, sizeof(crosshairname) );
  1801. char texture[ 256 ];
  1802. Q_snprintf ( texture, sizeof( texture ), "vgui/crosshairs/%s", crosshairname );
  1803. m_pAdvCrosshairImage->UpdateCrosshair( r, g, b, scale, texture );
  1804. }
  1805. }
  1806. //-----------------------------------------------------------------------------
  1807. // Purpose: initialize the crosshair size list.
  1808. //-----------------------------------------------------------------------------
  1809. void COptionsSubMultiplayer::InitCrosshairSizeList(CLabeledCommandComboBox *cb)
  1810. {
  1811. if (cb == NULL)
  1812. {
  1813. return;
  1814. }
  1815. cb->Reset();
  1816. // add in the auto, small, medium, and large size selections.
  1817. cb->AddItem("#GameUI_Auto", "cl_crosshairscale 0");
  1818. cb->AddItem("#GameUI_Small", "cl_crosshairscale 1200");
  1819. cb->AddItem("#GameUI_Medium", "cl_crosshairscale 768");
  1820. cb->AddItem("#GameUI_Large", "cl_crosshairscale 600");
  1821. // parse out the size value from the cvar and set the initial value.
  1822. int initialScale = 0;
  1823. ConVarRef cl_crosshairscale( "cl_crosshairscale" );
  1824. if ( cl_crosshairscale.IsValid() )
  1825. {
  1826. initialScale = cl_crosshairscale.GetInt();
  1827. if ( initialScale <= 0 )
  1828. {
  1829. initialScale = 0;
  1830. }
  1831. else if ( initialScale <= 600 )
  1832. {
  1833. initialScale = 3;
  1834. }
  1835. else if ( initialScale <= 768 )
  1836. {
  1837. initialScale = 2;
  1838. }
  1839. else
  1840. {
  1841. initialScale = 1;
  1842. }
  1843. }
  1844. cb->SetInitialItem( initialScale );
  1845. }
  1846. //-----------------------------------------------------------------------------
  1847. // Purpose: initialize the crosshair style list
  1848. //-----------------------------------------------------------------------------
  1849. void COptionsSubMultiplayer::InitAdvCrosshairStyleList(CLabeledCommandComboBox *cb)
  1850. {
  1851. // Find out images
  1852. FileFindHandle_t fh;
  1853. char directory[ 512 ];
  1854. ConVarRef cl_crosshair_file( "cl_crosshair_file" );
  1855. if ( !cl_crosshair_file.IsValid() )
  1856. return;
  1857. cb->DeleteAllItems();
  1858. char crosshairfile[256];
  1859. Q_snprintf( crosshairfile, sizeof(crosshairfile), "materials/vgui/crosshairs/%s.vtf", cl_crosshair_file.GetString() );
  1860. Q_snprintf( directory, sizeof( directory ), "materials/vgui/crosshairs/*.vtf" );
  1861. const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
  1862. int i = 0, initialItem = 0;
  1863. while (fn)
  1864. {
  1865. char filename[ 512 ];
  1866. Q_snprintf( filename, sizeof(filename), "materials/vgui/crosshairs/%s", fn );
  1867. if ( strlen( filename ) >= 4 )
  1868. {
  1869. filename[ strlen( filename ) - 4 ] = 0;
  1870. Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
  1871. if ( g_pFullFileSystem->FileExists( filename ) )
  1872. {
  1873. // strip off the extension
  1874. Q_strncpy( filename, fn, sizeof( filename ) );
  1875. filename[ strlen( filename ) - 4 ] = 0;
  1876. cb->AddItem( filename, "" );
  1877. // check to see if this is the one we have set
  1878. Q_snprintf( filename, sizeof(filename), "materials/vgui/crosshairs/%s", fn );
  1879. if (!stricmp(filename, crosshairfile))
  1880. {
  1881. initialItem = i;
  1882. }
  1883. ++i;
  1884. }
  1885. }
  1886. fn = g_pFullFileSystem->FindNext( fh );
  1887. }
  1888. g_pFullFileSystem->FindClose( fh );
  1889. cb->SetInitialItem(initialItem);
  1890. }
  1891. //-----------------------------------------------------------------------------
  1892. // Purpose:
  1893. //-----------------------------------------------------------------------------
  1894. void COptionsSubMultiplayer::RemapLogo()
  1895. {
  1896. char logoname[256];
  1897. m_pLogoList->GetText( logoname, sizeof( logoname ) );
  1898. if( !logoname[ 0 ] )
  1899. return;
  1900. char fullLogoName[512];
  1901. // make sure there is a version with the proper shader
  1902. g_pFullFileSystem->CreateDirHierarchy( "materials/VGUI/logos/UI", "GAME" );
  1903. Q_snprintf( fullLogoName, sizeof( fullLogoName ), "materials/VGUI/logos/UI/%s.vmt", logoname );
  1904. if ( !g_pFullFileSystem->FileExists( fullLogoName ) )
  1905. {
  1906. FileHandle_t fp = g_pFullFileSystem->Open( fullLogoName, "wb" );
  1907. if ( !fp )
  1908. return;
  1909. char data[1024];
  1910. Q_snprintf( data, sizeof( data ), "\"UnlitGeneric\"\n\
  1911. {\n\
  1912. // Original shader: BaseTimesVertexColorAlphaBlendNoOverbright\n\
  1913. \"$translucent\" 1\n\
  1914. \"$basetexture\" \"VGUI\\logos\\%s\"\n\
  1915. \"$vertexcolor\" 1\n\
  1916. \"$vertexalpha\" 1\n\
  1917. \"$no_fullbright\" 1\n\
  1918. \"$ignorez\" 1\n\
  1919. }\n\
  1920. ", logoname );
  1921. g_pFullFileSystem->Write( data, strlen( data ), fp );
  1922. g_pFullFileSystem->Close( fp );
  1923. }
  1924. Q_snprintf( fullLogoName, sizeof( fullLogoName ), "logos/UI/%s", logoname );
  1925. m_pLogoImage->SetImage( fullLogoName );
  1926. }
  1927. //-----------------------------------------------------------------------------
  1928. // Purpose:
  1929. //-----------------------------------------------------------------------------
  1930. void COptionsSubMultiplayer::RemapModel()
  1931. {
  1932. const char *pModelName = m_pModelList->GetActiveItemCommand();
  1933. if( pModelName == NULL )
  1934. return;
  1935. char texture[ 256 ];
  1936. Q_snprintf ( texture, sizeof( texture ), "vgui/playermodels/%s", pModelName );
  1937. texture[ strlen( texture ) - 4 ] = 0;
  1938. m_pModelImage->setTexture( texture );
  1939. }
  1940. //-----------------------------------------------------------------------------
  1941. // Purpose: Called whenever model name changes
  1942. //-----------------------------------------------------------------------------
  1943. void COptionsSubMultiplayer::OnTextChanged(vgui::Panel *panel)
  1944. {
  1945. RemapModel();
  1946. RemapLogo();
  1947. RedrawCrosshairImage(); // redraw the crosshair.
  1948. RedrawAdvCrosshairImage();
  1949. }
  1950. //-----------------------------------------------------------------------------
  1951. // Purpose:
  1952. //-----------------------------------------------------------------------------
  1953. void COptionsSubMultiplayer::OnSliderMoved(KeyValues *data)
  1954. {
  1955. m_nTopColor = (int) m_pPrimaryColorSlider->GetSliderValue();
  1956. m_nBottomColor = (int) m_pSecondaryColorSlider->GetSliderValue();
  1957. RemapModel();
  1958. RedrawAdvCrosshairImage();
  1959. }
  1960. //-----------------------------------------------------------------------------
  1961. // Purpose:
  1962. //-----------------------------------------------------------------------------
  1963. void COptionsSubMultiplayer::OnApplyButtonEnable()
  1964. {
  1965. PostMessage(GetParent(), new KeyValues("ApplyButtonEnable"));
  1966. InvalidateLayout();
  1967. }
  1968. //#include <windows.h>
  1969. #define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
  1970. #define SUIT_HUE_START 192
  1971. #define SUIT_HUE_END 223
  1972. #define PLATE_HUE_START 160
  1973. #define PLATE_HUE_END 191
  1974. // @wge this struct definition is from Portal 2 source, but didn't want to conflict with other platforms so made it OSX only.
  1975. #if defined( _OSX ) || defined (LINUX)
  1976. typedef struct tagRGBQUAD {
  1977. uint8 rgbBlue;
  1978. uint8 rgbGreen;
  1979. uint8 rgbRed;
  1980. uint8 rgbReserved;
  1981. } RGBQUAD;
  1982. #endif // _OSX
  1983. //-----------------------------------------------------------------------------
  1984. // Purpose:
  1985. //-----------------------------------------------------------------------------
  1986. static void PaletteHueReplace( RGBQUAD *palSrc, int newHue, int Start, int end )
  1987. {
  1988. int i;
  1989. float r, b, g;
  1990. float maxcol, mincol;
  1991. float hue, val, sat;
  1992. hue = (float)(newHue * (360.0 / 255));
  1993. for (i = Start; i <= end; i++)
  1994. {
  1995. b = palSrc[ i ].rgbBlue;
  1996. g = palSrc[ i ].rgbGreen;
  1997. r = palSrc[ i ].rgbRed;
  1998. maxcol = MAX( MAX( r, g ), b ) / 255.0f;
  1999. mincol = MIN( MIN( r, g ), b ) / 255.0f;
  2000. val = maxcol;
  2001. sat = (maxcol - mincol) / maxcol;
  2002. mincol = val * (1.0f - sat);
  2003. if (hue <= 120)
  2004. {
  2005. b = mincol;
  2006. if (hue < 60)
  2007. {
  2008. r = val;
  2009. g = mincol + hue * (val - mincol)/(120 - hue);
  2010. }
  2011. else
  2012. {
  2013. g = val;
  2014. r = mincol + (120 - hue)*(val-mincol)/hue;
  2015. }
  2016. }
  2017. else if (hue <= 240)
  2018. {
  2019. r = mincol;
  2020. if (hue < 180)
  2021. {
  2022. g = val;
  2023. b = mincol + (hue - 120)*(val-mincol)/(240 - hue);
  2024. }
  2025. else
  2026. {
  2027. b = val;
  2028. g = mincol + (240 - hue)*(val-mincol)/(hue - 120);
  2029. }
  2030. }
  2031. else
  2032. {
  2033. g = mincol;
  2034. if (hue < 300)
  2035. {
  2036. b = val;
  2037. r = mincol + (hue - 240)*(val-mincol)/(360 - hue);
  2038. }
  2039. else
  2040. {
  2041. r = val;
  2042. b = mincol + (360 - hue)*(val-mincol)/(hue - 240);
  2043. }
  2044. }
  2045. palSrc[ i ].rgbBlue = (unsigned char)(b * 255);
  2046. palSrc[ i ].rgbGreen = (unsigned char)(g * 255);
  2047. palSrc[ i ].rgbRed = (unsigned char)(r * 255);
  2048. }
  2049. }
  2050. //-----------------------------------------------------------------------------
  2051. // Purpose:
  2052. //-----------------------------------------------------------------------------
  2053. void COptionsSubMultiplayer::RemapPalette( char *filename, int topcolor, int bottomcolor )
  2054. {
  2055. #if !defined( _OSX ) && !defined( _PS3 ) && !defined (LINUX)
  2056. char infile[ 256 ];
  2057. char outfile[ 256 ];
  2058. FileHandle_t file;
  2059. CUtlBuffer outbuffer( 16384, 16384 );
  2060. Q_snprintf( infile, sizeof( infile ), "models/player/%s/%s.bmp", filename, filename );
  2061. Q_strncpy( outfile, "models/player/remapped.bmp", sizeof( outfile ) );
  2062. file = g_pFullFileSystem->Open( infile, "rb" );
  2063. if ( file == FILESYSTEM_INVALID_HANDLE )
  2064. return;
  2065. // Parse bitmap
  2066. BITMAPFILEHEADER bmfHeader;
  2067. DWORD dwBitsSize, dwFileSize;
  2068. LPBITMAPINFO lpbmi;
  2069. dwFileSize = g_pFullFileSystem->Size( file );
  2070. g_pFullFileSystem->Read( &bmfHeader, sizeof(bmfHeader), file );
  2071. outbuffer.Put( &bmfHeader, sizeof( bmfHeader ) );
  2072. if (bmfHeader.bfType == DIB_HEADER_MARKER)
  2073. {
  2074. dwBitsSize = dwFileSize - sizeof(bmfHeader);
  2075. HGLOBAL hDIB = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize );
  2076. char *pDIB = (LPSTR)GlobalLock((HGLOBAL)hDIB);
  2077. {
  2078. g_pFullFileSystem->Read(pDIB, dwBitsSize, file );
  2079. lpbmi = (LPBITMAPINFO)pDIB;
  2080. // Remap palette
  2081. PaletteHueReplace( lpbmi->bmiColors, topcolor, SUIT_HUE_START, SUIT_HUE_END );
  2082. PaletteHueReplace( lpbmi->bmiColors, bottomcolor, PLATE_HUE_START, PLATE_HUE_END );
  2083. outbuffer.Put( pDIB, dwBitsSize );
  2084. }
  2085. GlobalUnlock( hDIB);
  2086. GlobalFree((HGLOBAL) hDIB);
  2087. }
  2088. g_pFullFileSystem->Close(file);
  2089. g_pFullFileSystem->RemoveFile( outfile, NULL );
  2090. g_pFullFileSystem->CreateDirHierarchy("models/player", NULL);
  2091. file = g_pFullFileSystem->Open( outfile, "wb" );
  2092. if ( file != FILESYSTEM_INVALID_HANDLE )
  2093. {
  2094. g_pFullFileSystem->Write( outbuffer.Base(), outbuffer.TellPut(), file );
  2095. g_pFullFileSystem->Close( file );
  2096. }
  2097. #endif // !_OSX && !_PS3
  2098. }
  2099. //-----------------------------------------------------------------------------
  2100. // Purpose:
  2101. //-----------------------------------------------------------------------------
  2102. void COptionsSubMultiplayer::ColorForName( char const *pszColorName, int&r, int&g, int&b )
  2103. {
  2104. r = g = b = 0;
  2105. int count = sizeof( itemlist ) / sizeof( itemlist[0] );
  2106. for ( int i = 0; i < count; i++ )
  2107. {
  2108. if ( StringHasPrefix( pszColorName, itemlist[ i ].name ) )
  2109. {
  2110. r = itemlist[ i ].r;
  2111. g = itemlist[ i ].g;
  2112. b = itemlist[ i ].b;
  2113. return;
  2114. }
  2115. }
  2116. }
  2117. //-----------------------------------------------------------------------------
  2118. // Purpose:
  2119. //-----------------------------------------------------------------------------
  2120. void COptionsSubMultiplayer::OnResetData()
  2121. {
  2122. // reset the DownloadFilter combo box
  2123. if ( m_pDownloadFilterCombo )
  2124. {
  2125. // cl_downloadfilter
  2126. ConVarRef cl_downloadfilter( "cl_downloadfilter" );
  2127. if ( Q_stricmp( cl_downloadfilter.GetString(), "none" ) == 0 )
  2128. {
  2129. m_pDownloadFilterCombo->ActivateItem( 2 );
  2130. }
  2131. else if ( Q_stricmp( cl_downloadfilter.GetString(), "nosounds" ) == 0 )
  2132. {
  2133. m_pDownloadFilterCombo->ActivateItem( 1 );
  2134. }
  2135. else
  2136. {
  2137. m_pDownloadFilterCombo->ActivateItem( 0 );
  2138. }
  2139. }
  2140. }
  2141. //-----------------------------------------------------------------------------
  2142. // Purpose:
  2143. //-----------------------------------------------------------------------------
  2144. void COptionsSubMultiplayer::OnApplyChanges()
  2145. {
  2146. m_pPrimaryColorSlider->ApplyChanges();
  2147. m_pSecondaryColorSlider->ApplyChanges();
  2148. // m_pModelList->ApplyChanges();
  2149. m_pLogoList->ApplyChanges();
  2150. m_pLogoList->GetText(m_LogoName, sizeof(m_LogoName));
  2151. m_pHighQualityModelCheckBox->ApplyChanges();
  2152. for ( int i=0; i<m_cvarToggleCheckButtons.GetCount(); ++i )
  2153. {
  2154. CCvarToggleCheckButton *toggleButton = m_cvarToggleCheckButtons[i];
  2155. if( toggleButton->IsVisible() && toggleButton->IsEnabled() )
  2156. {
  2157. toggleButton->ApplyChanges();
  2158. }
  2159. }
  2160. if ( !ModInfo().NoCrosshair() )
  2161. {
  2162. if (m_pCrosshairSize != NULL)
  2163. {
  2164. m_pCrosshairSize->ApplyChanges();
  2165. }
  2166. if (m_pCrosshairTranslucencyCheckbox != NULL)
  2167. {
  2168. m_pCrosshairTranslucencyCheckbox->ApplyChanges();
  2169. }
  2170. ApplyCrosshairColorChanges();
  2171. }
  2172. if ( ModInfo().AdvCrosshair() )
  2173. {
  2174. m_pAdvCrosshairRedSlider->ApplyChanges();
  2175. m_pAdvCrosshairGreenSlider->ApplyChanges();
  2176. m_pAdvCrosshairBlueSlider->ApplyChanges();
  2177. m_pAdvCrosshairScaleSlider->ApplyChanges();
  2178. m_pAdvCrosshairStyle->ApplyChanges();
  2179. // save the crosshair
  2180. char cmd[512];
  2181. char crosshair[256];
  2182. m_pAdvCrosshairStyle->GetText(crosshair, sizeof(crosshair));
  2183. Q_snprintf(cmd, sizeof(cmd), "cl_crosshair_file %s\n", crosshair);
  2184. engine->ClientCmd_Unrestricted(cmd);
  2185. }
  2186. // NOTE: <<vitaliy>> this feature is obsolete in CS:GO
  2187. // save the logo name
  2188. char cmd[512];
  2189. if ( m_LogoName[ 0 ] )
  2190. {
  2191. Q_snprintf(cmd, sizeof(cmd), "cl_logofile materials/vgui/logos/%s.vtf\n", m_LogoName);
  2192. }
  2193. else
  2194. {
  2195. Q_strncpy( cmd, "cl_logofile \"\"\n", sizeof( cmd ) );
  2196. }
  2197. engine->ClientCmd_Unrestricted(cmd);
  2198. if ( m_pModelList && m_pModelList->IsVisible() && m_pModelList->GetActiveItemCommand() )
  2199. {
  2200. Q_strncpy( m_ModelName, m_pModelList->GetActiveItemCommand(), sizeof( m_ModelName ) );
  2201. Q_StripExtension( m_ModelName, m_ModelName, sizeof ( m_ModelName ) );
  2202. // save the player model name
  2203. Q_snprintf(cmd, sizeof(cmd), "cl_playermodel models/%s.mdl\n", m_ModelName );
  2204. engine->ClientCmd_Unrestricted(cmd);
  2205. }
  2206. else
  2207. {
  2208. m_ModelName[0] = 0;
  2209. }
  2210. // set the DownloadFilter cvar
  2211. if ( m_pDownloadFilterCombo )
  2212. {
  2213. ConVarRef cl_downloadfilter( "cl_downloadfilter" );
  2214. switch ( m_pDownloadFilterCombo->GetActiveItem() )
  2215. {
  2216. default:
  2217. case 0:
  2218. cl_downloadfilter.SetValue( "all" );
  2219. break;
  2220. case 1:
  2221. cl_downloadfilter.SetValue( "nosounds" );
  2222. break;
  2223. case 2:
  2224. cl_downloadfilter.SetValue( "none" );
  2225. break;
  2226. }
  2227. }
  2228. }
  2229. //-----------------------------------------------------------------------------
  2230. // Purpose: apply the crosshair color values to the cvar.
  2231. // also set the slider values to match the new value.
  2232. //-----------------------------------------------------------------------------
  2233. void COptionsSubMultiplayer::ApplyCrosshairColorChanges()
  2234. {
  2235. char cmd[256];
  2236. cmd[0] = 0;
  2237. if (m_pCrosshairColorComboBox != NULL)
  2238. {
  2239. int val = m_pCrosshairColorComboBox->GetActiveItem();
  2240. Q_snprintf( cmd, sizeof(cmd), "cl_crosshaircolor %d\n", val );
  2241. engine->ClientCmd_Unrestricted( cmd );
  2242. }
  2243. }
  2244. //-----------------------------------------------------------------------------
  2245. // Purpose: Allow the res file to create controls on per-mod basis
  2246. //-----------------------------------------------------------------------------
  2247. Panel *COptionsSubMultiplayer::CreateControlByName( const char *controlName )
  2248. {
  2249. if( !Q_stricmp( "CCvarToggleCheckButton", controlName ) )
  2250. {
  2251. CCvarToggleCheckButton *newButton = new CCvarToggleCheckButton( this, controlName, "", "" );
  2252. m_cvarToggleCheckButtons.AddElement( newButton );
  2253. return newButton;
  2254. }
  2255. else
  2256. {
  2257. return BaseClass::CreateControlByName( controlName );
  2258. }
  2259. }