SpriteBatch.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #include <Urho3D/Urho3DAll.h>
  2. #include <Urho3D/Graphics/SpriteBatch.h>
  3. class Game : public Application
  4. {
  5. URHO3D_OBJECT(Game, Application);
  6. public:
  7. SharedPtr<Scene> scene_;
  8. SharedPtr<Node> cameraNode_;
  9. float yaw_ = 0.0f;
  10. float pitch_ = 0.0f;
  11. SharedPtr<SpriteBatch> worldSpaceSpriteBatch_;
  12. SharedPtr<SpriteBatch> screenSpaceSpriteBatch_;
  13. SharedPtr<SpriteBatch> virtualSpriteBatch_;
  14. float fpsTimeCounter_ = 0.0f;
  15. i32 fpsFrameCounter_ = 0;
  16. i32 fpsValue_ = 0;
  17. i32 currentTest_ = 1;
  18. float angle_ = 0.0f;
  19. float scale_ = 0.0f;
  20. Game(Context* context) : Application(context)
  21. {
  22. }
  23. void Setup()
  24. {
  25. engineParameters_[EP_WINDOW_RESIZABLE] = true;
  26. engineParameters_[EP_FULL_SCREEN] = false;
  27. engineParameters_[EP_WINDOW_WIDTH] = 1200;
  28. engineParameters_[EP_WINDOW_HEIGHT] = 900;
  29. engineParameters_[EP_FRAME_LIMITER] = false;
  30. engineParameters_[EP_LOG_NAME] = GetSubsystem<FileSystem>()->GetAppPreferencesDir("urho3d", "logs") + "56_SpriteBatch.log";
  31. }
  32. void Start()
  33. {
  34. //GetSubsystem<Engine>()->SetMaxFps(10);
  35. CreateScene();
  36. SetupViewport();
  37. SubscribeToEvents();
  38. XMLFile* xmlFile = GetSubsystem<ResourceCache>()->GetResource<XMLFile>("UI/DefaultStyle.xml");
  39. DebugHud* debugHud = engine_->CreateDebugHud();
  40. debugHud->SetDefaultStyle(xmlFile);
  41. screenSpaceSpriteBatch_ = new SpriteBatch(context_);
  42. worldSpaceSpriteBatch_ = new SpriteBatch(context_);
  43. worldSpaceSpriteBatch_->camera_ = cameraNode_->GetComponent<Camera>();
  44. worldSpaceSpriteBatch_->compareMode_ = CMP_LESSEQUAL;
  45. virtualSpriteBatch_ = new SpriteBatch(context_);
  46. virtualSpriteBatch_->virtualScreenSize_ = IntVector2(700, 600);
  47. }
  48. void SetupViewport()
  49. {
  50. SharedPtr<Viewport> viewport(new Viewport(context_, scene_, cameraNode_->GetComponent<Camera>()));
  51. GetSubsystem<Renderer>()->SetViewport(0, viewport);
  52. }
  53. void CreateScene()
  54. {
  55. ResourceCache* cache = GetSubsystem<ResourceCache>();
  56. scene_ = new Scene(context_);
  57. scene_->CreateComponent<Octree>();
  58. Node* planeNode = scene_->CreateChild("Plane");
  59. planeNode->SetScale(Vector3(100.0f, 1.0f, 100.0f));
  60. StaticModel* planeObject = planeNode->CreateComponent<StaticModel>();
  61. planeObject->SetModel(cache->GetResource<Model>("Models/Plane.mdl"));
  62. planeObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));
  63. Node* lightNode = scene_->CreateChild("DirectionalLight");
  64. lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f));
  65. Light* light = lightNode->CreateComponent<Light>();
  66. light->SetColor(Color(0.5f, 0.5f, 0.5f));
  67. light->SetLightType(LIGHT_DIRECTIONAL);
  68. light->SetCastShadows(true);
  69. light->SetShadowBias(BiasParameters(0.00025f, 0.5f));
  70. light->SetShadowCascade(CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f));
  71. //light->SetShadowIntensity(0.5f);
  72. Node* zoneNode = scene_->CreateChild("Zone");
  73. Zone* zone = zoneNode->CreateComponent<Zone>();
  74. zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
  75. zone->SetAmbientColor(Color(0.5f, 0.5f, 0.5f));
  76. zone->SetFogColor(Color(0.4f, 0.5f, 0.8f));
  77. zone->SetFogStart(100.0f);
  78. zone->SetFogEnd(300.0f);
  79. constexpr i32 NUM_OBJECTS = 20;
  80. for (i32 i = 0; i < NUM_OBJECTS; ++i)
  81. {
  82. Node* mushroomNode = scene_->CreateChild("Mushroom");
  83. mushroomNode->SetPosition(Vector3(Random(90.0f) - 45.0f, 0.0f, Random(90.0f) - 45.0f));
  84. mushroomNode->SetRotation(Quaternion(0.0f, Random(360.0f), 0.0f));
  85. mushroomNode->SetScale(0.5f + Random(2.0f));
  86. StaticModel* mushroomObject = mushroomNode->CreateComponent<StaticModel>();
  87. mushroomObject->SetModel(cache->GetResource<Model>("Models/Mushroom.mdl"));
  88. mushroomObject->SetMaterial(cache->GetResource<Material>("Materials/Mushroom.xml"));
  89. mushroomObject->SetCastShadows(true);
  90. }
  91. cameraNode_ = scene_->CreateChild("Camera");
  92. cameraNode_->CreateComponent<Camera>();
  93. cameraNode_->SetPosition(Vector3(0.0f, 2.0f, -5.0f));
  94. }
  95. void MoveCamera(float timeStep)
  96. {
  97. constexpr float MOVE_SPEED = 20.0f;
  98. constexpr float MOUSE_SENSITIVITY = 0.1f;
  99. Input* input = GetSubsystem<Input>();
  100. IntVector2 mouseMove = input->GetMouseMove();
  101. yaw_ += MOUSE_SENSITIVITY * mouseMove.x_;
  102. pitch_ += MOUSE_SENSITIVITY * mouseMove.y_;
  103. pitch_ = Clamp(pitch_, -90.0f, 90.0f);
  104. cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f));
  105. if (input->GetKeyDown(KEY_W))
  106. cameraNode_->Translate(Vector3::FORWARD * MOVE_SPEED * timeStep);
  107. if (input->GetKeyDown(KEY_S))
  108. cameraNode_->Translate(Vector3::BACK * MOVE_SPEED * timeStep);
  109. if (input->GetKeyDown(KEY_A))
  110. cameraNode_->Translate(Vector3::LEFT * MOVE_SPEED * timeStep);
  111. if (input->GetKeyDown(KEY_D))
  112. cameraNode_->Translate(Vector3::RIGHT * MOVE_SPEED * timeStep);
  113. }
  114. void SubscribeToEvents()
  115. {
  116. SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(Game, HandleUpdate));
  117. SubscribeToEvent(E_ENDVIEWRENDER, URHO3D_HANDLER(Game, HandleEndViewRender));
  118. }
  119. void HandleUpdate(StringHash eventType, VariantMap& eventData)
  120. {
  121. using namespace Update;
  122. float timeStep = eventData[P_TIMESTEP].GetFloat();
  123. Input* input = GetSubsystem<Input>();
  124. Time* time = GetSubsystem<Time>();
  125. if (input->GetKeyDown(KEY_1))
  126. currentTest_ = 1;
  127. else if (input->GetKeyDown(KEY_2))
  128. currentTest_ = 2;
  129. else if (input->GetKeyDown(KEY_3))
  130. currentTest_ = 3;
  131. if (input->GetMouseButtonDown(MOUSEB_RIGHT))
  132. {
  133. input->SetMouseVisible(false);
  134. MoveCamera(timeStep);
  135. }
  136. else
  137. {
  138. input->SetMouseVisible(true);
  139. }
  140. fpsTimeCounter_ += timeStep;
  141. fpsFrameCounter_++;
  142. if (fpsTimeCounter_ >= 1.0f)
  143. {
  144. fpsTimeCounter_ = 0.0f;
  145. fpsValue_ = fpsFrameCounter_;
  146. fpsFrameCounter_ = 0;
  147. }
  148. angle_ += timeStep * 100.0f;
  149. angle_ = fmod(angle_, 360.0f);
  150. scale_ = 1.0f + Sin(time->GetElapsedTime() * 200.0f) * 0.3f;
  151. }
  152. bool collide_ = true;
  153. void HandleEndViewRender(StringHash eventType, VariantMap& eventData)
  154. {
  155. Input* input = GetSubsystem<Input>();
  156. ResourceCache* cache = GetSubsystem<ResourceCache>();
  157. Graphics* graphics = GetSubsystem<Graphics>();
  158. // Размер текстуры должен быть степенью двойки (64, 128, 256, ...),
  159. // иначе она не будет работать в GL ES 1.0 (в вебе).
  160. // В некоторых случаях (например для "Urho2D/Stretchable.png" - 200x200) может помочь
  161. // Texture2D* head = cache->GetResource<Texture2D>("Urho2D/Stretchable.png");
  162. // if (head->GetAddressMode(COORD_U) == ADDRESS_WRAP)
  163. // {
  164. // head->SetAddressMode(COORD_U, ADDRESS_CLAMP);
  165. // head->SetAddressMode(COORD_V, ADDRESS_CLAMP);
  166. // }
  167. // как это сделано в Sprite2D.cpp.
  168. // В других случаях ("Urho2D/imp/imp_head.png" - 238x149) и это не помогает.
  169. Texture2D* head = cache->GetResource<Texture2D>("Textures/FishBoneLogo.png");
  170. Font* font = cache->GetResource<Font>("Fonts/Anonymous Pro.ttf");
  171. // Очистка экрана. Если сцена пустая, то можно просто задать цвет зоны
  172. //GetSubsystem<Graphics>()->Clear(CLEAR_COLOR, Color::GREEN);
  173. String str;
  174. if (currentTest_ == 1)
  175. {
  176. screenSpaceSpriteBatch_->SetShapeColor(0xFFFF0000);
  177. screenSpaceSpriteBatch_->DrawCircle(500.f, 200.f, 200.f);
  178. Vector2 origin = Vector2(head->GetWidth() * 0.5f, head->GetHeight() * 0.5f);
  179. screenSpaceSpriteBatch_->DrawSprite(head, Vector2(200.0f, 200.0f), nullptr, 0xFFFFFFFF, angle_, origin, Vector2(scale_, scale_));
  180. str = "QqWЙйр";
  181. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 60.f), 0xFF00FF00, 0.0f, Vector2::ZERO, Vector2::ONE, FlipModes::None);
  182. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(104.0f, 60.f), 0xFF00FF00, 0.0f, Vector2::ZERO, Vector2::ONE, FlipModes::Horizontally);
  183. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 100.f), 0xFF00FF00, 0.0f, Vector2::ZERO, Vector2::ONE, FlipModes::Vertically);
  184. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(104.0f, 100.f), 0xFF00FF00, 0.0f, Vector2::ZERO, Vector2::ONE, FlipModes::Vertically | FlipModes::Both);
  185. // screenSpaceSpriteBatch_->Flush(); не вызываем, так как еще текст будем выводить
  186. }
  187. else if (currentTest_ == 2)
  188. {
  189. worldSpaceSpriteBatch_->DrawSprite(head, Vector2(0.0f, 0.0f), nullptr, 0xFFFFFFFF, 0.0f, Vector2::ZERO, Vector2(0.01f, 0.01f));
  190. worldSpaceSpriteBatch_->Flush();
  191. }
  192. else if (currentTest_ == 3)
  193. {
  194. virtualSpriteBatch_->SetShapeColor(0x90FF0000);
  195. virtualSpriteBatch_->DrawAABBSolid(Vector2::ZERO, (Vector2)virtualSpriteBatch_->virtualScreenSize_);
  196. virtualSpriteBatch_->DrawSprite(head, Vector2(200.0f, 200.0f));
  197. // Преобразуем координаты мыши из оконных координат в виртуальные координаты
  198. Vector2 virtualMousePos = virtualSpriteBatch_->GetVirtualPos(Vector2(GetSubsystem<Input>()->GetMousePosition()));
  199. virtualSpriteBatch_->SetShapeColor(0xFFFFFFFF);
  200. virtualSpriteBatch_->DrawArrow({100.0f, 100.f}, virtualMousePos, 10);
  201. virtualSpriteBatch_->Flush();
  202. }
  203. // Выводим индекс текущего теста
  204. str = "Текущий тест: " + String(currentTest_) + " (используйте 1, 2, 3 для переключения)";
  205. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 0.f), 0xFFFFFFFF);
  206. // Выводим описание текущего теста
  207. if (currentTest_ == 1)
  208. {
  209. str = "Рисование в экранном пространстве";
  210. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 24.f), 0xFFFFFFFF);
  211. }
  212. else if (currentTest_ == 2)
  213. {
  214. str = "Рисование в пространстве сцены";
  215. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 24.f), 0xFFFFFFFF);
  216. }
  217. else if (currentTest_ == 3)
  218. {
  219. str = "Использование виртуальных координат";
  220. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 24.f), 0xFFFFFFFF);
  221. str = "Синий прямоугольник - границы виртуального экрана (700x600 виртуальных пикселей)";
  222. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 48.f), 0xFFFFFFFF);
  223. str = "Меняйте размеры окна, чтобы увидеть, как виртуальный экран вписывается в окно";
  224. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, Vector2(4.0f, 72.f), 0xFFFFFFFF);
  225. }
  226. // Выводим подсказку про ПКМ
  227. str = "Зажмите ПКМ для перемещения по сцене";
  228. Vector2 pos{graphics->GetWidth() - 550.f, graphics->GetHeight() - 36.f}; // TODO: Добавить MeasureString
  229. screenSpaceSpriteBatch_->DrawString(str, font, 20.f, pos, 0xFFFFFFFF);
  230. // Выводим FPS
  231. str = "FPS: " + String(fpsValue_);
  232. pos = {10.f, graphics->GetHeight() - 56.f};
  233. screenSpaceSpriteBatch_->DrawString(str, font, 40.f, pos, 0xFF0000FF);
  234. screenSpaceSpriteBatch_->Flush();
  235. }
  236. };
  237. URHO3D_DEFINE_APPLICATION_MAIN(Game)