/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "m4/graphics/gr_series.h" #include "m4/core/errors.h" #include "m4/wscript/ws_load.h" #include "m4/wscript/ws_machine.h" #include "m4/wscript/wst_regs.h" #include "m4/vars.h" #include "m4/m4.h" namespace M4 { void Series::play(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum, int32 frameRate, int32 loopCount, int32 s, int32 x, int32 y, int32 firstFrame, int32 lastFrame) { _series = M4::series_play(seriesName, layer, flags, triggerNum, frameRate, loopCount, s, x, y, firstFrame, lastFrame); const Common::String shadow = Common::String::format("%ss", seriesName); _seriesS = M4::series_play(shadow.c_str(), layer + 1, flags, -1, frameRate, loopCount, s, x, y, firstFrame, lastFrame); } void Series::show(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum, int32 duration, int32 index, int32 s, int32 x, int32 y) { _series = M4::series_show(seriesName, layer, flags, triggerNum, duration, index, s, x, y); const Common::String shadow = Common::String::format("%ss", seriesName); _seriesS = M4::series_show(shadow.c_str(), layer + 1, flags, -1, duration, index, s, x, y); } void Series::show(const char *series1, const char *series2, int layer) { _series = M4::series_show(series1, layer); _seriesS = M4::series_show(series2, layer + 1); } void Series::show_index2(const char *series1, const char *series2, int layer, int index1, int index2) { _series = M4::series_show(series1, layer, 0, -1, -1, index1); _seriesS = M4::series_show(series2, layer + 1, 0, -1, -1, index1 + 1); } void Series::series_play(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum, int32 frameRate, int32 loopCount, int32 s, int32 x, int32 y, int32 firstFrame, int32 lastFrame) { Series tmp; tmp.play(seriesName, layer, flags, triggerNum, frameRate, loopCount, s, x, y, firstFrame, lastFrame); } void Series::series_show(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum, int32 duration, int32 index, int32 s, int32 x, int32 y) { Series tmp; tmp.show(seriesName, layer, flags, triggerNum, duration, index, s, x, y); } void Series::terminate() { if (_series) terminateMachineAndNull(_series); if (_seriesS) terminateMachineAndNull(_seriesS); } static void series_trigger_dispatch_callback(frac16 myMessage, machine * /*sender*/) { kernel_trigger_dispatchx(myMessage); } int32 series_load(const char *seriesName, int32 assetIndex, RGB8 *myPal) { const int32 myAssetIndex = AddWSAssetCELS(seriesName, assetIndex, myPal); if ((myAssetIndex < 0) || (myAssetIndex >= 256)) error_show(FL, 'SPNF', seriesName); return myAssetIndex; } void series_unload(int32 assetIndex) { ClearWSAssets(_WS_ASSET_CELS, assetIndex, assetIndex); } bool series_draw_sprite(int32 spriteHash, int32 index, Buffer *destBuff, int32 x, int32 y) { M4sprite srcSprite; M4Rect clipRect, updateRect; if (!destBuff) { error_show(FL, 'BUF!'); return false; } M4sprite *srcSpritePtr = &srcSprite; if ((srcSpritePtr = GetWSAssetSprite(nullptr, (uint32)spriteHash, (uint32)index, srcSpritePtr, nullptr)) == nullptr) error_show(FL, 'SPNF', "hash: %d, index: %d", spriteHash, index); HLock(srcSpritePtr->sourceHandle); //gr_pal_interface(&master_palette[0]); srcSpritePtr->data = (uint8 *)((intptr)*(srcSpritePtr->sourceHandle) + srcSpritePtr->sourceOffset); RendGrBuff Destination; DrawRequestX dr; RendCell Frame; Destination.Width = destBuff->stride; Destination.Height = destBuff->h; Destination.PixMap = (void *)destBuff->data; dr.x = x; dr.y = y; dr.scale_x = 100; dr.scale_y = 100; dr.depth_map = destBuff->data; dr.Pal = nullptr; dr.ICT = nullptr; dr.depth = 0; Frame.hot_x = srcSpritePtr->xOffset; Frame.hot_y = srcSpritePtr->yOffset; Frame.Width = srcSpritePtr->w; Frame.Height = srcSpritePtr->h; Frame.Comp = (uint32)srcSpritePtr->encoding; Frame.data = srcSpritePtr->data; clipRect.x1 = 0; clipRect.y1 = 0; clipRect.x2 = Destination.Width; clipRect.y2 = Destination.Height; // and draw the sprite render_sprite_to_8BBM(&Destination, &dr, &Frame, &clipRect, &updateRect); HUnLock(srcSpritePtr->sourceHandle); return true; } bool series_show_frame(int32 spriteHash, int32 index, Buffer *destBuff, int32 x, int32 y) { return series_draw_sprite(spriteHash, index, destBuff, x, y); } machine *series_stream(const char *seriesName, int32 frameRate, int32 layer, int32 trigger) { SysFile *sysFile = new SysFile(seriesName); // Store the frameRate in g_temp1 // If it is < 0, the default frame rate for the ss will be used _G(globals)[GLB_TEMP_1] = frameRate << 16; // Store the SysFile pointer _G(globals)[GLB_TEMP_4] = (intptr)sysFile; // Set the callback trigger _G(globals)[GLB_TEMP_5] = kernel_trigger_create(trigger); // Set the layer _G(globals)[GLB_TEMP_6] = layer << 16; machine *m = kernel_spawn_machine(seriesName, HASH_STREAM_MACHINE, series_trigger_dispatch_callback); return m; } bool series_stream_break_on_frame(machine *m, int32 frameNum, int32 trigger) { // Parameter verification if (!m) return false; _G(globals)[GLB_TEMP_2] = frameNum << 16; _G(globals)[GLB_TEMP_3] = kernel_trigger_create(trigger); // Send the message to the machine to accept the new callback frame num and trigger sendWSMessage(0x10000, 0, m, 0, nullptr, 1); return true; } void series_set_frame_rate(machine *m, int32 newFrameRate) { if ((!m) || (!m->myAnim8) || !verifyMachineExists(m)) { if (g_engine->getGameType() == GType_Burger) error_show(FL, 'SSFR'); return; } m->myAnim8->myRegs[IDX_CELS_FRAME_RATE] = newFrameRate << 16; } machine *series_show(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum, int32 duration, int32 index, int32 s, int32 x, int32 y) { int32 myAssetIndex; RGB8 *tempPalettePtr = nullptr; term_message(seriesName); if (flags & SERIES_LOAD_PALETTE) tempPalettePtr = &_G(master_palette)[0]; if ((myAssetIndex = AddWSAssetCELS(seriesName, -1, tempPalettePtr)) < 0) error_show(FL, 'SPNF', seriesName); _G(globals)[GLB_TEMP_1] = (frac16)myAssetIndex << 24; // cels hash _G(globals)[GLB_TEMP_2] = layer << 16; // layer _G(globals)[GLB_TEMP_3] = kernel_trigger_create(triggerNum); // trigger _G(globals)[GLB_TEMP_4] = duration << 16; // frame duration (-1=forever, 0=default) _G(globals)[GLB_TEMP_5] = index << 16; // index of series to show _G(globals)[GLB_TEMP_6] = (s << 16) / 100; // scale _G(globals)[GLB_TEMP_7] = x << 16; // x _G(globals)[GLB_TEMP_8] = y << 16; // y _G(globals)[GLB_TEMP_14] = (flags & SERIES_STICK) ? 0x10000 : 0; // stick to screen after trigger? _G(globals)[GLB_TEMP_16] = (flags & SERIES_HORZ_FLIP) ? 0x10000 : 0;// horizontal flip machine *m = kernel_spawn_machine(seriesName, HASH_SERIES_SHOW_MACHINE, series_trigger_dispatch_callback); if (!m) error_show(FL, 'WSMF', seriesName); return m; } machine *series_place_sprite(const char *seriesName, int32 index, int32 x, int32 y, int32 s, int32 layer) { return series_show(seriesName, layer, 0x40, -1, -1, index, s, x, y); } machine *series_show_sprite(const char *seriesName, int32 index, int32 layer) { return series_show(seriesName, layer, 0x40, -1, -1, index); } machine *series_play(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum, int32 frameRate, int32 loopCount, int32 s, int32 x, int32 y, int32 firstFrame, int32 lastFrame) { int32 myAssetIndex; RGB8 *tempPalettePtr = nullptr; term_message(seriesName); if (flags & SERIES_LOAD_PALETTE) tempPalettePtr = &_G(master_palette)[0]; if ((myAssetIndex = AddWSAssetCELS(seriesName, -1, tempPalettePtr)) < 0) error_show(FL, 'SPNF', seriesName); _G(globals)[GLB_TEMP_1] = (frac16)myAssetIndex << 24; // cels hash _G(globals)[GLB_TEMP_2] = layer << 16; // layer _G(globals)[GLB_TEMP_3] = kernel_trigger_create(triggerNum); // trigger _G(globals)[GLB_TEMP_4] = frameRate << 16; // framerate _G(globals)[GLB_TEMP_5] = loopCount << 16; // loop count _G(globals)[GLB_TEMP_6] = (s << 16) / 100; // scale _G(globals)[GLB_TEMP_7] = x << 16; // x _G(globals)[GLB_TEMP_8] = y << 16; // y _G(globals)[GLB_TEMP_9] = firstFrame << 16; // first frame _G(globals)[GLB_TEMP_10] = lastFrame << 16; // last frame _G(globals)[GLB_TEMP_11] = (flags & SERIES_PINGPONG) ? 0x10000 : 0; // ping pong _G(globals)[GLB_TEMP_12] = (flags & SERIES_BACKWARD) ? 0x10000 : 0; // backwards _G(globals)[GLB_TEMP_13] = (flags & SERIES_RANDOM) ? 0x10000 : 0; // random _G(globals)[GLB_TEMP_14] = (flags & SERIES_STICK) ? 0x10000 : 0; // stick to screen _G(globals)[GLB_TEMP_15] = (flags & SERIES_LOOP_TRIGGER) ? 0x10000 : 0; // trigger back every loop? _G(globals)[GLB_TEMP_16] = (flags & SERIES_HORZ_FLIP) ? 0x10000 : 0; // horizontal flip machine *m = kernel_spawn_machine(seriesName, HASH_SERIES_PLAY_MACHINE, series_trigger_dispatch_callback); if (!m) error_show(FL, 'WSMF', seriesName); return m; } machine *series_ranged_play(const char *seriesName, int32 loopCount, uint32 flags, int32 firstFrame, int32 lastFrame, int32 s, uint32 layer, int32 frameRate, int32 trigger, bool stickWhenDone) { if (loopCount == 1) loopCount = 0; if (stickWhenDone) flags |= 0x10; return series_play(seriesName, layer, flags, trigger, frameRate, loopCount, s, 0, 0, firstFrame, lastFrame); } machine *series_ranged_play_xy(const char *seriesName, int loopCount, int flags, int firstFrame, int lastFrame, int x, int y, int s, int layer, int frameRate, int trigger, bool stick_when_done) { if (loopCount == 1) loopCount = 0; if (stick_when_done) flags |= 0x10; return series_play(seriesName, layer, flags, trigger, frameRate, loopCount, s, x, y, firstFrame, lastFrame); } machine *series_plain_play(const char *seriesName, int32 loopCount, uint32 flags, int32 s, int32 layer, int32 frameRate, int32 trigger, bool stickWhenDone) { if (stickWhenDone) flags |= 0x10; if (loopCount == 1) loopCount = 0; return series_play(seriesName, layer, flags, trigger, frameRate, loopCount, s); } machine *series_play_xy(const char *seriesName, int loopCount, int flags, int x, int y, int scale, int layer, int frameRate, int trigger) { if (loopCount == 1) loopCount = 0; return series_play(seriesName, layer, flags, trigger, frameRate, loopCount, scale, x, y); } machine *series_simple_play(const char *seriesName, frac16 layer, bool stickWhenDone) { int flags = 0; if (stickWhenDone) flags |= 0x10; return series_play(seriesName, layer, flags); } } // namespace M4