2 #include <mof/script/Environment.hpp>
3 #include <mof/ConsoleIO.hpp>
4 #include "mof/EventScheduler.hpp"
5 #include "mof/OnceEventCondition.hpp"
6 #include "mof/KeyPressedEventCondition.hpp"
7 #include <mof/widgets.hpp>
8 #include <mof/streams.hpp>
9 #include <mof/Matrix3D.hpp>
10 #include <mof/Sprite.hpp>
11 #include <mof/script/ObjectData.hpp>
12 #include <mof/utilities.hpp>
13 #include <boost/bind.hpp>
14 #include <boost/format.hpp>
15 #include <boost/algorithm/string.hpp>
16 #include <mof/sound/SoundDevice.hpp>
25 struct Environment::Impl
27 bool waiting_; ///< Interpreterにコマンド実行の停止を伝えるための状態変数
28 mof::EventScheduler scheduler_; ///< キー入力待機など
29 std::shared_ptr<mof::InputReceiver> input_;
30 std::vector<std::shared_ptr<mof::script::MessageData>> message_data_list_;
31 std::vector<std::shared_ptr<mof::script::MenuData>> menu_data_list_;
32 std::vector<std::shared_ptr<mof::script::SoundData>> sound_data_list_;
33 std::vector<mof::script::PictureData::ptr> picture_data_list_;
34 std::vector<mof::script::ParticlegenData::ptr> particlegen_data_list_;
35 std::map<std::string, int> property_map_;
37 Impl(std::shared_ptr<mof::InputReceiver> input)
38 : waiting_(false), input_(input)
42 void setWaiting(bool waiting)
50 Environment::Environment(std::shared_ptr<mof::InputReceiver> input)
51 : impl_(new Impl(input))
53 impl_->property_map_["system.menu.move_cursor_sound"] = sound_create(_T("sound/move_cursor.wav"));
57 Environment::~Environment()
62 int Environment::message_create(const mof::tstring& title, const GameData::entry_t& style)
64 using namespace mof::script;
65 using namespace boost;
67 DEBUG_PRINT("message_create(" << title << ")");
68 std::shared_ptr<MessageData> data = std::shared_ptr<MessageData>(create_message_data(title, style).release());
69 impl_->message_data_list_.push_back(data);// TODO 再利用
70 return impl_->message_data_list_.size() -1;
74 int Environment::message_next(int id, const tstring& text)
76 DEBUG_PRINT("message_next(" << id << "," << text << ")");
77 std::shared_ptr<mof::script::MessageData>& data = impl_->message_data_list_.at(id);
78 data->message_->addPage(text);
79 return data->message_->nextPage();
83 int Environment::menu_create
85 const mof::tstring& title,
86 const std::vector<mof::tstring>& items,
87 const GameData::entry_t& style
90 using namespace mof::script;
91 using namespace boost;
93 DEBUG_PRINT("menu_create(" << title << ")");
94 std::shared_ptr<MenuData> data = std::shared_ptr<MenuData>(create_menu_data(title, items, style).release());
95 impl_->menu_data_list_.push_back(data);
96 return impl_->menu_data_list_.size() -1;
99 //{{{ menu_move_cursor
100 int Environment::menu_move_cursor(int id, MoveDirection direction)
102 using namespace mof::script;
103 using namespace boost;
105 DEBUG_PRINT(format("menu_move_cursor(%d, %d)") % id % direction);
106 auto& data = impl_->menu_data_list_.at(id);
107 auto& sound_data = impl_->sound_data_list_.at(impl_->property_map_["system.menu.move_cursor_sound"]);
108 int prev_index = data->menu_->getSelectedIndex();
109 mof::FrameNumber period;
112 period = data->menu_->up();
115 period = data->menu_->down();
118 period = data->menu_->left();
121 period = data->menu_->right();
126 if (data->menu_->getSelectedIndex() != prev_index) {
127 sound_data->sound_->stop();
128 sound_data->sound_->play(sound_data->streaming_);
134 int Environment::menu_select(int id)
136 using namespace mof::script;
137 using namespace boost;
139 DEBUG_PRINT(format("menu_select(%d)") % id);
140 auto& data = impl_->menu_data_list_.at(id);
141 return data->menu_->performAction();
144 //{{{ menu_get_current
145 int Environment::menu_get_current(int id)
147 using namespace mof::script;
148 using namespace boost;
150 DEBUG_PRINT(format("menu_get_current(%d)") % id);
151 auto& data = impl_->menu_data_list_.at(id);
152 DEBUG_PRINT(data->menu_->getSelectedIndex());
153 return data->menu_->getSelectedIndex();
157 void Environment::wait_for_key(mof::InputReceiver::Key key)
159 DEBUG_PRINT("wait_for_key(" << key << ")");
160 bool& waiting = impl_->waiting_;
161 impl_->scheduler_.addEvent
163 new mof::OnceEventCondition(new mof::KeyPressedEventCondition(key, impl_->input_)),
164 [&waiting](){waiting = false;}
166 impl_->waiting_ = true;
170 void Environment::wait_frame(size_t frame)
172 DEBUG_PRINT("wait_frame(" << frame << ")");
173 if (frame == 0)return;
174 bool& waiting = impl_->waiting_;
175 impl_->scheduler_.addEvent(frame, [&waiting](){waiting = false;});// set waiting_ false after 'frame'
176 impl_->waiting_ = true;
180 mof::InputReceiver::Key Environment::get_last_key()
182 //TODO 複数同時をtimestampで識別
183 DEBUG_PRINT("get_last_key()");
184 for (int key = mof::InputReceiver::BEGIN + 1; key < mof::InputReceiver::ANY; ++key) {
185 if (impl_->input_->testKeyState(static_cast<mof::InputReceiver::Key>(key))) {
186 return static_cast<mof::InputReceiver::Key>(key);// 最初に見つかったものを選ぶ
189 return mof::InputReceiver::END;// 何も入力されていないとき
193 int Environment::sound_create(const mof::tstring& filepath)
195 using namespace mof::script;
196 using namespace boost;
200 DEBUG_PRINT("sound_create(" << filepath << ")");
201 auto ptr = mof::sound::SoundDevice::create_static_sound(filepath);
203 auto data = std::make_shared<SoundData>();
204 data->sound_ = std::shared_ptr<mof::SoundBuffer>(ptr.release());
205 data->streaming_ = false;
206 impl_->sound_data_list_.push_back(data);
207 return impl_->sound_data_list_.size() -1;
211 void Environment::sound_play(int id)
213 using namespace mof::script;
214 using namespace boost;
216 DEBUG_PRINT("sound_play(" << id << ")");
217 impl_->sound_data_list_.at(id)->sound_->play(false);
221 GameData::ptr Environment::load_game_data(const mof::tstring& resource_path)
223 return get_game_data(resource_path);
227 void Environment::print_debug(const mof::tstring& message)
229 DEBUG_PRINT(message);
233 int Environment::picture_create(const mof::tstring& filepath)
235 using namespace mof::script;
236 using namespace boost;
238 DEBUG_PRINT("picture_create(" << filepath << ")");
239 auto data = std::make_shared<PictureData>();
241 std::make_shared<Sprite>
243 std::make_shared<mof::Texture>(filepath),
244 mof::Rectangle<mof::real>(0, 0, 1, 1)
246 impl_->picture_data_list_.push_back(data);// TODO 再利用
247 return impl_->picture_data_list_.size() -1;
251 //{{{ particlegen_create
252 int Environment::particlegen_create()
254 using namespace mof::script;
255 using namespace boost;
257 DEBUG_PRINT("particlegen_create()");
258 //DEBUG_PRINT("picture_create(" << filepath << ")");
259 auto data = std::make_shared<ParticlegenData>();
260 data->particlegen_ = std::make_shared<mof::particlegen>();
261 data->particlegen_->world_transform() << data->position_ref_.makeRef(Matrix3D::createIdentity());
262 impl_->particlegen_data_list_.push_back(data);// TODO 再利用
263 return impl_->particlegen_data_list_.size() -1;
267 // methods for common objects
269 int Environment::show(int id, const mof::tstring& class_path)
271 using namespace mof::script;
272 using namespace boost;
274 if (class_path == "menu") {
275 DEBUG_PRINT("menu_show(" << id << ")");
276 std::shared_ptr<MenuData>& data = impl_->menu_data_list_.at(id);
277 return data->frame_->show();
279 else if (class_path == "message") {
280 DEBUG_PRINT("message_show(" << id << ")");
281 std::shared_ptr<mof::script::MessageData>& data = impl_->message_data_list_.at(id);
282 return data->frame_->show();
284 else throw std::invalid_argument("unknown class path:" + class_path);
288 int Environment::hide(int id, const mof::tstring& class_path)
290 using namespace mof::script;
291 using namespace boost;
293 if (class_path == "menu") {
294 DEBUG_PRINT("menu_hide(" << id << ")");
295 std::shared_ptr<MenuData>& data = impl_->menu_data_list_.at(id);
296 return data->frame_->hide();
298 else if (class_path == "message") {
299 DEBUG_PRINT("message_hide(" << id << ")");
300 std::shared_ptr<mof::script::MessageData>& data = impl_->message_data_list_.at(id);
301 return data->frame_->hide();
303 else throw std::invalid_argument("unknown class path:" + class_path);
307 void Environment::dispose(int id, const mof::tstring& class_path)
309 using namespace mof::script;
310 using namespace boost;
312 if (class_path == "menu") {
313 DEBUG_PRINT("menu_dispose(" << id << ")");
314 impl_->menu_data_list_.at(id) = std::shared_ptr<MenuData>();// NULLに設定
316 else if (class_path == "message") {
317 DEBUG_PRINT("message_dispose(" << id << ")");
318 impl_->message_data_list_.at(id) = std::shared_ptr<MessageData>();// NULLに設定
320 else if (class_path == "picture") {
321 DEBUG_PRINT("picture_dispose(" << id << ")");
322 impl_->picture_data_list_.at(id) = std::shared_ptr<PictureData>();// NULLに設定
324 else if (class_path == "particlegen") {
325 DEBUG_PRINT("particlegen_dispose(" << id << ")");
326 impl_->particlegen_data_list_.at(id) = std::shared_ptr<ParticlegenData>();// NULLに設定
328 else if (class_path == "sound") {
329 DEBUG_PRINT("sound_dispose(" << id << ")");
330 impl_->sound_data_list_.at(id) = std::shared_ptr<SoundData>();// NULLに設定
332 else throw std::invalid_argument("unknown class path:" + class_path);
336 GameData::ptr Environment::get_properties(int id, const mof::tstring& class_path)
338 using namespace mof::script;
339 using namespace boost;
340 GameData::ptr game_data = std::make_shared<GameData>();
341 game_data->data_.resize(1);
342 GameData::entry_t& e = game_data->data_.front();
344 if (class_path == "menu") {
345 DEBUG_PRINT("get_property(" << id << class_path << ")");
346 std::shared_ptr<MenuData>& data = impl_->menu_data_list_.at(id);
347 Vector2D v = data->frame_->getView()->getPreferredSize();
348 e["preferred_size"] = (format("%d,%d") % v.x % v.y).str();
349 Vector2D pos = data->frame_->getView()->getPositionStream().value();
350 e["position2"] = (format("%d,%d") % pos.x % pos.y).str();
352 else if (class_path == "message") {
353 DEBUG_PRINT("get_property(" << id << class_path << ")");
354 std::shared_ptr<MessageData>& data = impl_->message_data_list_.at(id);
355 Vector2D v = data->frame_->getView()->getPreferredSize();
356 e["preferred_size"] = (format("%d,%d") % v.x % v.y).str();
357 Vector2D pos = data->frame_->getView()->getPositionStream().value();
358 e["position2"] = (format("%d,%d") % pos.x % pos.y).str();
360 else if (class_path == "picture") {
361 DEBUG_PRINT("get_property(" << id << class_path << ")");
362 std::shared_ptr<PictureData>& data = impl_->picture_data_list_.at(id);
363 Vector2D v = data->sprite_->getPreferredSize();
364 e["preferred_size"] = (format("%d,%d") % v.x % v.y).str();
365 Vector2D pos = data->sprite_->getPositionStream().value();
366 e["position2"] = (format("%d,%d") % pos.x % pos.y).str();
369 else throw std::invalid_argument("unknown class path:" + class_path);
374 //{{{ set_color_behavior
375 void Environment::set_color_behavior(int id, const mof::tstring& class_path, const Manipulator<Color4f>::ptr& seq, mof::FrameNumber period)
377 using namespace boost::algorithm;
378 DEBUG_PRINT("set_color_behavior(" << ")");
380 std::vector<mof::tstring> splited_list;
381 split(splited_list, class_path, is_any_of("."));
382 if (splited_list.front() == "picture") {
383 auto picture = impl_->picture_data_list_.at(id);
384 picture->sprite_->setColorStream(ColorStream(seq));
387 else if (splited_list.front() == "menu") {
388 if (splited_list.at(1) == "open") {
389 auto menu = impl_->menu_data_list_.at(id);
390 menu->frame_->setBehaviorOnColor(mof::widget::Frame::FRAME_OPEN, seq, period);
393 else if (splited_list.at(1) == "close") {
394 auto menu = impl_->menu_data_list_.at(id);
395 menu->frame_->setBehaviorOnColor(mof::widget::Frame::FRAME_CLOSE, seq, period);
400 else if (splited_list.front() == "message") {
401 if (splited_list.at(1) == "open") {
402 auto message = impl_->message_data_list_.at(id);
403 message->frame_->setBehaviorOnColor(mof::widget::Frame::FRAME_OPEN, seq, period);
406 else if (splited_list.at(1) == "close") {
407 auto message = impl_->message_data_list_.at(id);
408 message->frame_->setBehaviorOnColor(mof::widget::Frame::FRAME_CLOSE, seq, period);
416 throw std::logic_error("unknown class_path:" + class_path);
419 //{{{ set_position_behavior
420 void Environment::set_position_behavior(int id, const mof::tstring& class_path, const Manipulator<Vector2D>::ptr& seq, mof::FrameNumber period)
422 using namespace boost::algorithm;
423 DEBUG_PRINT("set_position_behavior(" << ")");
425 std::vector<mof::tstring> splited_list;
426 split(splited_list, class_path, is_any_of("."));
427 if (splited_list.front() == "picture") {
428 auto picture = impl_->picture_data_list_.at(id);
429 picture->sprite_->setPositionStream(Vector2DStream(seq));
432 else if (splited_list.front() == "menu") {
433 if (splited_list.at(1) == "open") {
434 auto menu = impl_->menu_data_list_.at(id);
435 menu->frame_->setBehaviorOnPosition(mof::widget::Frame::FRAME_OPEN, seq, period);
438 else if (splited_list.at(1) == "close") {
439 auto menu = impl_->menu_data_list_.at(id);
440 menu->frame_->setBehaviorOnPosition(mof::widget::Frame::FRAME_CLOSE, seq, period);
445 else if (splited_list.front() == "message") {
446 if (splited_list.at(1) == "open") {
447 auto message = impl_->message_data_list_.at(id);
448 message->frame_->setBehaviorOnPosition(mof::widget::Frame::FRAME_OPEN, seq, period);
451 else if (splited_list.at(1) == "close") {
452 auto message = impl_->message_data_list_.at(id);
453 message->frame_->setBehaviorOnPosition(mof::widget::Frame::FRAME_CLOSE, seq, period);
459 throw std::logic_error("unknown class_path:" + class_path);
462 //{{{ set_position_behavior
463 void Environment::set_position_behavior(int id, const mof::tstring& class_path, const Manipulator<Vector3D>::ptr& seq, mof::FrameNumber period)
465 using namespace boost::algorithm;
467 DEBUG_PRINT("set_position_behavior(" << ")");
469 std::vector<mof::tstring> splited_list;
470 split(splited_list, class_path, is_any_of("."));
471 if (splited_list.front() == "particlegen") {
472 auto p = impl_->particlegen_data_list_.at(id);
473 p->position_ref_.replace(0, std::make_shared<Translation3D>(seq));
478 throw std::logic_error("unknown class_path:" + class_path);
481 //{{{ set_size_behavior
482 void Environment::set_size_behavior(int id, const mof::tstring& class_path, const Manipulator<Vector2D>::ptr& seq, mof::FrameNumber period)
484 using namespace boost::algorithm;
485 DEBUG_PRINT("set_position_behavior(" << ")");
487 std::vector<mof::tstring> splited_list;
488 split(splited_list, class_path, is_any_of("."));
489 if (splited_list.front() == "picture") {
490 auto picture = impl_->picture_data_list_.at(id);
491 picture->sprite_->setSizeStream(Vector2DStream(seq));
494 else if (splited_list.front() == "menu") {
495 if (splited_list.at(1) == "open") {
496 auto menu = impl_->menu_data_list_.at(id);
497 menu->frame_->setBehaviorOnSize(mof::widget::Frame::FRAME_OPEN, seq, period);
500 else if (splited_list.at(1) == "close") {
501 auto menu = impl_->menu_data_list_.at(id);
502 menu->frame_->setBehaviorOnSize(mof::widget::Frame::FRAME_CLOSE, seq, period);
507 else if (splited_list.front() == "message") {
508 if (splited_list.at(1) == "open") {
509 auto message = impl_->message_data_list_.at(id);
510 message->frame_->setBehaviorOnSize(mof::widget::Frame::FRAME_OPEN, seq, period);
513 else if (splited_list.at(1) == "close") {
514 auto message = impl_->message_data_list_.at(id);
515 message->frame_->setBehaviorOnSize(mof::widget::Frame::FRAME_CLOSE, seq, period);
520 throw std::logic_error("unknown class_path:" + class_path);
525 void Environment::update()
527 using namespace mof::script;
529 impl_->scheduler_.update();
530 foreach (auto data, impl_->message_data_list_) {
531 if (data.get()) data->frame_->update();
533 foreach (auto data, impl_->menu_data_list_) {
534 if (data.get()) data->frame_->update();
536 foreach (auto data, impl_->sound_data_list_) {
537 if (data.get()) data->sound_->update();
540 foreach (auto data, impl_->picture_data_list_) {
541 if (data.get()) data->sprite_->update();
544 foreach (auto data, impl_->particlegen_data_list_) {
545 if (data) data->particlegen_->update();
552 void Environment::draw() const
554 using namespace mof::script;
557 mof::GraphicsDevice::setAlphaBlendingMode(mof::GraphicsDevice::BLENDING_MODE_ADD);
558 mof::GraphicsDevice::setZBuffer(false);
559 foreach (auto& data, impl_->particlegen_data_list_) {
561 auto& list = data->particlegen_->drawables();
562 foreach (auto p, list) p->draw();
566 mof::GraphicsDevice::setZBuffer(true);
567 mof::GraphicsDevice::setAlphaBlendingMode(mof::GraphicsDevice::BLENDING_MODE_ALPHA);
569 foreach (auto data, impl_->picture_data_list_) {
570 if (data.get()) data->sprite_->draw();
574 foreach (auto data, impl_->message_data_list_) {
575 if (data.get()) data->frame_->getView()->draw();
578 foreach (auto data, impl_->menu_data_list_) {
579 if (data.get()) data->frame_->getView()->draw();
586 bool Environment::isWaiting() const
588 return impl_->waiting_;