Smooth 2D Noise Viewer
Perlin and Value Noise
WindowsHelpers.cpp
Go to the documentation of this file.
1
6
7// MIT License
8//
9// Copyright (c) 2022 Ian Parberry
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to
13// deal in the Software without restriction, including without limitation the
14// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
15// sell copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27// IN THE SOFTWARE.
28
29#include <shobjidl_core.h>
30#include <atlbase.h>
31
32#include "WindowsHelpers.h"
33#include "Includes.h"
34
36// Initialization functions
37
38#pragma region Initialization
39
42
43ULONG_PTR InitGDIPlus(){
44 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
45 ULONG_PTR gdiplusToken;
46 Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
47 return gdiplusToken;
48} //InitGDIPlus
49
50#pragma endregion Initialization
51
53// Save functions
54
55#pragma region Save functions
56
61
62HRESULT GetEncoderClsid(const WCHAR* format, CLSID* pClsid){
63 UINT num = 0; //number of image encoders
64 UINT n = 0; //size of the image encoder array in bytes
65 HRESULT hr = E_FAIL; //return result
66
67 Gdiplus::ImageCodecInfo* pCodecInfo = nullptr; //for codec info
68 if(FAILED(Gdiplus::GetImageEncodersSize(&num, &n)))return E_FAIL; //get sizes
69 if(n == 0)return E_FAIL; //there are no encoders
70
71 pCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(n)); //allocate codec info memory
72 if(pCodecInfo == nullptr)return E_FAIL; //malloc failed (as if)
73 if(FAILED(GetImageEncoders(num, n, pCodecInfo)))return E_FAIL; //get encoders
74
75 for(UINT j=0; j<num && hr!=S_OK; j++) //for each encoder, while not found
76 if(wcscmp(pCodecInfo[j].MimeType, format) == 0){ //found the codex we want
77 *pClsid = pCodecInfo[j].Clsid; //return it
78 hr = S_OK; //success
79 } //if
80
81 free(pCodecInfo); //clean up
82 return hr;
83} //GetEncoderClsid
84
96
97HRESULT SaveBitmap(HWND hwnd, const std::wstring& wstrName,
98 Gdiplus::Bitmap* pBitmap)
99{
100 COMDLG_FILTERSPEC filetypes[] = { //png files only
101 {L"PNG Files", L"*.png"}
102 }; //filetypes
103
104 std::wstring wstrFileName; //result
105 CComPtr<IFileSaveDialog> pDlg; //pointer to save dialog box
106 CComPtr<IShellItem> pItem; //item pointer
107 LPWSTR pwsz = nullptr; //pointer to null-terminated wide string for result
108
109 //fire up the save dialog box
110
111 if(FAILED(pDlg.CoCreateInstance(__uuidof(FileSaveDialog))))return E_FAIL;
112
113 pDlg->SetFileTypes(_countof(filetypes), filetypes); //set file types to png
114 pDlg->SetTitle(L"Save Image"); //set title bar text
115 pDlg->SetFileName(wstrName.c_str()); //set default file name
116 pDlg->SetDefaultExtension(L"png"); //set default extension
117
118 if(FAILED(pDlg->Show(hwnd)))return E_FAIL; //show the dialog box
119 if(FAILED(pDlg->GetResult(&pItem)))return E_FAIL; //get the result item
120 if(FAILED(pItem->GetDisplayName(SIGDN_FILESYSPATH, &pwsz)))return E_FAIL; //get file name
121
122 //wstrFileName should now contain the selected file name
123
124 CLSID clsid; //for PNG class id
125 if(FAILED(GetEncoderClsid((WCHAR*)L"image/png", &clsid)))return E_FAIL; //get
126 pBitmap->Save(pwsz, &clsid, nullptr); //the actual save happens here
127
128 CoTaskMemFree(pwsz); //clean up
129
130 return S_OK;
131} //SaveBitmap
132
133#pragma endregion Save functions
134
136// Create menu functions
137
138#pragma region Create menu functions
139
143
144HMENU CreateFileMenu(HMENU hMenubar){
145 HMENU hMenu = CreateMenu();
146
147 AppendMenuW(hMenu, MF_STRING, IDM_FILE_SAVE, L"Save...");
148 AppendMenuW(hMenu, MF_STRING, IDM_FILE_PROPS, L"Properties...");
149 AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"Quit");
150
151 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&File");
152 return hMenu;
153} //CreateFileMenu
154
158
159HMENU CreateGenerateMenu(HMENU hMenubar){
160 HMENU hMenu = CreateMenu();
161
162 AppendMenuW(hMenu, MF_STRING, IDM_GENERATE_PERLINNOISE, L"Perlin noise");
163 AppendMenuW(hMenu, MF_STRING, IDM_GENERATE_VALUENOISE, L"Value noise");
164 AppendMenuW(hMenu, MF_SEPARATOR, 0, nullptr);
165 AppendMenuW(hMenu, MF_STRING, IDM_GENERATE_JUMP, L"Jump");
166 AppendMenuW(hMenu, MF_STRING, IDM_GENERATE_RESETORIGIN, L"Reset origin");
167 AppendMenuW(hMenu, MF_SEPARATOR, 0, nullptr);
168 AppendMenuW(hMenu, MF_STRING, IDM_GENERATE_RANDOMIZE, L"Randomize");
169
170 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&Generate");
171 return hMenu;
172} //CreateGenerateMenu
173
177
178HMENU CreateViewMenu(HMENU hMenubar){
179 HMENU hMenu = CreateMenu();
180
181 AppendMenuW(hMenu, MF_STRING, IDM_VIEW_COORDS, L"Coordinates");
182 AppendMenuW(hMenu, MF_STRING, IDM_VIEW_GRID, L"Grid");
183
184 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&View");
185 return hMenu;
186} //CreateViewMenu
187
191
192HMENU CreateDistributionMenu(HMENU hMenubar){
193 HMENU hMenu = CreateMenu();
194
195 AppendMenuW(hMenu, MF_STRING, IDM_DISTRIBUTION_UNIFORM, L"Uniform");
196 AppendMenuW(hMenu, MF_STRING, IDM_DISTRIBUTION_MAXIMAL, L"Maximal");
197 AppendMenuW(hMenu, MF_STRING, IDM_DISTRIBUTION_COSINE, L"Cosine");
198 AppendMenuW(hMenu, MF_STRING, IDM_DISTRIBUTION_NORMAL, L"Normal");
199 AppendMenuW(hMenu, MF_STRING, IDM_DISTRIBUTION_EXPONENTIAL, L"Exponential");
200 AppendMenuW(hMenu, MF_STRING, IDM_DISTRIBUTION_MIDPOINT, L"Midpoint displacement");
201
202 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&Distribution");
203 return hMenu;
204} //CreateDistributionMenu
205
209
210HMENU CreateHashMenu(HMENU hMenubar){
211 HMENU hMenu = CreateMenu();
212
213 AppendMenuW(hMenu, MF_STRING, IDM_HASH_PERM, L"Permutation");
214 AppendMenuW(hMenu, MF_STRING, IDM_HASH_LCON, L"Linear congruential");
215 AppendMenuW(hMenu, MF_STRING, IDM_HASH_STD, L"Std::hash");
216
217 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&Hash");
218 return hMenu;
219} //CreateHashMenu
220
224
225HMENU CreateSplineMenu(HMENU hMenubar){
226 HMENU hMenu = CreateMenu();
227
228 AppendMenuW(hMenu, MF_STRING, IDM_SPLINE_NONE, L"None");
229 AppendMenuW(hMenu, MF_STRING, IDM_SPLINE_CUBIC, L"Cubic");
230 AppendMenuW(hMenu, MF_STRING, IDM_SPLINE_QUINTIC, L"Quintic");
231
232 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&Spline");
233 return hMenu;
234} //CreateSplineMenu
235
239
240HMENU CreateSettingsMenu(HMENU hMenubar){
241 HMENU hMenu = CreateMenu();
242
243 AppendMenuW(hMenu, MF_STRING, IDM_SETTINGS_OCTAVE_UP,
244 L"Increase number of octaves");
245 AppendMenuW(hMenu, MF_STRING, IDM_SETTINGS_OCTAVE_DN,
246 L"Decrease number of octaves");
247 AppendMenuW(hMenu, MF_SEPARATOR, 0, nullptr);
248 AppendMenuW(hMenu, MF_STRING, IDM_SETTINGS_SCALE_UP, L"Scale up");
249 AppendMenuW(hMenu, MF_STRING, IDM_SETTINGS_SCALE_DN, L"Scale down");
250 AppendMenuW(hMenu, MF_SEPARATOR, 0, nullptr);
251 AppendMenuW(hMenu, MF_STRING, IDM_SETTINGS_TSIZE_UP, L"Table size up");
252 AppendMenuW(hMenu, MF_STRING, IDM_SETTINGS_TSIZE_DN, L"Table size down");
253 AppendMenuW(hMenu, MF_SEPARATOR, 0, nullptr);
254 AppendMenuW(hMenu, MF_STRING, IDM_SETTINGS_RESET, L"Reset to defaults");
255
256 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&Settings");
257 return hMenu;
258} //CreateSettingsMenu
259
262
263void CreateHelpMenu(HMENU hMenubar){
264 HMENU hMenu = CreateMenu();
265
266 AppendMenuW(hMenu, MF_STRING, IDM_HELP_HELP, L"Display help...");
267 AppendMenuW(hMenu, MF_STRING, IDM_HELP_ABOUT, L"About...");
268 AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR)hMenu, L"&Help");
269} //CreateHelpMenu
270
271#pragma endregion Create menu functions
272
274// Update menu functions
275
276#pragma region Update menu functions
277
282
283void UpdateFileMenu(HMENU hMenu, eNoise noise){
284 if(noise == eNoise::None){
285 EnableMenuItem(hMenu, IDM_FILE_SAVE, MF_GRAYED);
286 EnableMenuItem(hMenu, IDM_FILE_PROPS, MF_GRAYED);
287 } //if
288
289 else{
290 EnableMenuItem(hMenu, IDM_FILE_SAVE, MF_ENABLED);
291 EnableMenuItem(hMenu, IDM_FILE_PROPS, MF_ENABLED);
292 } //else
293} //UpdateFileMenu
294
302
303void UpdateGenerateMenu(HMENU hMenu, eNoise noise){
304 CheckMenuItem(hMenu, IDM_GENERATE_PERLINNOISE,
305 (noise == eNoise::Perlin)? MF_CHECKED: MF_UNCHECKED);
306 CheckMenuItem(hMenu, IDM_GENERATE_VALUENOISE,
307 (noise == eNoise::Value)? MF_CHECKED: MF_UNCHECKED);
308
309 EnableMenuItem(hMenu, IDM_GENERATE_RANDOMIZE,
310 (noise == eNoise::None)? MF_GRAYED: MF_ENABLED);
311 EnableMenuItem(hMenu, IDM_GENERATE_JUMP,
312 (noise == eNoise::None)? MF_GRAYED: MF_ENABLED);
313
314 EnableMenuItem(hMenu, IDM_GENERATE_RESETORIGIN,
315 (noise == eNoise::None)? MF_GRAYED: MF_ENABLED);
316} //UpdateGenerateMenu
317
322
323void UpdateViewMenu(HMENU hMenu, eNoise noise){
324 EnableMenuItem(hMenu, IDM_VIEW_COORDS,
325 (noise == eNoise::None)? MF_GRAYED: MF_ENABLED);
326 EnableMenuItem(hMenu, IDM_VIEW_GRID,
327 (noise == eNoise::None)? MF_GRAYED: MF_ENABLED);
328} //UpdateViewMenu
329
335
336void UpdateMenuItemGray(HMENU hMenu, UINT item, eNoise noise, bool bGray){
337 EnableMenuItem(hMenu, item,
338 (noise == eNoise::None || bGray)? MF_GRAYED: MF_ENABLED);
339} //UpdateMenuItemGray
340
345
346void UpdateMenuItemCheck(HMENU hMenu, UINT item, bool bCheck){
347 CheckMenuItem(hMenu, item, bCheck? MF_CHECKED: MF_UNCHECKED);
348} //UpdateMenuItemCheck
349
355
356void UpdateDistributionMenu(HMENU hMenu, eNoise noise, eDistribution distr){
357 if(noise == eNoise::None){
358 EnableMenuItem(hMenu, IDM_DISTRIBUTION_UNIFORM, MF_GRAYED);
359 EnableMenuItem(hMenu, IDM_DISTRIBUTION_MAXIMAL, MF_GRAYED);
360 EnableMenuItem(hMenu, IDM_DISTRIBUTION_COSINE, MF_GRAYED);
361 EnableMenuItem(hMenu, IDM_DISTRIBUTION_NORMAL, MF_GRAYED);
362 EnableMenuItem(hMenu, IDM_DISTRIBUTION_EXPONENTIAL, MF_GRAYED);
363 EnableMenuItem(hMenu, IDM_DISTRIBUTION_MIDPOINT, MF_GRAYED);
364 } //if
365
366 else{
367 EnableMenuItem(hMenu, IDM_DISTRIBUTION_UNIFORM, MF_ENABLED);
368 EnableMenuItem(hMenu, IDM_DISTRIBUTION_MAXIMAL, MF_ENABLED);
369 EnableMenuItem(hMenu, IDM_DISTRIBUTION_COSINE, MF_ENABLED);
370 EnableMenuItem(hMenu, IDM_DISTRIBUTION_NORMAL, MF_ENABLED);
371 EnableMenuItem(hMenu, IDM_DISTRIBUTION_EXPONENTIAL, MF_ENABLED);
372 EnableMenuItem(hMenu, IDM_DISTRIBUTION_MIDPOINT, MF_ENABLED);
373 } //if
374
375 CheckMenuItem(hMenu, IDM_DISTRIBUTION_UNIFORM,
376 distr == eDistribution::Uniform? MF_CHECKED: MF_UNCHECKED);
377 CheckMenuItem(hMenu, IDM_DISTRIBUTION_MAXIMAL,
378 distr == eDistribution::Maximal? MF_CHECKED: MF_UNCHECKED);
379 CheckMenuItem(hMenu, IDM_DISTRIBUTION_COSINE,
380 distr == eDistribution::Cosine? MF_CHECKED: MF_UNCHECKED);
381 CheckMenuItem(hMenu, IDM_DISTRIBUTION_NORMAL,
382 distr == eDistribution::Normal? MF_CHECKED: MF_UNCHECKED);
383 CheckMenuItem(hMenu, IDM_DISTRIBUTION_EXPONENTIAL,
384 distr == eDistribution::Exponential? MF_CHECKED: MF_UNCHECKED);
385 CheckMenuItem(hMenu, IDM_DISTRIBUTION_MIDPOINT,
386 distr == eDistribution::Midpoint? MF_CHECKED: MF_UNCHECKED);
387} //UpdateDistributionMenu
388
394
395void UpdateHashMenu(HMENU hMenu, eNoise noise, eHash h){
396 switch(noise){
397 case eNoise::None:
398 EnableMenuItem(hMenu, IDM_HASH_PERM, MF_GRAYED);
399 EnableMenuItem(hMenu, IDM_HASH_LCON, MF_GRAYED);
400 EnableMenuItem(hMenu, IDM_HASH_STD, MF_GRAYED);
401 break;
402
403 case eNoise::Perlin:
404 case eNoise::Value:
405 EnableMenuItem(hMenu, IDM_HASH_PERM, MF_ENABLED);
406 EnableMenuItem(hMenu, IDM_HASH_LCON, MF_ENABLED);
407 EnableMenuItem(hMenu, IDM_HASH_STD, MF_ENABLED);
408 break;
409 } //switch
410
411 CheckMenuItem(hMenu, IDM_HASH_PERM,
412 (h == eHash::Permutation)? MF_CHECKED: MF_UNCHECKED);
413 CheckMenuItem(hMenu, IDM_HASH_LCON,
414 (h == eHash::LinearCongruential)? MF_CHECKED: MF_UNCHECKED);
415 CheckMenuItem(hMenu, IDM_HASH_STD,
416 (h == eHash::Std)? MF_CHECKED: MF_UNCHECKED);
417} //UpdateHashMenu
418
424
425void UpdateSplineMenu(HMENU hMenu, eNoise noise, eSpline spline){
426 switch(noise){
427 case eNoise::None:
428 EnableMenuItem(hMenu, IDM_SPLINE_NONE, MF_GRAYED);
429 EnableMenuItem(hMenu, IDM_SPLINE_CUBIC, MF_GRAYED);
430 EnableMenuItem(hMenu, IDM_SPLINE_QUINTIC, MF_GRAYED);
431 break;
432
433 case eNoise::Perlin:
434 case eNoise::Value:
435 EnableMenuItem(hMenu, IDM_SPLINE_NONE, MF_ENABLED);
436 EnableMenuItem(hMenu, IDM_SPLINE_CUBIC, MF_ENABLED);
437 EnableMenuItem(hMenu, IDM_SPLINE_QUINTIC, MF_ENABLED);
438 break;
439 } //switch
440
441 CheckMenuItem(hMenu, IDM_SPLINE_NONE,
442 (spline == eSpline::None)? MF_CHECKED: MF_UNCHECKED);
443 CheckMenuItem(hMenu, IDM_SPLINE_CUBIC,
444 (spline == eSpline::Cubic)? MF_CHECKED: MF_UNCHECKED);
445 CheckMenuItem(hMenu, IDM_SPLINE_QUINTIC,
446 (spline == eSpline::Quintic)? MF_CHECKED: MF_UNCHECKED);
447} //UpdateSplineMenu
448
453
454void UpdateSettingsMenu(HMENU hMenu, eNoise noise){
455 if(noise == eNoise::None){
456 EnableMenuItem(hMenu, IDM_SETTINGS_OCTAVE_UP, MF_GRAYED);
457 EnableMenuItem(hMenu, IDM_SETTINGS_OCTAVE_DN, MF_GRAYED);
458 EnableMenuItem(hMenu, IDM_SETTINGS_SCALE_UP, MF_GRAYED);
459 EnableMenuItem(hMenu, IDM_SETTINGS_SCALE_DN, MF_GRAYED);
460 EnableMenuItem(hMenu, IDM_SETTINGS_TSIZE_UP, MF_GRAYED);
461 EnableMenuItem(hMenu, IDM_SETTINGS_TSIZE_DN, MF_GRAYED);
462 } //if
463} //UpdateSettingsMenu
eDistribution
Distribution.
Definition: Defines.h:54
eSpline
Spline type.
Definition: Defines.h:62
eHash
Hash function type.
Definition: Defines.h:46
eNoise
Perlin noise type.
Definition: Defines.h:38
Useful includes.
HMENU CreateViewMenu(HMENU hMenubar)
Create View menu.
void UpdateGenerateMenu(HMENU hMenu, eNoise noise)
Update Generate menu.
HMENU CreateSplineMenu(HMENU hMenubar)
Create Spline menu.
HMENU CreateHashMenu(HMENU hMenubar)
Create Hash menu.
void UpdateHashMenu(HMENU hMenu, eNoise noise, eHash h)
Update Hash menu.
void UpdateViewMenu(HMENU hMenu, eNoise noise)
Update View menu.
HMENU CreateDistributionMenu(HMENU hMenubar)
Create Distribution menu.
void UpdateSettingsMenu(HMENU hMenu, eNoise noise)
Update Settings menu.
HMENU CreateSettingsMenu(HMENU hMenubar)
Create Settings menu.
void UpdateSplineMenu(HMENU hMenu, eNoise noise, eSpline spline)
Update Spline menu.
HRESULT SaveBitmap(HWND hwnd, const std::wstring &wstrName, Gdiplus::Bitmap *pBitmap)
Save bitmap to file.
HRESULT GetEncoderClsid(const WCHAR *format, CLSID *pClsid)
void UpdateMenuItemGray(HMENU hMenu, UINT item, eNoise noise, bool bGray)
Update menu item bool.
ULONG_PTR InitGDIPlus()
Initialize GDI+.
void UpdateFileMenu(HMENU hMenu, eNoise noise)
Update File menu.
HMENU CreateFileMenu(HMENU hMenubar)
Create File menu.
void UpdateDistributionMenu(HMENU hMenu, eNoise noise, eDistribution distr)
Update Distribution menu.
void UpdateMenuItemCheck(HMENU hMenu, UINT item, bool bCheck)
Update menu item check.
void CreateHelpMenu(HMENU hMenubar)
Create Help menu.
HMENU CreateGenerateMenu(HMENU hMenubar)
Create Generate menu.
Interface for some helpful Windows-specific functions.
#define IDM_SETTINGS_TSIZE_UP
Menu id for table size up.
#define IDM_VIEW_GRID
Menu id for view grid.
#define IDM_GENERATE_VALUENOISE
Menu id for Value Noise.
#define IDM_DISTRIBUTION_EXPONENTIAL
Menu id for exponential distribution.
#define IDM_DISTRIBUTION_UNIFORM
Menu id for uniform distribution.
#define IDM_HASH_LCON
Menu id for linear congruential hash.
#define IDM_DISTRIBUTION_NORMAL
Menu id for normal distribution.
#define IDM_GENERATE_PERLINNOISE
Menu id for Perlin Noise.
#define IDM_FILE_SAVE
Menu id for Save.
#define IDM_SPLINE_QUINTIC
Menu id for quintic spline.
#define IDM_SPLINE_NONE
Menu id for cubic spline.
#define IDM_HASH_STD
Menu id for std::hash.
#define IDM_SETTINGS_SCALE_UP
Menu id for scale up.
#define IDM_SETTINGS_SCALE_DN
Menu id for scale down.
#define IDM_GENERATE_JUMP
Menu id for jump.
#define IDM_FILE_QUIT
Menu id for Quit.
#define IDM_HASH_PERM
Menu id for permutation hash.
#define IDM_SETTINGS_RESET
Menu id for reset settings.
#define IDM_HELP_HELP
Menu id for display help.
#define IDM_SETTINGS_TSIZE_DN
Menu id for table size down.
#define IDM_SETTINGS_OCTAVE_UP
Menu id for octave up.
#define IDM_SPLINE_CUBIC
Menu id for no spline.
#define IDM_SETTINGS_OCTAVE_DN
Menu id for octave down.
#define IDM_DISTRIBUTION_COSINE
Menu id for cosine distribution.
#define IDM_GENERATE_RANDOMIZE
Menu id for regenerate Noise.
#define IDM_DISTRIBUTION_MAXIMAL
Menu id for midpoint displacement.
#define IDM_DISTRIBUTION_MIDPOINT
Menu id for midpoint displacement.
#define IDM_HELP_ABOUT
Menu id for display About info.
#define IDM_VIEW_COORDS
Menu id for view coordinates.
#define IDM_GENERATE_RESETORIGIN
Menu id for reset origin.
#define IDM_FILE_PROPS
Menu id for Properties.