editor.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*******************************************************************************************
  2. *
  3. * raylib-extras [ImGui] example - editor
  4. *
  5. * This is a more complex ImGui Integration
  6. * It shows how to build windows on top of 2d and 3d views using a render texture
  7. *
  8. * Copyright (c) 2021 Jeffery Myers
  9. *
  10. ********************************************************************************************/
  11. #include "raylib.h"
  12. #include "raymath.h"
  13. #include "imgui.h"
  14. #include "rlImGui.h"
  15. #include "rlImGuiColors.h"
  16. bool Quit = false;
  17. bool ImGuiDemoOpen = false;
  18. // DPI scaling functions
  19. float ScaleToDPIF(float value)
  20. {
  21. return GetWindowScaleDPI().x * value;
  22. }
  23. int ScaleToDPII(int value)
  24. {
  25. return int(GetWindowScaleDPI().x * value);
  26. }
  27. class DocumentWindow
  28. {
  29. public:
  30. bool Open = false;
  31. RenderTexture ViewTexture;
  32. virtual void Setup() = 0;
  33. virtual void Shutdown() = 0;
  34. virtual void Show() = 0;
  35. virtual void Update() = 0;
  36. bool Focused = false;
  37. Rectangle ContentRect = { 0 };
  38. };
  39. class ImageViewerWindow : public DocumentWindow
  40. {
  41. public:
  42. void Setup() override
  43. {
  44. Camera.zoom = 1;
  45. Camera.target.x = 0;
  46. Camera.target.y = 0;
  47. Camera.rotation = 0;
  48. Camera.offset.x = GetScreenWidth() / 2.0f;
  49. Camera.offset.y = GetScreenHeight() / 2.0f;
  50. ViewTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
  51. ImageTexture = LoadTexture("resources/parrots.png");
  52. UpdateRenderTexture();
  53. }
  54. void Show() override
  55. {
  56. ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
  57. ImGui::SetNextWindowSizeConstraints(ImVec2(ScaleToDPIF(400.0f), ScaleToDPIF(400.0f)), ImVec2(float(GetScreenWidth()), float(GetScreenHeight())));
  58. Focused = false;
  59. if (ImGui::Begin("Image Viewer", &Open, ImGuiWindowFlags_NoScrollbar))
  60. {
  61. // save off the screen space content rectangle
  62. ContentRect = { ImGui::GetWindowPos().x + ImGui::GetCursorScreenPos().x, ImGui::GetWindowPos().y + ImGui::GetCursorScreenPos().y, ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y };
  63. Focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
  64. ImVec2 size = ImGui::GetContentRegionAvail();
  65. // center the scratch pad in the view
  66. Rectangle viewRect = { 0 };
  67. viewRect.x = ViewTexture.texture.width / 2 - size.x / 2;
  68. viewRect.y = ViewTexture.texture.height / 2 - size.y / 2;
  69. viewRect.width = size.x;
  70. viewRect.height = -size.y;
  71. if (ImGui::BeginChild("Toolbar", ImVec2(ImGui::GetContentRegionAvail().x, 25)))
  72. {
  73. ImGui::SetCursorPosX(2);
  74. ImGui::SetCursorPosY(3);
  75. if (ImGui::Button("None"))
  76. {
  77. CurrentToolMode = ToolMode::None;
  78. }
  79. ImGui::SameLine();
  80. if (ImGui::Button("Move"))
  81. {
  82. CurrentToolMode = ToolMode::Move;
  83. }
  84. ImGui::SameLine();
  85. switch (CurrentToolMode)
  86. {
  87. case ToolMode::None:
  88. ImGui::TextUnformatted("No Tool");
  89. break;
  90. case ToolMode::Move:
  91. ImGui::TextUnformatted("Move Tool");
  92. break;
  93. default:
  94. break;
  95. }
  96. ImGui::SameLine();
  97. ImGui::TextUnformatted(TextFormat("camera target X%f Y%f", Camera.target.x, Camera.target.y));
  98. ImGui::EndChild();
  99. }
  100. rlImGuiImageRect(&ViewTexture.texture, int(size.x), int(size.y), viewRect);
  101. }
  102. ImGui::End();
  103. ImGui::PopStyleVar();
  104. }
  105. void Update() override
  106. {
  107. if (!Open)
  108. return;
  109. if (IsWindowResized())
  110. {
  111. UnloadRenderTexture(ViewTexture);
  112. ViewTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
  113. Camera.offset.x = GetScreenWidth() / 2.0f;
  114. Camera.offset.y = GetScreenHeight() / 2.0f;
  115. }
  116. Vector2 mousePos = GetMousePosition();
  117. if (Focused)
  118. {
  119. if (CurrentToolMode == ToolMode::Move)
  120. {
  121. // only do this tool when the mouse is in the content area of the window
  122. if (IsMouseButtonDown(0) && CheckCollisionPointRec(mousePos, ContentRect))
  123. {
  124. if (!Dragging)
  125. {
  126. LastMousePos = mousePos;
  127. LastTarget = Camera.target;
  128. }
  129. Dragging = true;
  130. Vector2 mouseDelta = Vector2Subtract(LastMousePos, mousePos);
  131. mouseDelta.x /= Camera.zoom;
  132. mouseDelta.y /= Camera.zoom;
  133. Camera.target = Vector2Add(LastTarget, mouseDelta);
  134. DirtyScene = true;
  135. }
  136. else
  137. {
  138. Dragging = false;
  139. }
  140. }
  141. }
  142. else
  143. {
  144. Dragging = false;
  145. }
  146. if (DirtyScene)
  147. {
  148. DirtyScene = false;
  149. UpdateRenderTexture();
  150. }
  151. }
  152. Texture ImageTexture;
  153. Camera2D Camera = { 0 };
  154. Vector2 LastMousePos = { 0 };
  155. Vector2 LastTarget = { 0 };
  156. bool Dragging = false;
  157. bool DirtyScene = false;
  158. enum class ToolMode
  159. {
  160. None,
  161. Move,
  162. };
  163. ToolMode CurrentToolMode = ToolMode::None;
  164. void UpdateRenderTexture()
  165. {
  166. BeginTextureMode(ViewTexture);
  167. ClearBackground(BLUE);
  168. // camera with our view offset with a world origin of 0,0
  169. BeginMode2D(Camera);
  170. // center the image at 0,0
  171. DrawTexture(ImageTexture, ImageTexture.width / -2, ImageTexture.height / -2, WHITE);
  172. EndMode2D();
  173. EndTextureMode();
  174. }
  175. void Shutdown() override
  176. {
  177. UnloadRenderTexture(ViewTexture);
  178. UnloadTexture(ImageTexture);
  179. }
  180. };
  181. class SceneViewWindow : public DocumentWindow
  182. {
  183. public:
  184. Camera3D Camera = { 0 };
  185. void Setup() override
  186. {
  187. ViewTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
  188. Camera.fovy = 45;
  189. Camera.up.y = 1;
  190. Camera.position.y = 3;
  191. Camera.position.z = -25;
  192. Image img = GenImageChecked(ScaleToDPII(256), ScaleToDPII(256), ScaleToDPII(32), ScaleToDPII(32), DARKGRAY, WHITE);
  193. GridTexture = LoadTextureFromImage(img);
  194. UnloadImage(img);
  195. GenTextureMipmaps(&GridTexture);
  196. SetTextureFilter(GridTexture, TEXTURE_FILTER_ANISOTROPIC_16X);
  197. SetTextureWrap(GridTexture, TEXTURE_WRAP_CLAMP);
  198. }
  199. void Shutdown() override
  200. {
  201. UnloadRenderTexture(ViewTexture);
  202. UnloadTexture(GridTexture);
  203. }
  204. void Show() override
  205. {
  206. ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
  207. ImGui::SetNextWindowSizeConstraints(ImVec2(ScaleToDPIF(400.0f), ScaleToDPIF(400.0f)), ImVec2((float)GetScreenWidth(), (float)GetScreenHeight()));
  208. if (ImGui::Begin("3D View", &Open, ImGuiWindowFlags_NoScrollbar))
  209. {
  210. Focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows);
  211. // draw the view
  212. rlImGuiImageRenderTextureFit(&ViewTexture, true);
  213. }
  214. ImGui::End();
  215. ImGui::PopStyleVar();
  216. }
  217. void Update() override
  218. {
  219. if (!Open)
  220. return;
  221. if (IsWindowResized())
  222. {
  223. UnloadRenderTexture(ViewTexture);
  224. ViewTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
  225. }
  226. float period = 10;
  227. float magnitude = 25;
  228. Camera.position.x = sinf(float(GetTime() / period)) * magnitude;
  229. BeginTextureMode(ViewTexture);
  230. ClearBackground(SKYBLUE);
  231. BeginMode3D(Camera);
  232. // grid of cube trees on a plane to make a "world"
  233. DrawPlane(Vector3{ 0, 0, 0 }, Vector2{ 50, 50 }, BEIGE); // simple world plane
  234. float spacing = 4;
  235. int count = 5;
  236. for (float x = -count * spacing; x <= count * spacing; x += spacing)
  237. {
  238. for (float z = -count * spacing; z <= count * spacing; z += spacing)
  239. {
  240. Vector3 pos = { x, 0.5f, z };
  241. Vector3 min = { x - 0.5f,0,z - 0.5f };
  242. Vector3 max = { x + 0.5f,1,z + 0.5f };
  243. DrawCube(Vector3{ x, 1.5f, z }, 1, 1, 1, GREEN);
  244. DrawCube(Vector3{ x, 0.5f, z }, 0.25f, 1, 0.25f, BROWN);
  245. }
  246. }
  247. EndMode3D();
  248. EndTextureMode();
  249. }
  250. Texture2D GridTexture = { 0 };
  251. };
  252. ImageViewerWindow ImageViewer;
  253. SceneViewWindow SceneView;
  254. void DoMainMenu()
  255. {
  256. if (ImGui::BeginMainMenuBar())
  257. {
  258. if (ImGui::BeginMenu("File"))
  259. {
  260. if (ImGui::MenuItem("Exit"))
  261. Quit = true;
  262. ImGui::EndMenu();
  263. }
  264. if (ImGui::BeginMenu("Window"))
  265. {
  266. ImGui::MenuItem("ImGui Demo", nullptr, &ImGuiDemoOpen);
  267. ImGui::MenuItem("Image Viewer", nullptr, &ImageViewer.Open);
  268. ImGui::MenuItem("3D View", nullptr, &SceneView.Open);
  269. ImGui::EndMenu();
  270. }
  271. ImGui::EndMainMenuBar();
  272. }
  273. }
  274. int main(int argc, char* argv[])
  275. {
  276. // Initialization
  277. //--------------------------------------------------------------------------------------
  278. int screenWidth = 1900;
  279. int screenHeight = 900;
  280. // do not set the FLAG_WINDOW_HIGHDPI flag, that scales a low res framebuffer up to the native resolution.
  281. // use the native resolution and scale your geometry.
  282. SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT);
  283. InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Editor Example");
  284. SetTargetFPS(144);
  285. rlImGuiSetup(true);
  286. ImGui::GetIO().ConfigWindowsMoveFromTitleBarOnly = true;
  287. ImageViewer.Setup();
  288. ImageViewer.Open = true;
  289. SceneView.Setup();
  290. SceneView.Open = true;
  291. // Main game loop
  292. while (!WindowShouldClose() && !Quit) // Detect window close button or ESC key
  293. {
  294. ImageViewer.Update();
  295. SceneView.Update();
  296. BeginDrawing();
  297. ClearBackground(DARKGRAY);
  298. rlImGuiBegin();
  299. DoMainMenu();
  300. if (ImGuiDemoOpen)
  301. ImGui::ShowDemoWindow(&ImGuiDemoOpen);
  302. if (ImageViewer.Open)
  303. ImageViewer.Show();
  304. if (SceneView.Open)
  305. SceneView.Show();
  306. rlImGuiEnd();
  307. EndDrawing();
  308. //----------------------------------------------------------------------------------
  309. }
  310. rlImGuiShutdown();
  311. ImageViewer.Shutdown();
  312. SceneView.Shutdown();
  313. // De-Initialization
  314. //--------------------------------------------------------------------------------------
  315. CloseWindow(); // Close window and OpenGL context
  316. //--------------------------------------------------------------------------------------
  317. return 0;
  318. }