1
1
// SuperTux
2
2
// Copyright (C) 2006 Matthias Braun <[email protected] >
3
+ // 2023-2024 Vankata453
3
4
//
4
5
// This program is free software: you can redistribute it and/or modify
5
6
// it under the terms of the GNU General Public License as published by
29
30
#include " util/reader_document.hpp"
30
31
#include " util/reader_mapping.hpp"
31
32
#include " util/reader_object.hpp"
33
+ #include " util/string_util.hpp"
32
34
#include " video/surface.hpp"
33
35
#include " video/texture_manager.hpp"
34
36
@@ -48,70 +50,141 @@ SpriteData::Action::Action() :
48
50
{
49
51
}
50
52
51
- SpriteData::SpriteData (const ReaderMapping& mapping) :
52
- actions(),
53
- name()
53
+ void
54
+ SpriteData::Action::reset (SurfacePtr surface)
54
55
{
55
- auto iter = mapping.get_iter ();
56
- while (iter.next ())
57
- {
58
- if (iter.get_key () == " name" ) {
59
- iter.get (name);
60
- } else if (iter.get_key () == " action" ) {
61
- parse_action (iter.as_mapping ());
62
- } else {
63
- log_warning << " Unknown sprite field: " << iter.get_key () << std::endl;
64
- }
65
- }
66
- if (actions.empty ())
67
- throw std::runtime_error (" Error: Sprite without actions." );
56
+ x_offset = 0 ;
57
+ y_offset = 0 ;
58
+ hitbox_w = static_cast <float >(surface->get_width ());
59
+ hitbox_h = static_cast <float >(surface->get_height ());
60
+ hitbox_unisolid = false ;
61
+ fps = 10 ;
62
+ loops = -1 ;
63
+ loop_frame = 1 ;
64
+ has_custom_loops = false ;
65
+ family_name.clear ();
66
+ surfaces = { surface };
68
67
}
69
68
70
- SpriteData::SpriteData (const std::string& image) :
71
- actions(),
72
- name()
73
- {
74
- auto surface = Surface::from_file (image);
75
- if (!TextureManager::current ()->last_load_successful ())
76
- throw std::runtime_error (" Cannot load image." );
77
69
78
- auto action = create_action_from_surface (surface);
79
- action->name = " default" ;
80
- actions[action->name ] = std::move (action);
70
+ SpriteData::SpriteData (const std::string& filename) :
71
+ m_filename(filename),
72
+ m_load_successful(false ),
73
+ actions()
74
+ {
75
+ load ();
81
76
}
82
77
83
- SpriteData::SpriteData () :
84
- actions(),
85
- name()
78
+ void
79
+ SpriteData::load ()
86
80
{
87
- auto surface = Surface::from_texture (TextureManager::current ()->create_dummy_texture ());
88
- auto action = create_action_from_surface (surface);
89
- action->name = " default" ;
90
- actions[action->name ] = std::move (action);
81
+ // Reset all existing actions to a dummy texture
82
+ if (!actions.empty ())
83
+ {
84
+ auto surface = Surface::from_texture (TextureManager::current ()->create_dummy_texture ());
85
+ for (const auto & action : actions)
86
+ action.second ->reset (surface);
87
+ }
88
+
89
+ if (StringUtil::has_suffix (m_filename, " .sprite" ))
90
+ {
91
+ try
92
+ {
93
+ auto doc = ReaderDocument::from_file (m_filename);
94
+ auto root = doc.get_root ();
95
+
96
+ if (root.get_name () != " supertux-sprite" )
97
+ {
98
+ std::ostringstream msg;
99
+ msg << " '" << m_filename << " ' is not a 'supertux-sprite' file!" ;
100
+ throw std::runtime_error (msg.str ());
101
+ }
102
+ else
103
+ {
104
+ // Load ".sprite" file
105
+ parse (root.get_mapping ());
106
+ }
107
+ }
108
+ catch (const std::exception & err)
109
+ {
110
+ log_warning << " Parse error when trying to load sprite '" << m_filename
111
+ << " ': " << err.what () << std::endl;
112
+
113
+ // Load initial dummy texture
114
+ if (actions.empty ())
115
+ {
116
+ auto surface = Surface::from_texture (TextureManager::current ()->create_dummy_texture ());
117
+ auto action = std::make_unique<Action>();
118
+ action->name = " default" ;
119
+ action->reset (surface);
120
+ actions[action->name ] = std::move (action);
121
+ }
122
+
123
+ m_load_successful = false ;
124
+ return ;
125
+ }
126
+ }
127
+ else
128
+ {
129
+ // Load single image
130
+ auto surface = Surface::from_file (m_filename);
131
+ if (!TextureManager::current ()->last_load_successful ())
132
+ throw std::runtime_error (" Cannot load image." );
133
+
134
+ // Create action, if it doesn't exist
135
+ {
136
+ auto i = actions.find (" default" );
137
+ if (i == actions.end ())
138
+ {
139
+ auto action = std::make_unique<Action>();
140
+ action->name = " default" ;
141
+ actions[" default" ] = std::move (action);
142
+ }
143
+ }
144
+ actions[" default" ]->reset (surface);
145
+ }
146
+
147
+ m_load_successful = true ;
91
148
}
92
149
93
- std::unique_ptr<SpriteData::Action>
94
- SpriteData::create_action_from_surface (SurfacePtr surface )
150
+ void
151
+ SpriteData::parse ( const ReaderMapping& mapping )
95
152
{
96
- auto action = std::make_unique<Action>();
97
-
98
- action->hitbox_w = static_cast <float >(surface->get_width ());
99
- action->hitbox_h = static_cast <float >(surface->get_height ());
100
- action->surfaces .push_back (surface);
153
+ auto iter = mapping.get_iter ();
154
+ while (iter.next ())
155
+ {
156
+ if (iter.get_key () == " action" )
157
+ parse_action (iter.as_mapping ());
158
+ else
159
+ log_warning << " Unknown sprite field: " << iter.get_key () << std::endl;
160
+ }
101
161
102
- return action;
162
+ if (actions.empty ())
163
+ throw std::runtime_error (" Error: Sprite without actions." );
103
164
}
104
165
105
166
void
106
167
SpriteData::parse_action (const ReaderMapping& mapping)
107
168
{
108
- auto action = std::make_unique<Action>();
169
+ std::string name;
170
+ mapping.get (" name" , name);
109
171
110
- if (!mapping. get ( " name " , action-> name ))
172
+ // Create action, if it doesn't exist
111
173
{
112
- if (!actions.empty ())
113
- throw std::runtime_error (" If there are more than one action, they need names!" );
174
+ auto i = actions.find (name);
175
+ if (i == actions.end ())
176
+ {
177
+ auto action = std::make_unique<Action>();
178
+ action->name = name;
179
+ actions[name] = std::move (action);
180
+ }
114
181
}
182
+ Action* action = actions[name].get ();
183
+
184
+ // Reset action
185
+ action->hitbox_w = 0 ;
186
+ action->hitbox_h = 0 ;
187
+ action->surfaces .clear ();
115
188
116
189
std::vector<float > hitbox;
117
190
if (mapping.get (" hitbox" , hitbox))
@@ -128,7 +201,7 @@ SpriteData::parse_action(const ReaderMapping& mapping)
128
201
break ;
129
202
130
203
default :
131
- throw std::runtime_error (" hitbox should specify 2/4 coordinates" );
204
+ throw std::runtime_error (" Hitbox should specify 2/4 coordinates! " );
132
205
}
133
206
}
134
207
mapping.get (" unisolid" , action->hitbox_unisolid );
@@ -141,7 +214,7 @@ SpriteData::parse_action(const ReaderMapping& mapping)
141
214
{
142
215
if (action->loop_frame < 1 )
143
216
{
144
- log_warning << " 'loop-frame' of action '" << action->name << " ' in sprite '" << name << " ' set to a value below 1." << std::endl;
217
+ log_warning << " 'loop-frame' of action '" << action->name << " ' in sprite '" << m_filename << " ' set to a value below 1." << std::endl;
145
218
action->loop_frame = 1 ;
146
219
}
147
220
}
@@ -343,7 +416,7 @@ SpriteData::parse_action(const ReaderMapping& mapping)
343
416
else
344
417
{
345
418
std::stringstream msg;
346
- msg << " Sprite '" << name << " ' unknown tag in 'surfaces' << " << i.get_name ();
419
+ msg << " Sprite '" << m_filename << " ' unknown tag in 'surfaces' << " << i.get_name ();
347
420
throw std::runtime_error (msg.str ());
348
421
}
349
422
}
@@ -362,7 +435,7 @@ SpriteData::parse_action(const ReaderMapping& mapping)
362
435
else
363
436
{
364
437
std::stringstream msg;
365
- msg << " Sprite '" << name << " ' contains no images in action '"
438
+ msg << " Sprite '" << m_filename << " ' contains no images in action '"
366
439
<< action->name << " '." ;
367
440
throw std::runtime_error (msg.str ());
368
441
}
@@ -372,11 +445,9 @@ SpriteData::parse_action(const ReaderMapping& mapping)
372
445
const int frames = static_cast <int >(action->surfaces .size ());
373
446
if (action->loop_frame > frames && frames > 0 )
374
447
{
375
- log_warning << " 'loop-frame' of action '" << action->name << " ' in sprite '" << name << " ' not-in-range of total frames." << std::endl;
448
+ log_warning << " 'loop-frame' of action '" << action->name << " ' in sprite '" << m_filename << " ' not-in-range of total frames." << std::endl;
376
449
action->loop_frame = 1 ;
377
450
}
378
-
379
- actions[action->name ] = std::move (action);
380
451
}
381
452
382
453
const SpriteData::Action*
0 commit comments