質問編集履歴

2

文章を修正

2024/01/03 12:00

投稿

samidare_chan
samidare_chan

スコア17

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

1

文章を修正

2024/01/03 11:57

投稿

samidare_chan
samidare_chan

スコア17

test CHANGED
File without changes
test CHANGED
@@ -1,45 +1,86 @@
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>
36
-
23
+ #include <chrono>
24
+ #include <random>
25
+ #include <thread>
26
+
27
+ struct Sprite
28
+ {
29
+ SDL_Texture *handle;
30
+ std::string path;
31
+ };
32
+
33
+
37
- std::vector<Engine::Sprite*> Engine::Resource::sprites;
34
+ std::vector<Sprite> sprites; //ロードした画像リスト
38
- std::vector<std::string> Engine::Resource::nowLoad;
35
+ std::vector<std::string> nowLoad; //現在ロード中の画像リスト
39
- std::mutex Engine::Resource::loadMutex;
36
+ std::mutex loadMutex;
40
- std::condition_variable Engine::Resource::loadCV;
37
+ std::condition_variable loadCV;
38
+
41
-
39
+ std::chrono::_V2::system_clock::time_point startTime;
40
+
41
+ void SetStartTime()
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
+ ##############################################################*/
42
- Engine::Sprite* Engine::Resource::LoadSprite(const char* filePath)
83
+ Sprite LoadSprite(const char* filePath)
43
84
  {
44
85
  std::unique_lock<std::mutex> lock(loadMutex);
45
86
 
@@ -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,127 +134,322 @@
92
134
 
93
135
  i++;
94
136
  }
95
-
96
137
  nowLoad.erase(nowLoad.begin() + i);
97
138
 
98
-
99
-
100
- int width,height;
139
+ //ロード済みスプライトリストに追加
101
- SDL_QueryTexture(texture,NULL,NULL,&width,&height);
102
-
103
-
104
-
105
- sprites.push_back(new Sprite(std::string(filePath),texture,glm::ivec2(width,height)));
140
+ sprites.push_back(Sprite{texture, std::string(filePath) });
141
+ //sprites.push_back(Sprite{ milliseconds, std::string(filePath) });
106
142
 
107
143
  // 画像のロードが完了したことを通知
108
144
  loadCV.notify_all();
109
145
 
