editor.cpp 8.7 KB

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