質問内容
提示コードのvoid Engine::SpriteRenderer::Render()
関数部ですがSDL_Texture* texture = IMG_LoadTexture(Context::GetRenderer(),"./tile4.png");
を使うと正常に描画できるのですがsprite.handle
を使って描画すると描画されません。これはなぜでしょうか? 非同期で画像ロードしてしっかりと待機していて同じポインターを指しているのですが原因がわかりません。デストラクタ等は定義、宣言していません。
知りたいこと
画像が描画できない原因が知りたい
確認したいこと
SDL_GetError()
を実行しましたが何も表示されていません。
#ソースコード 全文
画像ロード関数
cpp
1#include <iostream> 2#include <Context.hpp> 3#include <vector> 4#include <functional> 5#include <future> 6#include <iostream> 7#include <glm/glm.hpp> 8#include <thread> 9#include <mutex> 10#include <condition_variable> 11#include <chrono> 12#include <random> 13#include <thread> 14 15struct Sprite 16{ 17 SDL_Texture *handle; 18 std::string path; 19}; 20 21 22std::vector<Sprite> sprites; //ロードした画像リスト 23std::vector<std::string> nowLoad; //現在ロード中の画像リスト 24std::mutex loadMutex; 25std::condition_variable loadCV; 26 27std::chrono::_V2::system_clock::time_point startTime; 28 29void SetStartTime() 30{ 31 startTime = std::chrono::high_resolution_clock::now(); 32} 33 34int GetEndTime() 35{ 36 37 auto endTime = std::chrono::high_resolution_clock::now(); 38 auto time = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime); 39 40 return time.count(); 41} 42 43/*############################################################## 44# 乱数取得 45##############################################################*/ 46int GetRandom(int rand) 47{ 48 // 現在の時間を取得して種(seed)として使用する 49 auto now = std::chrono::high_resolution_clock::now(); 50 auto seed = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count(); 51 52 // 乱数生成器を初期化 53 std::mt19937_64 generator(seed); 54 55 // ミリ秒単位の乱数を生成 56 std::uniform_int_distribution<int> distribution(0, rand); 57 int random_number = distribution(generator); 58 59 //std::cout << "ミリ秒単位の乱数: " << random_number << std::endl; 60 61 return random_number; 62} 63 64/*############################################################## 65 66# 非同期 版 67 68# スプライトロード関数 69※ テスト用のためロード時間を乱数でミリ秒待機 70##############################################################*/ 71Sprite LoadSprite(const char* filePath) 72{ 73 std::unique_lock<std::mutex> lock(loadMutex); 74 75 // 他のスレッドが同じ画像をロード中であれば待機 76 loadCV.wait(lock, [&filePath]() 77 { 78 for(const std::string& path : nowLoad) 79 { 80 if (path == std::string(filePath)) 81 { 82 return false; 83 } 84 } 85 86 return true; 87 }); 88 89 //スプライトリストから取り出す 90 for (const Sprite& s : sprites) 91 { 92 if (s.path == std::string(filePath)) 93 { 94 std::cout << "found sprite" << std::endl; 95 return s; 96 } 97 } 98 99 std::cout << "new sprite" << std::endl; 100 101 // ロード中の画像リストに追加 102 nowLoad.push_back(std::string(filePath)); 103 lock.unlock(); // ロックを解除して他のスレッドがロードを開始できるようにする 104 105 //画像ロード 106// int milliseconds = 1000; 107 //int milliseconds = GetRandom(1000); 108// std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); 109 SDL_Texture *texture = IMG_LoadTexture(Engine::Context::GetRenderer(),"tile4.jpg"); 110 111 lock.lock(); // ロックを再取得して安全に状態を更新する 112 113 114 //ロードが終わったためリストから削除 115 int i = 0; 116 for(const std::string& s : nowLoad) 117 { 118 if(s == filePath) 119 { 120 break; 121 } 122 123 i++; 124 } 125 nowLoad.erase(nowLoad.begin() + i); 126 127 //ロード済みスプライトリストに追加 128 sprites.push_back(Sprite{texture, std::string(filePath) }); 129 //sprites.push_back(Sprite{ milliseconds, std::string(filePath) }); 130 131 // 画像のロードが完了したことを通知 132 loadCV.notify_all(); 133 134 return sprites.back(); 135} 136 137/*############################################################## 138 139# 同期 版 140 141# スプライトロード関数 142※ テスト用のためロード時間を乱数でミリ秒待機 143##############################################################*/ 144 145 146/*############################################################## 147# Component 基底 148##############################################################*/ 149class GameObject; 150class Component 151{ 152public: 153 154GameObject *gameObject; 155 Component(GameObject* g) 156 { 157 gameObject = g; 158 } 159 160 virtual std::vector<std::future<void>> PreLoad() 161 { 162 163 return std::move(futures); 164 } 165 166 167 virtual void Start() = 0; 168 169 virtual void Update() = 0; 170 171 virtual void Render() 172 { 173 174 } 175 176protected: 177 178 std::vector<std::future<void>> futures; 179}; 180/*############################################################## 181# GameObject 基底 182##############################################################*/ 183class GameObject 184{ 185public: 186 187 GameObject() 188 { 189 190 } 191 192 std::vector<std::future<void>> getPreLoad() 193 { 194 std::vector<std::future<void>> process; 195 196 for(Component *c : components) 197 { 198 for(std::future<void> &f : c->PreLoad()) 199 { 200 process.push_back(std::move(f)); 201 } 202 } 203 204 return std::move(process); 205 } 206 207 208 void Start() 209 { 210 for(Component* c : components) 211 { 212 c->Start(); 213 } 214 } 215 void Update() 216 { 217 for(Component* c : components) 218 { 219 c->Update(); 220 } 221 } 222 223 void Render() 224 { 225 for(Component* c : components) 226 { 227 c->Render(); 228 } 229 } 230 231 std::vector<Component*> components; 232}; 233 234/*############################################################## 235# Scene 基底 236##############################################################*/ 237class Scene 238{ 239public: 240 241 std::vector<GameObject*> gameObjects; 242 void PreaLoad() 243 { 244 std::vector<std::future<void>> futures; 245 for(GameObject *g : gameObjects) 246 { 247 for(std::future<void> &f : g->getPreLoad()) 248 { 249 futures.push_back(std::move(f)); 250 } 251 } 252 253 254 SetStartTime(); 255 for(std::future<void> &f : futures) 256 { 257 f.wait(); 258 } 259 260 int time = GetEndTime(); 261 std::cout<<time<<std::endl; 262 } 263 264 265 void Update() 266 { 267 for(GameObject *g : gameObjects) 268 { 269 g->Update(); 270 } 271 } 272 273 void Render() 274 { 275 for(GameObject *g : gameObjects) 276 { 277 g->Render(); 278 } 279 } 280 281 282}; 283 284/*############################################################## 285# SpriteRenderer コンポーネント 286##############################################################*/ 287class SpriteRenderer : public Component 288{ 289public: 290 291 Sprite sprite; 292 SpriteRenderer(GameObject* g): Component(g) 293 { 294 295 } 296 297 void Start() override 298 { 299 300 } 301 302 void Update() override 303 { 304 305 } 306 307 void Render() override 308 { 309 SDL_Texture* texture = IMG_LoadTexture(Engine::Context::GetRenderer(),"tile4.jpg"); 310 SDL_Rect rect = {0,0,64,64}; 311 SDL_Rect dest = {100,100,64,64}; 312 313 //std::cout<<"Render"<<std::endl; 314 //SDL_RenderCopy(Engine::Context::GetRenderer(),texture,&rect,&dest); 315 SDL_RenderCopy(Engine::Context::GetRenderer(),sprite.handle,&rect,&dest); 316 //SDL_RenderCopy(Engine::Context::GetRenderer(),sprite.handle,&rect,&dest); 317 318 std::cout<<SDL_GetError()<<std::endl; 319 } 320}; 321 322 323/*############################################################## 324# Control コンポーネント 325##############################################################*/ 326class SpriteRenderer; 327class Control : public Component 328{ 329public: 330 Control(GameObject *g): Component(g) 331 { 332 333 } 334 335 std::vector<std::future<void>> PreLoad() override 336 { 337 338 339 futures.push_back(std::async(std::launch::async,[this](){ ((SpriteRenderer*)(gameObject->components.at(0)))->sprite = LoadSprite("tile4.jpg"); })); 340 341 342 343 return std::move(futures); 344 } 345 346 void Start() 347 { 348 349 } 350 351 void Update() 352 { 353 354 } 355}; 356/*############################################################## 357# Player ゲームオブジェクト 358##############################################################*/ 359class Player : public GameObject 360{ 361public: 362 Player(): GameObject() 363 { 364 components.push_back(new SpriteRenderer(this)); 365 components.push_back(new Control(this)); 366 } 367 368 369 370 371}; 372 373 374 375 376/*############################################################## 377# Game シーン 378##############################################################*/ 379class Game : public Scene 380{ 381public: 382 Game(): Scene() 383 { 384 gameObjects.push_back(new Player()); 385 }; 386 387 388 void PreLoad() 389 { 390 for(std::future<void> &f : gameObjects.at(0)->getPreLoad()) 391 { 392 f.wait(); 393 } 394 } 395 396 void Start() 397 { 398 gameObjects.at(0)->Start(); 399 } 400 401 void Update() 402 { 403 404 gameObjects.at(0)->Update(); 405 } 406 407 void Render() 408 { 409 gameObjects.at(0)->Render(); 410 } 411}; 412 413 414 415 416int main() 417{ 418 Engine::Context::Init("Game",glm::ivec2(680,480)); 419 Game *g = new Game(); 420 421 g->PreLoad(); 422 423 g->Start(); 424 while(true) 425 { 426 Engine::Context::ClearBuffer(); 427 if(Engine::Context::GetKey(SDL_SCANCODE_ESCAPE) == true) 428 { 429 break; 430 } 431 432 433 g->Update(); 434 g->Render(); 435 436 Engine::Context::RenderBuffer(); 437 } 438 439 440 Engine::Context::Finalize(); 441 return 0; 442}
手元の環境で再現して調査しようとしていますが、苦戦しています。
もし、お手数でなければ教えてください。
(一般的なstd::asyncの話として考えてほしい、というなら結構です)
1. OSとC++コンパイラは何を使用していますか?
2. Context.hppは、https://www.sfml-dev.org/index.php のSFMLでしょうか?
3. glmは、https://github.com/icaven/glm でしょうか?
4. SDLは、https://github.com/libsdl-org/SDL でしょうか? また、#include <SDL.h>は不要ですか?
5. IMG_LoadTextureクラス、Engineクラスは、どのヘッダーに属するクラスでしょうか?
全く知らない物の話なので的外れかとも思いますが……
まず,やろうとしている処理というのがそもそもマルチスレッドで(というか「メインでないスレッドで」とでもいうか?)実施可能な処理なのか? というあたりは大丈夫なのでしょうか?
例えば……
確か,OpenGLのレンダリングコンテキストはスレッド固有みたいな扱いだったと記憶しています.
お使いのライブラリ(SDL?)に,それと似たような何らかの事柄が存在していたりはしないのだろうか? とか,ちょっと思いました.
(SDLというやつが裏で何を(OpenGL? DirectX? その他?)用いているのか等全く知りませんが,SDLがそういったところを仕様として面倒見てくれる(マルチスレッドOKと保証してくれる)物なのだろうか? …みたいな?)
回答1件
あなたの回答
tips
プレビュー