teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

2

文章を修正

2024/01/03 12:00

投稿

samidare_chan
samidare_chan

スコア18

title CHANGED
@@ -1,1 +1,1 @@
1
- 非同期で読み込んだ画像が描画されない原因が知りたい
1
+ std::future,std::asyncを使った非同期で読み込んだ画像が描画されない原因が知りたい
body CHANGED
File without changes

1

文章を修正

2024/01/03 11:57

投稿

samidare_chan
samidare_chan

スコア18

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