110
- return sprites.back();
146
+ return sprites.back();
111
-
147
+ }
148
+
149
+ /*##############################################################
150
+
151
+ # 同期 版
152
+
153
+ # スプライトロード関数 
154
+ ※ テスト用のためロード時間を乱数でミリ秒待機
155
+ ##############################################################*/
156
+
157
+
158
+ /*##############################################################
159
+ # Component 基底
160
+ ##############################################################*/
161
+ class GameObject;
162
+ class Component
163
+ {
164
+ public:
112
165
 
166
+ GameObject *gameObject;
167
+ Component(GameObject* g)
168
+ {
169
+ gameObject = g;
170
+ }
171
+
172
+ virtual std::vector<std::future<void>> PreLoad()
173
+ {
174
+
175
+ return std::move(futures);
176
+ }
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
+
190
+ std::vector<std::future<void>> futures;
191
+ };
192
+ /*##############################################################
193
+ # GameObject 基底
194
+ ##############################################################*/
195
+ class GameObject
196
+ {
197
+ public:
198
+
199
+ GameObject()
200
+ {
201
+
202
+ }
203
+
204
+ std::vector<std::future<void>> getPreLoad()
205
+ {
206
+ std::vector<std::future<void>> process;
207
+
208
+ for(Component *c : components)
209
+ {
210
+ for(std::future<void> &f : c->PreLoad())
211
+ {
212
+ process.push_back(std::move(f));
213
+ }
214
+ }
215
+
216
+ return std::move(process);
217
+ }
218
+
219
+
220
+ void Start()
221
+ {
222
+ for(Component* c : components)
223
+ {
224
+ c->Start();
225
+ }
226
+ }
227
+ void Update()
228
+ {
229
+ for(Component* c : components)
230
+ {
231
+ c->Update();
232
+ }
233
+ }
234
+
235
+ void Render()
236
+ {
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
250
+ {
251
+ public:
252
+
253
+ std::vector<GameObject*> gameObjects;
254
+ void PreaLoad()
255
+ {
256
+ std::vector<std::future<void>> futures;
257
+ for(GameObject *g : gameObjects)
258
+ {
259
+ for(std::future<void> &f : g->getPreLoad())
260
+ {
261
+ futures.push_back(std::move(f));
262
+ }
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;
274
+ }
275
+
276
+
277
+ void Update()
278
+ {
279
+ for(GameObject *g : gameObjects)
280
+ {
281
+ g->Update();
282
+ }
283
+ }
284
+
285
+ void Render()
286
+ {
287
+ for(GameObject *g : gameObjects)
288
+ {
289
+ g->Render();
290
+ }
291
+ }
292
+
293
+
294
+ };
295
+
296
+ /*##############################################################
297
+ # SpriteRenderer コンポーネント
298
+ ##############################################################*/
299
+ class SpriteRenderer : public Component
300
+ {
301
+ public:
302
+
303
+ Sprite sprite;
304
+ SpriteRenderer(GameObject* g): Component(g)
305
+ {
306
+
307
+ }
308
+
309
+ void Start() override
310
+ {
311
+
312
+ }
313
+
314
+ void Update() override
315
+ {
316
+
317
+ }
318
+
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};
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);
329
+
330
+ std::cout<<SDL_GetError()<<std::endl;
331
+ }
332
+ };
333
+
334
+
335
+ /*##############################################################
336
+ # Control コンポーネント
337
+ ##############################################################*/
338
+ class SpriteRenderer;
339
+ class Control : public Component
340
+ {
341
+ public:
342
+ Control(GameObject *g): Component(g)
343
+ {
344
+
345
+ }
346
+
347
+ std::vector<std::future<void>> PreLoad() override
348
+ {
349
+
350
+
351
+ futures.push_back(std::async(std::launch::async,[this](){ ((SpriteRenderer*)(gameObject->components.at(0)))->sprite = LoadSprite("tile4.jpg"); }));
352
+
353
+
354
+
355
+ return std::move(futures);
356
+ }
357
+
358
+ void Start()
359
+ {
360
+
361
+ }
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
+ {
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;
113
454
  }
114
455
  ```
115
- ##### 利用
116
- ```cpp
117
- #include "PlayerControl.hpp"
118
- #include <SpriteRenderer.hpp>
119
- #include <Resource.hpp>
120
-
121
- PlayerControl::PlayerControl(Engine::GameObject* g) : Engine::Component(g)
122
- {
123
-
124
- }
125
-
126
- std::vector<std::future<void>> PlayerControl::PreLoad()
127
- {
128
- futures.push_back(std::async(std::launch::async,[this]()
129
- {
130
- Engine::SpriteRenderer *sp = (Engine::SpriteRenderer*)gameObject->GetComponent<Engine::SpriteRenderer>();
131
- sp->sprite = Engine::Resource::LoadSprite("./tile4.png");
132
-
133
- std::cout<<sp->sprite->texture<<std::endl;
134
- }));
135
-
136
-
137
- return std::move(futures);
138
- }
139
-
140
- void PlayerControl::Start()
141
- {
142
-
143
- }
144
-
145
- void PlayerControl::Update()
146
- {
147
-
148
- }
149
- ```
150
- ##### 待機側 
151
- ```cpp
152
-
153
- void Engine::Scene::PreLoad()
154
- {
155
- std::vector<std::future<void>> futures;
156
- for(GameObject *g : gameObjects)
157
- {
158
- for(std::future<void> &f : g->getPreLoad())
159
- {
160
- futures.push_back(std::move(f));
161
- }
162
- }
163
-
164
- for(std::future<void> &f : futures)
165
- {
166
- f.wait();
167
- }
168
- }
169
-
170
-
171
- void Engine::Scene::Loop()
172
- {
173
- PreLoad();
174
-
175
- Awake();
176
- Start();
177
-
178
- while(true)
179
- {
180
- Context::ClearBuffer();
181
-
182
- if(Context::GetKey(SDL_SCANCODE_ESCAPE) == true)
183
- {
184
- break;
185
- }
186
-
187
- Update();
188
-
189
-
190
- Render();
191
-
192
-
193
- Context::RenderBuffer();
194
- }
195
- }
196
- ```
197
- ##### 実行描画
198
- ```cpp
199
-
200
- void Engine::SpriteRenderer::Render()
201
- {
202
-
203
- const SDL_Texture* texture = IMG_LoadTexture(Context::GetRenderer(),"./tile4.png");
204
-
205
- std::cout<<" "<<sprite->texture<<std::endl;
206
-
207
-
208
-
209
- int err = SDL_RenderCopy(Context::GetRenderer(),(SDL_Texture*)texture,&rect,&dest);
210
- //int err = SDL_RenderCopy(Context::GetRenderer(),(SDL_Texture*)sprite->texture,&rect,&dest);
211
-
212
-
213
- std::cout<<SDL_GetError()<<err<<std::endl;
214
-
215
- // int err = SDL_RenderCopyEx(Context::GetRenderer(),(SDL_Texture*)sprite->texture,NULL,&rect, 0.0,NULL,SDL_FLIP_VERTICAL);
216
- }
217
- ```
218
-