Merge lp:~widelands-dev/widelands/memory_leak into lp:widelands

Proposed by SirVer
Status: Merged
Merged at revision: 7735
Proposed branch: lp:~widelands-dev/widelands/memory_leak
Merge into: lp:widelands
Diff against target: 539 lines (+140/-142)
6 files modified
src/graphic/rendertarget.cc (+92/-82)
src/graphic/rendertarget.h (+8/-6)
src/graphic/text/font_io.cc (+1/-1)
src/logic/map_objects/world/world.cc (+2/-2)
src/ui_basic/table.cc (+5/-19)
src/ui_fsmenu/loadgame.cc (+32/-32)
To merge this branch: bzr merge lp:~widelands-dev/widelands/memory_leak
Reviewer Review Type Date Requested Status
GunChleoc Approve
Tino Approve
Review via email: mp+283690@code.launchpad.net

Commit message

- Fix big memory leak and extra work in UI::Table::draw.
- Fix a couple of minor memory leaks around the code I found using the Leaks tool in Apple's Instruments.
- Correctly crop destination and source rectangle while blitting.

Major leak explanation:
On each frame we created a downscaled texture if the image of a table entry was too small and leaked this texture immediately. This extra scaling work we did there was even unnecessary since OpenGL can scale down images while blitting for free.

Deleted that rescaling code, which makes the texture creation unnecessary, gets rid of the memory leak and also buys CPU cycles since a lot of work is now never done.

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Hi, I am bunnybot (https://github.com/widelands/bunnybot).

I am keeping the source branch lp:~widelands-dev/widelands/memory_leak mirrored to https://github.com/widelands/widelands/tree/_widelands_dev_widelands_memory_leak

You can give me commands by starting a line with @bunnybot <command>. I understand:
 merge: Merges the source branch into the target branch, closing the merge proposal. I will use the proposed commit message if it is set.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Have you tested that this doesn't regress https://bugs.launchpad.net/widelands/+bug/1522564?

This bug was the reason I stopped using blitrect_scale.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 343 has changed state to: errored. Details: https://travis-ci.org/widelands/widelands/builds/104189929.

Revision history for this message
SirVer (sirver) wrote :

> Have you tested that this doesn't regress https://bugs.launchpad.net/widelands/+bug/1522564?

No, I did not. It very likely regresses that as blitrect_scale does not change the source rect when cropping. I'll look into that, but I'd like to get https://code.launchpad.net/~widelands-dev/widelands/fix_editor_transparency_issue/+merge/282874 in before that, since it touches on the same code and I do not want to deal with the conflicts.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 343 has changed state to: passed. Details: https://travis-ci.org/widelands/widelands/builds/104189929.

Revision history for this message
kaputtnik (franku) wrote :

> Have you tested that this doesn't regress https://bugs.launchpad.net/widelands/+bug/1522564?

This branch regresses that bug. It looks likes the images are in an additional row. I attached a screenshot to the bug, look : https://bugs.launchpad.net/widelands/+bug/1522564/+attachment/4555267/+files/overlap.png

I am in hurry, want to test further this afternoon.

Revision history for this message
GunChleoc (gunchleoc) wrote :

The problem is that blitrect_scale doesn't crop.

Revision history for this message
kaputtnik (franku) wrote :

I get increasing memory for about 30-100k per second. Opening the message window does not increase the memory usage anymore.

All looks good, except the overlapping images in the message menu.

Do not approve, because bug 1522564 is linked here.

Revision history for this message
SirVer (sirver) wrote :

> I get increasing memory for about 30-100k per second.

Does this ever stop or grow boundless?

I just pushed a commit that should fix bug 1522564 too. This is ready for code review and another round of testing.

Revision history for this message
kaputtnik (franku) wrote :

It increases boundless. I believe this caused by the wares which are produced... but i am not sure.

Today i have no time anymore for testing.

Revision history for this message
Tino (tino79) wrote :

I do not experience any more memory leaking on windows.
And no overlapping icons in the message menu.

review: Approve
Revision history for this message
bunnybot (widelandsofficial) wrote :

Travis build 354 has changed state to: failed. Details: https://travis-ci.org/widelands/widelands/builds/104294390.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Graphics now look OK on Ubuntu. Code LGTM.

Travis fail is because of Codecheck - I fixed all but 1 Codecheck warning in https://code.launchpad.net/~widelands-dev/widelands/codecheck_compiler_fixes/+merge/283722.

review: Approve
Revision history for this message
kaputtnik (franku) wrote :

To fiddle out why the memory increases will take some time. So we could merge this and i open a new bug if i found the something.

Revision history for this message
SirVer (sirver) wrote :

Widelands is currently not leaking memory during normal gameplay. I checked that yesterday. So the increases you see are probably just due to map objects being created.

I'd still like a code review if possible.

> Am 24.01.2016 um 11:27 schrieb kaputtnik <email address hidden>:
>
> To fiddle out why the memory increases will take some time. So we could merge this and i open a new bug if i found the something.
>
>
> --
> https://code.launchpad.net/~widelands-dev/widelands/memory_leak/+merge/283690
> You proposed lp:~widelands-dev/widelands/memory_leak for merging.

Revision history for this message
SirVer (sirver) wrote :

Oh, gun already reviewed the code. did not see that.

@bunnybot merge

Revision history for this message
kaputtnik (franku) wrote :

> So the increases you see are probably just due to map objects being created.

Yes that is probably be the reason.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/graphic/rendertarget.cc'
2--- src/graphic/rendertarget.cc 2016-01-17 19:54:32 +0000
3+++ src/graphic/rendertarget.cc 2016-01-24 08:40:10 +0000
4@@ -154,17 +154,13 @@
5 void RenderTarget::blit(const Point& dst, const Image* image, BlendMode blend_mode, UI::Align align)
6 {
7 Point destination_point(dst);
8-
9 UI::correct_for_align(align, image->width(), image->height(), &destination_point);
10
11- Rect srcrc(Point(0, 0), image->width(), image->height());
12+ Rect source_rect(Point(0, 0), image->width(), image->height());
13+ Rect destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
14
15- if (to_surface_geometry(&destination_point, &srcrc)) {
16- m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
17- *image,
18- srcrc,
19- 1.,
20- blend_mode);
21+ if (to_surface_geometry(&destination_rect, &source_rect)) {
22+ m_surface->blit(destination_rect, *image, source_rect, 1., blend_mode);
23 }
24 }
25
26@@ -172,14 +168,13 @@
27 const Image* image,
28 const RGBAColor& blend_mode, UI::Align align) {
29 Point destination_point(dst);
30-
31 UI::correct_for_align(align, image->width(), image->height(), &destination_point);
32
33- Rect srcrc(Point(0, 0), image->width(), image->height());
34+ Rect source_rect(Point(0, 0), image->width(), image->height());
35+ Rect destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
36
37- if (to_surface_geometry(&destination_point, &srcrc)) {
38- m_surface->blit_monochrome(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
39- *image, srcrc, blend_mode);
40+ if (to_surface_geometry(&destination_rect, &source_rect)) {
41+ m_surface->blit_monochrome(destination_rect, *image, source_rect, blend_mode);
42 }
43 }
44
45@@ -194,49 +189,33 @@
46
47 // We want to use the given srcrc, but we must make sure that we are not
48 // blitting outside of the boundaries of 'image'.
49- Rect srcrc(gsrcrc.x,
50+ Rect source_rect(gsrcrc.x,
51 gsrcrc.y,
52 std::min<int32_t>(image->width() - gsrcrc.x, gsrcrc.w),
53 std::min<int32_t>(image->height() - gsrcrc.y, gsrcrc.h));
54+ Rect destination_rect(dst.x, dst.y, source_rect.w, source_rect.h);
55
56- Point destination_point(dst);
57- if (to_surface_geometry(&destination_point, &srcrc))
58- m_surface->blit(Rect(destination_point.x, destination_point.y, srcrc.w, srcrc.h),
59- *image,
60- srcrc,
61- 1.,
62- blend_mode);
63+ if (to_surface_geometry(&destination_rect, &source_rect)) {
64+ m_surface->blit(destination_rect, *image, source_rect, 1., blend_mode);
65+ }
66 }
67
68-void RenderTarget::blitrect_scale(const Rect& dst,
69+void RenderTarget::blitrect_scale(Rect destination_rect,
70 const Image* image,
71- const Rect& source_rect,
72- const float opacity,
73+ Rect source_rect,
74+ const float opacity,
75 const BlendMode blend_mode) {
76-
77- Point destination_point(dst.x, dst.y);
78- Rect srcrect(source_rect);
79- if (to_surface_geometry(&destination_point, &srcrect)) {
80- m_surface->blit(Rect(destination_point.x, destination_point.y, dst.w, dst.h),
81- *image,
82- source_rect,
83- opacity,
84- blend_mode);
85+ if (to_surface_geometry(&destination_rect, &source_rect)) {
86+ m_surface->blit(destination_rect, *image, source_rect, opacity, blend_mode);
87 }
88 }
89
90-void RenderTarget::blitrect_scale_monochrome(const Rect& destination_rect,
91+void RenderTarget::blitrect_scale_monochrome(Rect destination_rect,
92 const Image* image,
93- const Rect& source_rect,
94+ Rect source_rect,
95 const RGBAColor& blend) {
96- Point destination_point(destination_rect.x, destination_rect.y);
97- Rect srcrect(source_rect);
98- if (to_surface_geometry(&destination_point, &srcrect)) {
99- m_surface->blit_monochrome(
100- Rect(destination_point.x, destination_point.y, destination_rect.w, destination_rect.h),
101- *image,
102- source_rect,
103- blend);
104+ if (to_surface_geometry(&destination_rect, &source_rect)) {
105+ m_surface->blit_monochrome(destination_rect, *image, source_rect, blend);
106 }
107 }
108
109@@ -347,12 +326,13 @@
110 uint32_t time,
111 const RGBColor* player_color,
112 const Rect& source_rect) {
113- Point destination_point = dst - animation.hotspot();
114- destination_point += source_rect.origin();
115+ Rect destination_rect(dst.x - animation.hotspot().x + source_rect.x,
116+ dst.y - animation.hotspot().y + source_rect.y, source_rect.w,
117+ source_rect.h);
118
119 Rect srcrc(source_rect);
120- if (to_surface_geometry(&destination_point, &srcrc))
121- animation.blit(time, destination_point, srcrc, player_color, m_surface);
122+ if (to_surface_geometry(&destination_rect, &srcrc))
123+ animation.blit(time, destination_rect.origin(), srcrc, player_color, m_surface);
124
125 // Look if there is a sound effect registered for this frame and trigger the
126 // effect (see SoundHandler::stereo_position).
127@@ -423,41 +403,71 @@
128 * Clip against window and source bitmap, returns false if blitting is
129 * unnecessary because image is not inside the target surface.
130 */
131-bool RenderTarget::to_surface_geometry(Point* dst, Rect* srcrc) const
132+bool RenderTarget::to_surface_geometry(Rect* destination_rect, Rect* source_rect) const
133 {
134- assert(0 <= srcrc->x);
135- assert(0 <= srcrc->y);
136- *dst += m_offset;
137-
138- // Clipping
139- if (dst->x < 0) {
140- if (srcrc->w <= -dst->x)
141- return false;
142- srcrc->x -= dst->x;
143- srcrc->w += dst->x;
144- dst->x = 0;
145- }
146-
147- if (dst->x + srcrc->w > m_rect.w) {
148- if (m_rect.w <= dst->x)
149- return false;
150- srcrc->w = m_rect.w - dst->x;
151- }
152-
153- if (dst->y < 0) {
154- if (srcrc->h <= -dst->y)
155- return false;
156- srcrc->y -= dst->y;
157- srcrc->h += dst->y;
158- dst->y = 0;
159- }
160-
161- if (dst->y + srcrc->h > m_rect.h) {
162- if (m_rect.h <= dst->y)
163- return false;
164- srcrc->h = m_rect.h - dst->y;
165- }
166-
167- *dst += m_rect.origin();
168+ assert(0 <= source_rect->x);
169+ assert(0 <= source_rect->y);
170+ destination_rect->x += m_offset.x;
171+ destination_rect->y += m_offset.y;
172+
173+ // We have to clip the target rect against our own drawing area. If we make
174+ // changes to any side of our rectangle, we have to change the source rect
175+ // too. But since the source_rectangle might have a different size than the
176+ // destination_rect, we do this by making the proportional change.
177+
178+ // Clipping, from the left.
179+ if (destination_rect->x < 0) {
180+ if (destination_rect->w <= -destination_rect->x) {
181+ return false;
182+ }
183+ // Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
184+ const int source_rect_pixel_change =
185+ 0.5 + -static_cast<double>(destination_rect->x) / destination_rect->w * source_rect->w;
186+ source_rect->x += source_rect_pixel_change;
187+ source_rect->w -= source_rect_pixel_change;
188+ destination_rect->w += destination_rect->x;
189+ destination_rect->x = 0;
190+ }
191+
192+ // Clipping, from the right.
193+ if (destination_rect->x + destination_rect->w > m_rect.w) {
194+ if (m_rect.w <= destination_rect->x) {
195+ return false;
196+ }
197+ const int new_destination_w = m_rect.w - destination_rect->x;
198+ // Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
199+ source_rect->w =
200+ 0.5 + static_cast<double>(new_destination_w) / destination_rect->w * source_rect->w;
201+ destination_rect->w = new_destination_w;
202+ }
203+
204+ // Clipping, from the top.
205+ if (destination_rect->y < 0) {
206+ if (destination_rect->h <= -destination_rect->y) {
207+ return false;
208+ }
209+ // Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
210+ const int source_rect_pixel_change = 0.5 +
211+ -static_cast<double>(destination_rect->y) / destination_rect->h * source_rect->h;
212+ source_rect->y += source_rect_pixel_change;
213+ source_rect->h -= source_rect_pixel_change;
214+ destination_rect->h += destination_rect->y;
215+ destination_rect->y = 0;
216+ }
217+
218+ // Clipping, from the bottom.
219+ if (destination_rect->y + destination_rect->h > m_rect.h) {
220+ if (m_rect.h <= destination_rect->y) {
221+ return false;
222+ }
223+ const int new_destination_h = m_rect.h - destination_rect->y;
224+ // Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
225+ source_rect->h =
226+ 0.5 + static_cast<double>(new_destination_h) / destination_rect->h * source_rect->h;
227+ destination_rect->h = new_destination_h;
228+ }
229+
230+ destination_rect->x += m_rect.x;
231+ destination_rect->y += m_rect.y;
232 return true;
233 }
234
235=== modified file 'src/graphic/rendertarget.h'
236--- src/graphic/rendertarget.h 2016-01-23 10:08:40 +0000
237+++ src/graphic/rendertarget.h 2016-01-24 08:40:10 +0000
238@@ -83,16 +83,18 @@
239 // multiplied with 'opacity' before blitting. The 'blend_mode'
240 // defines if values are blended with whats already there or just
241 // copied over.
242- void blitrect_scale(const Rect& destination_rect,
243+ // Rect's are taken by value on purpose.
244+ void blitrect_scale(Rect destination_rect,
245 const Image* image,
246- const Rect& source_rect,
247+ Rect source_rect,
248 float opacity,
249 BlendMode blend_mode);
250
251- // Like blitrect_scale. See MonochromeBlitProgram for details.
252- void blitrect_scale_monochrome(const Rect& destination_rect,
253+ // Like blitrect_scale. See MonochromeBlitProgram for details. Rect's are
254+ // taken by value on purpose.
255+ void blitrect_scale_monochrome(Rect destination_rect,
256 const Image* image,
257- const Rect& source_rect,
258+ Rect source_rect,
259 const RGBAColor& blend);
260
261 void tile(const Rect&,
262@@ -118,7 +120,7 @@
263
264 protected:
265 bool clip(Rect & r) const;
266- bool to_surface_geometry(Point* dst, Rect* srcrc) const;
267+ bool to_surface_geometry(Rect* destination_rect, Rect* source_rect) const;
268
269 // Does the actual blitting.
270 void do_blit_animation(const Point& dst,
271
272=== modified file 'src/graphic/text/font_io.cc'
273--- src/graphic/text/font_io.cc 2014-11-18 17:45:58 +0000
274+++ src/graphic/text/font_io.cc 2016-01-24 08:40:10 +0000
275@@ -40,7 +40,7 @@
276 // this class is destroyed.
277 std::unique_ptr<std::string> memory;
278 {
279- FileRead* fr = new FileRead();
280+ std::unique_ptr<FileRead> fr(new FileRead());
281 fr->open(*g_fs, filename);
282 memory.reset(new std::string(fr->data(0), fr->get_size()));
283 }
284
285=== modified file 'src/logic/map_objects/world/world.cc'
286--- src/logic/map_objects/world/world.cc 2016-01-13 07:27:55 +0000
287+++ src/logic/map_objects/world/world.cc 2016-01-24 08:40:10 +0000
288@@ -50,15 +50,15 @@
289 for (size_t i = 0; i < terrains_->size(); ++i) {
290 TerrainDescription* terrain = terrains_->get_mutable(i);
291 for (size_t j = 0; j < terrain->texture_paths().size(); ++j) {
292- SDL_Surface* sdl_surface = load_image_as_sdl_surface(terrain->texture_paths()[j]);
293-
294 // Set the minimap color on the first loaded image.
295 if (j == 0) {
296+ SDL_Surface* sdl_surface = load_image_as_sdl_surface(terrain->texture_paths()[j]);
297 uint8_t top_left_pixel = static_cast<uint8_t*>(sdl_surface->pixels)[0];
298 const SDL_Color top_left_pixel_color =
299 sdl_surface->format->palette->colors[top_left_pixel];
300 terrain->set_minimap_color(
301 RGBColor(top_left_pixel_color.r, top_left_pixel_color.g, top_left_pixel_color.b));
302+ SDL_FreeSurface(sdl_surface);
303 }
304 terrain->add_texture(g_gr->images().get(terrain->texture_paths()[j]));
305 }
306
307=== modified file 'src/ui_basic/table.cc'
308--- src/ui_basic/table.cc 2016-01-11 15:18:51 +0000
309+++ src/ui_basic/table.cc 2016-01-24 08:40:10 +0000
310@@ -283,7 +283,7 @@
311 Columns::size_type const nr_columns = m_columns.size();
312 for (uint32_t i = 0, curx = 0; i < nr_columns; ++i) {
313 const Column& column = m_columns[i];
314- int const curw = column.width;
315+ int const curw = column.width;
316 Align alignment = mirror_alignment(column.alignment);
317
318 const Image* entry_picture = er.get_picture(i);
319@@ -291,11 +291,10 @@
320
321 Point point(curx, y);
322 int picw = 0;
323- int pich = 0;
324
325- if (entry_picture) {
326+ if (entry_picture != nullptr) {
327 picw = entry_picture->width();
328- pich = entry_picture->height();
329+ const int pich = entry_picture->height();
330
331 int draw_x = point.x;
332
333@@ -319,22 +318,9 @@
334 draw_x += curw - blit_width;
335 }
336
337- // Temporary texture for the scaled image
338- Texture* scaled_texture = new Texture(blit_width, max_pic_height);
339-
340- // Initialize the rectangle
341- scaled_texture->fill_rect(Rect(0, 0, blit_width, max_pic_height),
342- RGBAColor(255, 255, 255, 0));
343-
344 // Create the scaled image
345- scaled_texture->blit(Rect(0, 0, blit_width, max_pic_height),
346- *entry_picture,
347- Rect(0, 0, picw, pich),
348- 1.,
349- BlendMode::UseAlpha);
350-
351- // This will now blit with any appropriate cropping
352- dst.blit(Point(draw_x, point.y + 1), scaled_texture);
353+ dst.blitrect_scale(Rect(draw_x, point.y + 1, blit_width, max_pic_height),
354+ entry_picture, Rect(0, 0, picw, pich), 1., BlendMode::UseAlpha);
355
356 // For text alignment below
357 picw = blit_width;
358
359=== modified file 'src/ui_fsmenu/loadgame.cc'
360--- src/ui_fsmenu/loadgame.cc 2016-01-17 08:29:59 +0000
361+++ src/ui_fsmenu/loadgame.cc 2016-01-24 08:40:10 +0000
362@@ -435,16 +435,16 @@
363 m_games_data.clear();
364 m_table.clear();
365
366- SavegameData* gamedata = new SavegameData();
367
368 if (m_settings && !m_settings->settings().saved_games.empty()) {
369+ SavegameData gamedata;
370 for (uint32_t i = 0; i < m_settings->settings().saved_games.size(); ++i) {
371- gamedata->filename = m_settings->settings().saved_games.at(i).path;
372- m_games_data.push_back(*gamedata);
373+ gamedata.filename = m_settings->settings().saved_games.at(i).path;
374+ m_games_data.push_back(gamedata);
375
376 UI::Table<uintptr_t const>::EntryRecord & te =
377 m_table.add(m_games_data.size() - 1);
378- te.set_string(0, FileSystem::filename_without_ext(gamedata->filename.c_str()).c_str());
379+ te.set_string(0, FileSystem::filename_without_ext(gamedata.filename.c_str()).c_str());
380 }
381 } else { // Normal case
382 // Fill it with all files we find.
383@@ -465,7 +465,7 @@
384 continue;
385 }
386
387- gamedata = new SavegameData();
388+ SavegameData gamedata;
389
390 std::string savename = gamefilename;
391 if (m_is_replay) savename += WLGF_SUFFIX;
392@@ -474,30 +474,30 @@
393 continue;
394 }
395
396- gamedata->filename = gamefilename;
397+ gamedata.filename = gamefilename;
398
399 try {
400 Widelands::GameLoader gl(savename.c_str(), m_game);
401 gl.preload_game(gpdp);
402
403- gamedata->gametype = gpdp.get_gametype();
404+ gamedata.gametype = gpdp.get_gametype();
405
406 if (!m_is_replay) {
407 if (m_settings->settings().multiplayer) {
408- if (gamedata->gametype == GameController::GameType::SINGLEPLAYER) {
409+ if (gamedata.gametype == GameController::GameType::SINGLEPLAYER) {
410 continue;
411 }
412- } else if (gamedata->gametype > GameController::GameType::SINGLEPLAYER) {
413+ } else if (gamedata.gametype > GameController::GameType::SINGLEPLAYER) {
414 continue;
415 }
416 }
417
418- gamedata->mapname = gpdp.get_mapname();
419- gamedata->gametime = gpdp.get_gametime();
420- gamedata->nrplayers = gpdp.get_number_of_players();
421- gamedata->version = gpdp.get_version();
422+ gamedata.mapname = gpdp.get_mapname();
423+ gamedata.gametime = gpdp.get_gametime();
424+ gamedata.nrplayers = gpdp.get_number_of_players();
425+ gamedata.version = gpdp.get_version();
426
427- gamedata->savetimestamp = gpdp.get_savetimestamp();
428+ gamedata.savetimestamp = gpdp.get_savetimestamp();
429 time_t t;
430 time(&t);
431 struct tm * currenttime = localtime(&t);
432@@ -506,9 +506,9 @@
433 int8_t current_month = currenttime->tm_mon;
434 int8_t current_day = currenttime->tm_mday;
435
436- struct tm * savedate = localtime(&gamedata->savetimestamp);
437+ struct tm * savedate = localtime(&gamedata.savetimestamp);
438
439- if (gamedata->savetimestamp > 0) {
440+ if (gamedata.savetimestamp > 0) {
441 if (savedate->tm_year == current_year &&
442 savedate->tm_mon == current_month &&
443 savedate->tm_mday == current_day) { // Today
444@@ -518,7 +518,7 @@
445
446 /** TRANSLATORS: Display date for choosing a savegame/replay */
447 /** TRANSLATORS: hour:minute */
448- gamedata->savedatestring = (boost::format(_("Today, %1%:%2%"))
449+ gamedata.savedatestring = (boost::format(_("Today, %1%:%2%"))
450 % savedate->tm_hour % minute).str();
451 } else if ((savedate->tm_year == current_year &&
452 savedate->tm_mon == current_month &&
453@@ -531,13 +531,13 @@
454
455 /** TRANSLATORS: Display date for choosing a savegame/replay */
456 /** TRANSLATORS: hour:minute */
457- gamedata->savedatestring = (boost::format(_("Yesterday, %1%:%2%"))
458+ gamedata.savedatestring = (boost::format(_("Yesterday, %1%:%2%"))
459 % savedate->tm_hour % minute).str();
460 } else { // Older
461
462 /** TRANSLATORS: Display date for choosing a savegame/replay */
463 /** TRANSLATORS: month day, year */
464- gamedata->savedatestring = (boost::format(_("%2% %1%, %3%"))
465+ gamedata.savedatestring = (boost::format(_("%2% %1%, %3%"))
466 % savedate->tm_mday
467 % localize_month(savedate->tm_mon)
468 % (1900 + savedate->tm_year)).str();
469@@ -546,18 +546,18 @@
470
471 {
472 i18n::Textdomain td("win_conditions");
473- gamedata->wincondition = _(gpdp.get_win_condition());
474+ gamedata.wincondition = _(gpdp.get_win_condition());
475 }
476- gamedata->minimap_path = gpdp.get_minimap_path();
477- m_games_data.push_back(*gamedata);
478+ gamedata.minimap_path = gpdp.get_minimap_path();
479+ m_games_data.push_back(gamedata);
480
481 UI::Table<uintptr_t const>::EntryRecord & te =
482 m_table.add(m_games_data.size() - 1);
483- te.set_string(0, gamedata->savedatestring);
484+ te.set_string(0, gamedata.savedatestring);
485
486 if (m_is_replay || m_settings->settings().multiplayer) {
487 std::string gametypestring;
488- switch (gamedata->gametype) {
489+ switch (gamedata.gametype) {
490 case GameController::GameType::SINGLEPLAYER:
491 /** TRANSLATORS: "Single Player" entry in the Game Mode table column. */
492 /** TRANSLATORS: "Keep this to 6 letters maximum. */
493@@ -572,7 +572,7 @@
494 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */
495 /** TRANSLATORS: %1% is the number of players */
496 gametypestring = (boost::format(_("H (%1%)"))
497- % static_cast<unsigned int>(gamedata->nrplayers)).str();
498+ % static_cast<unsigned int>(gamedata.nrplayers)).str();
499 break;
500 case GameController::GameType::NETCLIENT:
501 /** TRANSLATORS: "Multiplayer" entry in the Game Mode table column. */
502@@ -581,20 +581,20 @@
503 /** TRANSLATORS: Make sure that this translation is consistent with the tooltip. */
504 /** TRANSLATORS: %1% is the number of players */
505 gametypestring = (boost::format(_("MP (%1%)"))
506- % static_cast<unsigned int>(gamedata->nrplayers)).str();
507+ % static_cast<unsigned int>(gamedata.nrplayers)).str();
508 break;
509 case GameController::GameType::REPLAY:
510 gametypestring = "";
511 break;
512 }
513 te.set_string(1, gametypestring);
514- te.set_string(2, map_filename(gamedata->filename, gamedata->mapname));
515+ te.set_string(2, map_filename(gamedata.filename, gamedata.mapname));
516 } else {
517- te.set_string(1, map_filename(gamedata->filename, gamedata->mapname));
518+ te.set_string(1, map_filename(gamedata.filename, gamedata.mapname));
519 }
520 } catch (const WException & e) {
521 // we simply skip illegal entries
522- gamedata->errormessage =
523+ gamedata.errormessage =
524 ((boost::format("%s\n\n%s\n\n%s"))
525 /** TRANSLATORS: Error message introduction for when an old savegame can't be loaded */
526 % _("This file has the wrong format and can’t be loaded."
527@@ -603,9 +603,9 @@
528 % _("Error message:")
529 % e.what()).str();
530
531- const std::string fs_filename = FileSystem::filename_without_ext(gamedata->filename.c_str());
532- gamedata->mapname = fs_filename;
533- m_games_data.push_back(*gamedata);
534+ const std::string fs_filename = FileSystem::filename_without_ext(gamedata.filename.c_str());
535+ gamedata.mapname = fs_filename;
536+ m_games_data.push_back(gamedata);
537
538 UI::Table<uintptr_t const>::EntryRecord & te =
539 m_table.add(m_games_data.size() - 1);

Subscribers

People subscribed via source and target branches

to status/vote changes: