diff options
author | Willem Jan Palenstijn | 2009-10-03 20:49:18 +0000 |
---|---|---|
committer | Willem Jan Palenstijn | 2009-10-03 20:49:18 +0000 |
commit | b9cdb1abb76c94723c24ca66eb8d47d96c8c5ebd (patch) | |
tree | d4f40b3f6a8f55aef1e24506bd3771f8269d64a1 | |
parent | f6de0b4ec9fcc240cdc0c46aedb2e2089e07bd5c (diff) | |
download | scummvm-rg350-b9cdb1abb76c94723c24ca66eb8d47d96c8c5ebd.tar.gz scummvm-rg350-b9cdb1abb76c94723c24ca66eb8d47d96c8c5ebd.tar.bz2 scummvm-rg350-b9cdb1abb76c94723c24ca66eb8d47d96c8c5ebd.zip |
SCI: Merge new GUI code written by m_kiewitz.
This is a major rewrite of the graphics code. A slightly adapted
version of the old code is still available and currently the default.
The new code is selectable in sci.cpp, but is not yet finished.
svn-id: r44565
35 files changed, 5704 insertions, 627 deletions
diff --git a/dists/msvc8/sci.vcproj b/dists/msvc8/sci.vcproj index 3b6ef9206e..fcbed561ef 100644 --- a/dists/msvc8/sci.vcproj +++ b/dists/msvc8/sci.vcproj @@ -92,6 +92,29 @@ <File RelativePath="..\..\engines\sci\gfx\seq_decoder.cpp" /> <File RelativePath="..\..\engines\sci\gfx\seq_decoder.h" /> </Filter> + <Filter Name="gui"> + <File RelativePath="..\..\engines\sci\gui\gui.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_dbllist.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_dbllist.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_font.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_font.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_gfx.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_gfx.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_helpers.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_memmgr.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_memmgr.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_picture.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_picture.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_screen.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_screen.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_view.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_view.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_windowmgr.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_windowmgr.h" /> + <File RelativePath="..\..\engines\sci\gui32\gui32.h" /> + <File RelativePath="..\..\engines\sci\gui32\gui32.cpp" /> + </Filter> <Filter Name="sfx"> <File RelativePath="..\..\engines\sci\sfx\core.cpp" /> <File RelativePath="..\..\engines\sci\sfx\core.h" /> diff --git a/dists/msvc9/sci.vcproj b/dists/msvc9/sci.vcproj index c9b4dc9a8b..dbca6ab062 100644 --- a/dists/msvc9/sci.vcproj +++ b/dists/msvc9/sci.vcproj @@ -93,6 +93,29 @@ <File RelativePath="..\..\engines\sci\gfx\seq_decoder.cpp" /> <File RelativePath="..\..\engines\sci\gfx\seq_decoder.h" /> </Filter> + <Filter Name="gui"> + <File RelativePath="..\..\engines\sci\gui\gui.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_dbllist.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_dbllist.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_font.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_font.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_gfx.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_gfx.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_helpers.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_memmgr.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_memmgr.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_picture.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_picture.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_screen.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_screen.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_view.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_view.h" /> + <File RelativePath="..\..\engines\sci\gui\gui_windowmgr.cpp" /> + <File RelativePath="..\..\engines\sci\gui\gui_windowmgr.h" /> + <File RelativePath="..\..\engines\sci\gui32\gui32.h" /> + <File RelativePath="..\..\engines\sci\gui32\gui32.cpp" /> + </Filter> <Filter Name="sfx"> <File RelativePath="..\..\engines\sci\sfx\core.cpp" /> <File RelativePath="..\..\engines\sci\sfx\core.h" /> diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 64b7601bb0..436abd66d4 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -332,18 +332,18 @@ SciKernelFunction kfunct_mappers[] = { DEFUN("ShowMovie", kShowMovie, "..*"), DEFUN("SetVideoMode", kSetVideoMode, "i"), DEFUN("Platform", kPlatform, "i*"), - DEFUN("PalVary", kPalVary, "ii*"), + DEFUN("TextColors", kTextColors, ".*"), + DEFUN("TextFonts", kTextFonts, ".*"), #if 0 // Stub functions + DEFUN("PalVary", kPalVary, "ii*"), DEFUN("ShiftScreen", kShiftScreen, ".*"), DEFUN("MemorySegment", kMemorySegment, ".*"), DEFUN("ListOps", kListOps, ".*"), DEFUN("ATan", kATan, ".*"), DEFUN("MergePoly", kMergePoly, ".*"), DEFUN("AssertPalette", kAssertPalette, ".*"), - DEFUN("TextColors", kTextColors, ".*"), - DEFUN("TextFonts", kTextFonts, ".*"), DEFUN("Record", kRecord, ".*"), DEFUN("PlayBack", kPlayBack, ".*"), DEFUN("DbugStr", kDbugStr, ".*"), diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index bb88fab45c..2e9025eba0 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -454,7 +454,8 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv); reg_t kSetVideoMode(EngineState *s, int argc, reg_t *argv); reg_t kStrSplit(EngineState *s, int argc, reg_t *argv); reg_t kPlatform(EngineState *s, int argc, reg_t *argv); -reg_t kPalVary(EngineState *s, int argc, reg_t *argv); +reg_t kTextColors(EngineState *s, int argc, reg_t *argv); +reg_t kTextFonts(EngineState *s, int argc, reg_t *argv); } // End of namespace Sci diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index d86fcdd073..728dad0df7 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -206,11 +206,13 @@ reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) { SegManager *segMan = s->segMan; if (obj.segment) { - int x = GET_SEL32V(obj, x); - int y = GET_SEL32V(obj, y); + int16 x = GET_SEL32V(obj, x); + int16 y = GET_SEL32V(obj, y); - PUT_SEL32V(obj, x, x - s->port->zone.x); - PUT_SEL32V(obj, y, y - s->port->zone.y); + s->gui->globalToLocal(&x, &y); + + PUT_SEL32V(obj, x, x); + PUT_SEL32V(obj, y, y); } return s->r_acc; @@ -222,11 +224,13 @@ reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv) { SegManager *segMan = s->segMan; if (obj.segment) { - int x = GET_SEL32V(obj, x); - int y = GET_SEL32V(obj, y); + int16 x = GET_SEL32V(obj, x); + int16 y = GET_SEL32V(obj, y); + + s->gui->localToGlobal(&x, &y); - PUT_SEL32V(obj, x, x + s->port->zone.x); - PUT_SEL32V(obj, y, y + s->port->zone.y); + PUT_SEL32V(obj, x, x); + PUT_SEL32V(obj, y, y); } return s->r_acc; diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 353c21a46d..51d9d3cb50 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -105,7 +105,8 @@ static inline int sign_extend_byte(int value) { return value; } -static void assert_primary_widget_lists(EngineState *s) { +// was static +void assert_primary_widget_lists(EngineState *s) { if (!s->dyn_views) { rect_t bounds = s->picture_port->_bounds; @@ -123,7 +124,8 @@ static void assert_primary_widget_lists(EngineState *s) { } } -static void reparentize_primary_widget_lists(EngineState *s, GfxPort *newport) { +// static +void reparentize_primary_widget_lists(EngineState *s, GfxPort *newport) { if (!newport) newport = s->picture_port; @@ -264,24 +266,6 @@ PaletteEntry get_pic_color(EngineState *s, int color) { } } -static gfx_color_t graph_map_color(EngineState *s, int color, int priority, int control) { - gfx_color_t retval; - - if (!s->resMan->isVGA()) { - retval = s->ega_colors[(color >=0 && color < 16)? color : 0]; - gfxop_set_color(s->gfx_state, &retval, (color < 0) ? -1 : retval.visual.r, retval.visual.g, retval.visual.b, - (color == -1) ? 255 : 0, priority, control); - } else { - retval.visual = get_pic_color(s, color); - retval.alpha = 0; - retval.priority = priority; - retval.control = control; - retval.mask = GFX_MASK_VISUAL | ((priority >= 0) ? GFX_MASK_PRIORITY : 0) | ((control >= 0) ? GFX_MASK_CONTROL : 0); - }; - - return retval; -} - static reg_t kSetCursorSci0(EngineState *s, int argc, reg_t *argv) { int16 cursor = argv[0].toSint16(); @@ -353,27 +337,8 @@ reg_t kSetCursor(EngineState *s, int argc, reg_t *argv) { } reg_t kMoveCursor(EngineState *s, int argc, reg_t *argv) { - Common::Point newPos; - - newPos = s->gfx_state->pointer_pos; - - if (argc == 1) { - // Case ignored on IBM PC - } else { - newPos.x = argv[0].toSint16() + s->port->zone.x; - newPos.y = argv[1].toSint16() + s->port->zone.y; - - if (newPos.x > s->port->zone.x + s->port->zone.width) - newPos.x = s->port->zone.x + s->port->zone.width; - if (newPos.y > s->port->zone.y + s->port->zone.height) - newPos.y = s->port->zone.y + s->port->zone.height; - - if (newPos.x < 0) newPos.x = 0; - if (newPos.y < 0) newPos.y = 0; - } - - gfxop_set_pointer_position(s->gfx_state, newPos); - + if (argc == 2) + s->gui->moveCursor(argv[0].toSint16(), argv[1].toSint16()); return s->r_acc; } @@ -439,116 +404,73 @@ void _k_redraw_box(EngineState *s, int x1, int y1, int x2, int y2) { #endif } -void _k_graph_rebuild_port_with_color(EngineState *s, gfx_color_t newbgcolor) { - GfxPort *port = s->port; - GfxPort *newport; - - newport = sciw_new_window(s, port->zone, port->_font, port->_color, newbgcolor, - s->titlebar_port->_font, s->ega_colors[15], s->ega_colors[8], - port->_title_text.c_str(), port->port_flags & ~kWindowTransparent); - - if (s->dyn_views) { - int found = 0; - GfxContainer *parent = s->dyn_views->_parent; - - while (parent && !(found |= (parent == port))) - parent = parent->_parent; - - s->dyn_views = NULL; +reg_t kGraph(EngineState *s, int argc, reg_t *argv) { + int rectLeft = 0, rectTop = 0, rectRight = 0, rectBottom = 0; + uint16 flags; + int16 priority, control, color, colorMask; + + Common::Rect rect; + if (argc>=5) { + rectLeft = argv[2].toSint16(); rectTop = argv[1].toSint16(); + rectRight = argv[4].toSint16(); rectBottom = argv[3].toSint16(); + // Fixup data, so that a valid rectangle is formed + if (rectLeft > rectRight) { + rectRight = rectLeft; rectLeft = argv[4].toSint16(); + } + if (rectTop > rectBottom) { + rectBottom = rectTop; rectTop = argv[3].toSint16(); + } + rect = Common::Rect (rectLeft, rectTop, rectRight, rectBottom); } - port->_parent->add((GfxContainer *)port->_parent, newport); - delete port; -} - -static bool activated_icon_bar = false; // FIXME: Avoid non-const global vars -static int port_origin_x = 0; // FIXME: Avoid non-const global vars -static int port_origin_y = 0; // FIXME: Avoid non-const global vars - -reg_t kGraph(EngineState *s, int argc, reg_t *argv) { - rect_t area; + // old code, may be removed later after class migration GfxPort *port = s->port; int redraw_port = 0; - + rect_t area; area = gfx_rect(argv[2].toSint16(), argv[1].toSint16() , argv[4].toSint16(), argv[3].toSint16()); - area.width = area.width - area.x; // Since the actual coordinates are absolute area.height = area.height - area.y; switch (argv[0].toSint16()) { case K_GRAPH_GET_COLORS_NR: - return make_reg(0, !s->resMan->isVGA() ? 0x10 : 0x100); break; - case K_GRAPH_DRAW_LINE: { - int16 priority = (argc > 6) ? argv[6].toSint16() : -1; - int16 control = (argc > 7) ? argv[7].toSint16() : -1; - gfx_color_t gfxcolor = graph_map_color(s, argv[5].toSint16(), priority, control); + case K_GRAPH_DRAW_LINE: + priority = (argc > 6) ? argv[6].toSint16() : -1; + control = (argc > 7) ? argv[7].toSint16() : -1; + color = argv[5].toSint16(); - debugC(2, kDebugLevelGraphics, "draw_line((%d, %d), (%d, %d), col=%d, p=%d, c=%d, mask=%d)\n", - argv[2].toSint16(), argv[1].toSint16(), argv[4].toSint16(), argv[3].toSint16(), argv[5].toSint16(), priority, control, gfxcolor.mask); - - redraw_port = 1; - - // Note: it's quite possible that the coordinates of the line will *not* form a valid rectangle (e.g. it might - // have negative width/height). The actual dirty rectangle is constructed in gfxdr_add_dirty(). - // FIXME/TODO: We need to change the semantics of this call, so that no fake rectangles are used. As it is, it's - // not possible change rect_t to Common::Rect, as we assume that Common::Rect forms a *valid* rectangle. - ADD_TO_CURRENT_PICTURE_PORT(gfxw_new_line(Common::Point(argv[2].toSint16(), argv[1].toSint16()), Common::Point(argv[4].toSint16(), argv[3].toSint16()), - gfxcolor, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL)); - - } - break; + // FIXME: rect must be changed to 2 Common::Point + s->gui->graphDrawLine(rect, color, priority, control); + break; case K_GRAPH_SAVE_BOX: - - area.x += s->port->zone.x + port_origin_x; - area.y += s->port->zone.y + port_origin_y; - area.width += -port_origin_x; - area.height += -port_origin_y; - - return(graph_save_box(s, area)); + flags = (argc > 5) ? argv[5].toUint16() : 0; + return s->gui->graphSaveBox(rect, flags); break; case K_GRAPH_RESTORE_BOX: - - graph_restore_box(s, argv[1]); + s->gui->graphRestoreBox(argv[1]); break; case K_GRAPH_FILL_BOX_BACKGROUND: - - _k_graph_rebuild_port_with_color(s, port->_bgcolor); - port = s->port; - - redraw_port = 1; + s->gui->graphFillBoxBackground(rect); break; case K_GRAPH_FILL_BOX_FOREGROUND: - - _k_graph_rebuild_port_with_color(s, port->_color); - port = s->port; - - redraw_port = 1; + s->gui->graphFillBoxForeground(rect); break; - case K_GRAPH_FILL_BOX_ANY: { - int16 priority = (argc > 7) ? argv[7].toSint16() : -1; - int16 control = (argc > 8) ? argv[8].toSint16() : -1; - gfx_color_t color = graph_map_color(s, argv[6].toSint16(), priority, control); - - color.mask = (byte)argv[5].toUint16(); - - debugC(2, kDebugLevelGraphics, "fill_box_any((%d, %d), (%d, %d), col=%d, p=%d, c=%d, mask=%d)\n", - argv[2].toSint16(), argv[1].toSint16(), argv[4].toSint16(), argv[3].toSint16(), argv[6].toSint16(), priority, control, argv[5].toUint16()); - - // FIXME/TODO: this is not right, as some of the dialogs are drawn *behind* some widgets. But at least it works for now - //ADD_TO_CURRENT_PICTURE_PORT(gfxw_new_box(s->gfx_state, area, color, color, GFX_BOX_SHADE_FLAT)); // old code - s->picture_port->add((GfxContainer *)s->picture_port, gfxw_new_box(s->gfx_state, area, color, color, GFX_BOX_SHADE_FLAT)); + case K_GRAPH_FILL_BOX_ANY: + priority = (argc > 7) ? argv[7].toSint16() : -1; + control = (argc > 8) ? argv[8].toSint16() : -1; + color = argv[6].toSint16(); + colorMask = argv[5].toUint16(); - } - break; + s->gui->graphFillBox(rect, colorMask, color, priority, control); + break; case K_GRAPH_UPDATE_BOX: { @@ -557,14 +479,12 @@ reg_t kGraph(EngineState *s, int argc, reg_t *argv) { area.x += s->port->zone.x; area.y += s->port->zone.y; - gfxop_update_box(s->gfx_state, area); - + // FIXME: Change to class calling + //gfxop_update_box(s->gfx_state, area); } break; case K_GRAPH_REDRAW_BOX: { - - debugC(2, kDebugLevelGraphics, "redraw_box(%d, %d, %d, %d)\n", argv[1].toSint16(), argv[2].toSint16(), argv[3].toSint16(), argv[4].toSint16()); area.x += s->port->zone.x; @@ -573,10 +493,9 @@ reg_t kGraph(EngineState *s, int argc, reg_t *argv) { if (s->dyn_views && s->dyn_views->_parent == (GfxContainer *)s->port) s->dyn_views->draw(Common::Point(0, 0)); - gfxop_update_box(s->gfx_state, area); - + // FIXME: Change to class calling + //gfxop_update_box(s->gfx_state, area); } - break; case K_GRAPH_ADJUST_PRIORITY: @@ -601,22 +520,19 @@ reg_t kGraph(EngineState *s, int argc, reg_t *argv) { } reg_t kTextSize(EngineState *s, int argc, reg_t *argv) { - int width, height; + int16 textWidth, textHeight; Common::String text = s->segMan->getString(argv[1]); reg_t *dest = s->segMan->derefRegPtr(argv[0], 4); int maxwidth = (argc > 3) ? argv[3].toUint16() : 0; int font_nr = argv[2].toUint16(); Common::String sep_str; - const char *sep = NULL; + const char *sep = NULL; if ((argc > 4) && (argv[4].segment)) { sep_str = s->segMan->getString(argv[4]); sep = sep_str.c_str(); } - if (maxwidth < 0) - maxwidth = 0; - dest[0] = dest[1] = NULL_REG; if (text.empty() || !dest) { // Empty text @@ -625,20 +541,19 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } - gfxop_get_text_params(s->gfx_state, font_nr, s->strSplit(text.c_str(), sep).c_str(), maxwidth ? maxwidth : MAX_TEXT_WIDTH_MAGIC_VALUE, - &width, &height, 0, NULL, NULL, NULL); - debugC(2, kDebugLevelStrings, "GetTextSize '%s' -> %dx%d\n", text.c_str(), width, height); - - dest[2] = make_reg(0, height); -// dest[3] = make_reg(0, maxwidth? maxwidth : width); - dest[3] = make_reg(0, width); + textWidth = dest[3].toUint16(); textHeight = dest[2].toUint16(); + s->gui->textSize(s->strSplit(text.c_str(), sep).c_str(), font_nr, maxwidth, &textWidth, &textHeight); + debugC(2, kDebugLevelStrings, "GetTextSize '%s' -> %dx%d\n", text.c_str(), textWidth, textHeight); + dest[2] = make_reg(0, textHeight); + dest[3] = make_reg(0, textWidth); return s->r_acc; } reg_t kWait(EngineState *s, int argc, reg_t *argv) { - uint32 time; int sleep_time = argv[0].toUint16(); +#if 0 + uint32 time; time = g_system->getMillis(); s->r_acc = make_reg(0, ((long)time - (long)s->last_wait_time) * 60 / 1000); @@ -650,6 +565,11 @@ reg_t kWait(EngineState *s, int argc, reg_t *argv) { // Reset speed throttler: Game is playing along nicely anyway if (sleep_time > 0) s->speedThrottler->reset(); +#endif + + // FIXME: we should not be asking from the GUI to wait. The kernel sounds + // like a better place + s->gui->wait(sleep_time); return s->r_acc; } @@ -977,72 +897,25 @@ void _k_view_list_free_backgrounds(EngineState *s, ViewObject *list, int list_nr #define K_DRAWPIC_FLAG_MIRRORED (1 << 14) reg_t kDrawPic(EngineState *s, int argc, reg_t *argv) { - drawn_pic_t dp; - bool add_to_pic = (argc > 2) ? !argv[2].toSint16() : false; - gfx_color_t transparent = s->wm_port->_bgcolor; - int picFlags = DRAWPIC01_FLAG_FILL_NORMALLY; - - if (s->_kernel->usesOldGfxFunctions()) - add_to_pic = (argc > 2) ? argv[2].toSint16() : false; - - dp.nr = argv[0].toSint16(); - dp.palette = (argc > 3) ? argv[3].toSint16() : 0; - - if ((argc > 1) && (argv[1].toUint16() & K_DRAWPIC_FLAG_MIRRORED)) - picFlags |= DRAWPIC1_FLAG_MIRRORED; - - gfxop_disable_dirty_frames(s->gfx_state); - - if (NULL != s->old_screen) { - gfxop_free_pixmap(s->gfx_state, s->old_screen); - } - - s->old_screen = gfxop_grab_pixmap(s->gfx_state, gfx_rect(0, 10, 320, 190)); - - debugC(2, kDebugLevelGraphics, "Drawing pic.%03d\n", argv[0].toSint16()); - - if (add_to_pic) { - gfxop_add_to_pic(s->gfx_state, dp.nr, picFlags, dp.palette); - } else { - gfxop_new_pic(s->gfx_state, dp.nr, picFlags, dp.palette); + sciResourceId pictureId = argv[0].toUint16(); + uint16 flags = 0; + uint16 style = 1; + int16 EGApaletteNo = -1; + + if (argc >= 2) + style = argv[1].toUint16(); + if (argc >= 3) { + if (!s->_kernel->usesOldGfxFunctions()) + flags = !argv[2].toUint16(); + else + flags = argv[2].toUint16(); } + if (argc >= 4) + EGApaletteNo = argv[3].toUint16(); - delete s->wm_port; - delete s->picture_port; - delete s->iconbar_port; - - s->wm_port = new GfxPort(s->visual, s->gfx_state->pic_port_bounds, s->ega_colors[0], transparent); - s->picture_port = new GfxPort(s->visual, s->gfx_state->pic_port_bounds, s->ega_colors[0], transparent); - - s->iconbar_port = new GfxPort(s->visual, gfx_rect(0, 0, 320, 200), s->ega_colors[0], transparent); - s->iconbar_port->_flags |= GFXW_FLAG_NO_IMPLICIT_SWITCH; - - s->visual->add((GfxContainer *)s->visual, s->picture_port); - s->visual->add((GfxContainer *)s->visual, s->wm_port); - s->visual->add((GfxContainer *)s->visual, s->iconbar_port); - - s->port = s->picture_port; - - s->pic_priority_table = gfxop_get_pic_metainfo(s->gfx_state); - - if (argc > 1) - s->pic_animate = argv[1].toSint16() & 0xff; // The animation used during kAnimate() later on - - s->dyn_views = NULL; - s->drop_views = NULL; - - s->priority_first = 42; - - if (s->_kernel->usesOldGfxFunctions()) - s->priority_last = 200; - else - s->priority_last = 190; - - s->pic_not_valid = 1; - s->pic_is_new = 1; + s->gui->drawPicture(pictureId, style, flags, EGApaletteNo); return s->r_acc; - } Common::Rect set_base(EngineState *s, reg_t object) { @@ -1230,9 +1103,14 @@ reg_t kSetNowSeen(EngineState *s, int argc, reg_t *argv) { } reg_t kPalette(EngineState *s, int argc, reg_t *argv) { +// warning("kPalette %d", argv[0].toUint16()); switch (argv[0].toUint16()) { case 1: - debug(5, "STUB: kPalette() effect 1, direct palette set"); + if (argc==3) { + int resourceNo = argv[1].toUint16(); + int flags = argv[2].toUint16(); + s->gui->paletteSet(resourceNo, flags); + } break; case 2: debug(5, "STUB: kPalette() effect 2, set flag to colors"); @@ -1263,26 +1141,15 @@ reg_t kPalette(EngineState *s, int argc, reg_t *argv) { int g = argv[2].toUint16(); int b = argv[3].toUint16(); - int i, delta, bestindex = -1, bestdelta = 200000; - - for (i = 0; i < s->gfx_state->gfxResMan->getColorCount(); i++) { - int dr = abs(s->gfx_state->gfxResMan->getColor(i).r - r); - int dg = abs(s->gfx_state->gfxResMan->getColor(i).g - g); - int db = abs(s->gfx_state->gfxResMan->getColor(i).b - b); - - delta = dr * dr + dg * dg + db * db; - - if (delta < bestdelta) { - bestdelta = delta; - bestindex = i; - } - } - // Don't warn about inexact mappings -- it's actually the - // rule rather than the exception - return make_reg(0, bestindex); + return make_reg(0, s->gui->paletteFind(r, g, b)); } case 6: - debug(5, "STUB: kPalette() effect 6, animate palette"); + if (argc==4) { + int fromColor = argv[1].toUint16(); + int toColor = argv[2].toUint16(); + int speed = argv[3].toSint16(); + s->gui->paletteAnimate(fromColor, toColor, speed); + } break; case 7: debug(5, "STUB: kPalette() effect 7, save palette to heap"); @@ -1297,12 +1164,7 @@ reg_t kPalette(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -reg_t kPalVary(EngineState *s, int argc, reg_t *argv) { - warning("STUB: kPalVary()"); - return NULL_REG; -} - -static void _k_draw_control(EngineState *s, reg_t obj, int inverse); +static void _k_draw_control(EngineState *s, reg_t obj, bool inverse); static void disableCertainButtons(SegManager *segMan, Common::String gameName, reg_t obj) { reg_t text_pos = GET_SEL32(obj, text); @@ -1349,15 +1211,15 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) { reg_t obj = argv[0]; disableCertainButtons(s->segMan, s->_gameName, obj); - _k_draw_control(s, obj, 0); - FULL_REDRAW(); + _k_draw_control(s, obj, false); +// FULL_REDRAW(); return NULL_REG; } reg_t kHiliteControl(EngineState *s, int argc, reg_t *argv) { reg_t obj = argv[0]; - _k_draw_control(s, obj, 1); + _k_draw_control(s, obj, true); return s->r_acc; } @@ -1541,15 +1403,17 @@ reg_t kEditControl(EngineState *s, int argc, reg_t *argv) { case K_CONTROL_ICON: case K_CONTROL_BOX: case K_CONTROL_BUTTON: - if (event.segment) PUT_SEL32V(event, claimed, 1); - _k_draw_control(s, obj, 0); + // Control shall not be redrawn here, Original Sierra interpreter doesn't do it and it will mangle up + // menus in at least SQ5 + //if (event.segment) PUT_SEL32V(event, claimed, 1); + //_k_draw_control(s, obj, false); return NULL_REG; break; case K_CONTROL_TEXT: { int state = GET_SEL32V(obj, state); PUT_SEL32V(obj, state, state | kControlStateDitherFramed); - _k_draw_control(s, obj, 0); + _k_draw_control(s, obj, false); PUT_SEL32V(obj, state, state); } break; @@ -1562,7 +1426,7 @@ reg_t kEditControl(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { +static void _k_draw_control(EngineState *s, reg_t obj, bool inverse) { SegManager *segMan = s->segMan; int x = (int16)GET_SEL32V(obj, nsLeft); int y = (int16)GET_SEL32V(obj, nsTop); @@ -1570,6 +1434,9 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { int yl = (int16)GET_SEL32V(obj, nsBottom) - y; rect_t area = gfx_rect(x, y, xl, yl); + Common::Rect rect; + rect = Common::Rect (x, y, (int16)GET_SEL32V(obj, nsRight), (int16)GET_SEL32V(obj, nsBottom)); + int font_nr = GET_SEL32V(obj, font); reg_t text_pos = GET_SEL32(obj, text); Common::String text; @@ -1578,7 +1445,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { int view = GET_SEL32V(obj, view); int cel = sign_extend_byte(GET_SEL32V(obj, cel)); int loop = sign_extend_byte(GET_SEL32V(obj, loop)); - gfx_alignment_t mode; + int mode; int type = GET_SEL32V(obj, type); int state = GET_SEL32V(obj, state); @@ -1588,18 +1455,14 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { switch (type) { case K_CONTROL_BUTTON: debugC(2, kDebugLevelGraphics, "drawing button %04x:%04x to %d,%d\n", PRINT_REG(obj), x, y); - ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, s->strSplit(text.c_str(), NULL).c_str(), font_nr, - (int8)(state & kControlStateFramed), (int8)inverse, (int8)(state & kControlStateDisabled))); - break; + s->gui->drawControlButton(rect, obj, s->strSplit(text.c_str(), NULL).c_str(), font_nr, state, inverse); + return; case K_CONTROL_TEXT: mode = (gfx_alignment_t) GET_SEL32V(obj, mode); - debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x to %d,%d, mode=%d\n", PRINT_REG(obj), x, y, mode); - - ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, s->strSplit(text.c_str()).c_str(), font_nr, mode, - (int8)(!!(state & kControlStateDitherFramed)), (int8)inverse)); - break; + s->gui->drawControlText(rect, obj, s->strSplit(text.c_str(), NULL).c_str(), font_nr, mode, state, inverse); + return; case K_CONTROL_EDIT: debugC(2, kDebugLevelGraphics, "drawing edit control %04x:%04x to %d,%d\n", PRINT_REG(obj), x, y); @@ -1676,9 +1539,9 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { selection = i + 1; } } + ADD_TO_CURRENT_PICTURE_PORT(sciw_new_list_control(s->port, obj, area, font_nr, entries_list, entries_nr, list_top, selection, (int8)inverse)); - free(entries_list); delete[] strings; } @@ -2350,75 +2213,34 @@ reg_t kAddToPic(EngineState *s, int argc, reg_t *argv) { } reg_t kGetPort(EngineState *s, int argc, reg_t *argv) { - return make_reg(0, s->port->_ID); + return s->gui->getPort(); } reg_t kSetPort(EngineState *s, int argc, reg_t *argv) { - if (activated_icon_bar && argc == 6) { - port_origin_x = port_origin_y = 0; - activated_icon_bar = false; - return s->r_acc; - } - + uint16 portPtr; + Common::Rect picRect; + int16 picTop, picLeft; + switch (argc) { - case 1 : { - unsigned int port_nr = argv[0].toSint16(); - GfxPort *new_port; - - /* We depart from official semantics here, sorry! - Reasoning: Sierra SCI does not clip ports while we do. - Therefore a draw to the titlebar port (which is the - official semantics) would cut off the lower part of the - icons in an SCI1 icon bar. Instead we have an - iconbar_port that does not exist in SSCI. */ - if (port_nr == (unsigned int) - 1) port_nr = s->iconbar_port->_ID; - - new_port = s->visual->getPort(port_nr); - - if (!new_port) { - warning("Invalid port %04x requested", port_nr); - return NULL_REG; - } - - s->port->draw(gfxw_point_zero); // Update the port we're leaving - s->port = new_port; - return s->r_acc; - } - case 6 : { - port_origin_y = argv[0].toSint16(); - port_origin_x = argv[1].toSint16(); - - if (argv[0].toSint16() == -10) { - s->port->draw(gfxw_point_zero); // Update the port we're leaving - s->port = s->iconbar_port; - activated_icon_bar = true; - return s->r_acc; - } - - // Notify the graphics resource manager that the pic port bounds changed - s->gfx_state->gfxResMan->changePortBounds(argv[5].toUint16(), argv[4].toUint16(), argv[3].toUint16() + argv[5].toUint16(), argv[2].toUint16() + argv[4].toUint16()); - - // LSL6 calls kSetPort to extend the screen to draw the GUI. If we free all resources - // here, the background picture is freed too, and this makes everything a big mess. - // FIXME/TODO: This code really needs to be rewritten to conform to the original behavior - if (s->_gameName != "lsl6") { - s->gfx_state->pic_port_bounds = gfx_rect(argv[5].toUint16(), argv[4].toUint16(), argv[3].toUint16(), argv[2].toUint16()); - - // FIXME: Should really only invalidate all loaded pic resources here; - // this is overkill - s->gfx_state->gfxResMan->freeAllResources(); - } else { - // WORKAROUND for LSL6 - printf("SetPort case 6 called in LSL6. Origin: %d, %d - Clip rect: %d, %d, %d, %d\n", argv[1].toSint16(), argv[0].toSint16(), argv[5].toUint16(), argv[4].toUint16(), argv[3].toUint16(), argv[2].toUint16()); - } + case 1: + portPtr = argv[0].toSint16(); + s->gui->setPort(portPtr); + break; + case 6: + picRect.top = argv[0].toSint16(); + picRect.left = argv[1].toSint16(); + picRect.bottom = argv[2].toSint16(); + picRect.right = argv[3].toSint16(); + picTop = argv[4].toSint16(); + picLeft = argv[5].toSint16(); + s->gui->setPortPic(picRect, picTop, picLeft); break; - } - default : + + default: error("SetPort was called with %d parameters", argc); break; } - return NULL_REG; } @@ -2428,142 +2250,43 @@ reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) { int cel = argv[2].toSint16(); int x = argv[3].toSint16(); int y = argv[4].toSint16(); - int priority = (argc > 5) ? argv[5].toSint16() : -1; - GfxView *new_view; - - gfxop_check_cel(s->gfx_state, view, &loop, &cel); + int priority = (argc > 5) ? argv[5].toUint16() : -1; + int paletteNo = (argc > 6) ? argv[6].toSint16() : 0; - debugC(2, kDebugLevelGraphics, "DrawCel((%d,%d), (view.%d, %d, %d), p=%d)\n", x, y, view, loop, cel, priority); - - new_view = gfxw_new_view(s->gfx_state, Common::Point(x, y), view, loop, cel, 0, priority, -1, - ALIGN_LEFT, ALIGN_TOP, GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET); - - ADD_TO_CURRENT_PICTURE_PORT(new_view); - FULL_REDRAW(); + s->gui->drawCell(view, loop, cel, x, y, priority, paletteNo); return s->r_acc; } reg_t kDisposeWindow(EngineState *s, int argc, reg_t *argv) { - unsigned int goner_nr = argv[0].toSint16(); - GfxPort *goner; - GfxPort *pred; - - goner = s->visual->getPort(goner_nr); - if ((goner_nr < 3) || (goner == NULL)) { - error("Removal of invalid window %04x requested", goner_nr); - return s->r_acc; - } - - if (s->dyn_views && (GfxContainer *)s->dyn_views->_parent == (GfxContainer *)goner) { - reparentize_primary_widget_lists(s, (GfxPort *) goner->_parent); - } - - if (s->drop_views && (GfxContainer *)s->drop_views->_parent == (GfxContainer *)goner) - s->drop_views = NULL; // Kill it - - pred = gfxw_remove_port(s->visual, goner); - - if (goner == s->port) // Did we kill the active port? - s->port = pred; - - // Find the last port that exists and that isn't marked no-switch - int id = s->visual->_portRefs.size() - 1; - while (id > 0 && (!s->visual->_portRefs[id] || (s->visual->_portRefs[id]->_flags & GFXW_FLAG_NO_IMPLICIT_SWITCH))) - id--; - - debugC(2, kDebugLevelGraphics, "Activating port %d after disposing window %d\n", id, goner_nr); - s->port = (id >= 0) ? s->visual->_portRefs[id] : 0; - - if (!s->port) - s->port = gfxw_find_default_port(s->visual); - - gfxop_update(s->gfx_state); + int goner_nr = argv[0].toSint16(); + int arg2 = (argc != 2 || argv[2].toUint16() == 0 ? 0 : 1); + s->gui->disposeWindow(goner_nr, arg2); return s->r_acc; } reg_t kNewWindow(EngineState *s, int argc, reg_t *argv) { - GfxPort *window; - int x, y, xl, yl, flags; - gfx_color_t bgcolor; - gfx_color_t fgcolor; - gfx_color_t black; - gfx_color_t lWhite; - int priority; + Common::Rect rect1 (argv[1].toSint16(), argv[0].toSint16(), argv[3].toSint16(), argv[2].toSint16()); + Common::Rect rect2; int argextra = argc == 13 ? 4 : 0; // Triggers in PQ3 and SCI1.1 games + int style = argv[5 + argextra].toSint16(); + int priority = (argc > 6 + argextra) ? argv[6 + argextra].toSint16() : -1; + int colorPen = (argc > 7 + argextra) ? argv[7 + argextra].toSint16() : 0; + int colorBack = (argc > 8 + argextra) ? argv[8 + argextra].toSint16() : 255; - y = argv[0].toSint16(); - x = argv[1].toSint16(); - yl = argv[2].toSint16() - y; - xl = argv[3].toSint16() - x; - - y += s->wm_port->_bounds.y; - - if (x + xl > 319) - x -= ((x + xl) - 319); - - flags = argv[5 + argextra].toSint16(); - - priority = (argc > 6 + argextra) ? argv[6 + argextra].toSint16() : -1; - bgcolor.mask = 0; - - int16 bgColor = (argc > 8 + argextra) ? argv[8 + argextra].toSint16() : 255; + // const char *title = argv[4 + argextra].segment ? kernel_dereference_char_pointer(s, argv[4 + argextra], 0) : NULL; + if (argc==13) { + rect2 = Common::Rect (argv[5].toSint16(), argv[4].toSint16(), argv[7].toSint16(), argv[6].toSint16()); + } - if (bgColor >= 0) { - if (!s->resMan->isVGA()) - bgcolor.visual = get_pic_color(s, MIN<int>(bgColor, 15)); - else - bgcolor.visual = get_pic_color(s, bgColor); - bgcolor.mask = GFX_MASK_VISUAL; - } else { - bgcolor.visual = PaletteEntry(0,0,0); - } - - bgcolor.priority = priority; - bgcolor.mask |= priority >= 0 ? GFX_MASK_PRIORITY : 0; - bgcolor.alpha = 0; - bgcolor.control = -1; - debugC(2, kDebugLevelGraphics, "New window with params %d, %d, %d, %d\n", argv[0].toSint16(), argv[1].toSint16(), argv[2].toSint16(), argv[3].toSint16()); - - int16 visualColor = (argc > 7 + argextra) ? argv[7 + argextra].toSint16() : 0; - fgcolor.visual = get_pic_color(s, visualColor); - fgcolor.mask = GFX_MASK_VISUAL; - fgcolor.control = -1; - fgcolor.priority = -1; - fgcolor.alpha = 0; - black.visual = get_pic_color(s, 0); - black.mask = GFX_MASK_VISUAL; - black.alpha = 0; - black.control = -1; - black.priority = -1; - lWhite.visual = get_pic_color(s, !s->resMan->isVGA() ? 15 : 255); - lWhite.mask = GFX_MASK_VISUAL; - lWhite.alpha = 0; - lWhite.priority = -1; - lWhite.control = -1; Common::String title; if (argv[4 + argextra].segment) { title = s->segMan->getString(argv[4 + argextra]); title = s->strSplit(title.c_str(), NULL); } - window = sciw_new_window(s, gfx_rect(x, y, xl, yl), s->titlebar_port->_font, fgcolor, bgcolor, - s->titlebar_port->_font, lWhite, black, title.c_str(), flags); - - // PQ3 and SCI1.1 games have the interpreter store underBits implicitly - if (argextra) - gfxw_port_auto_restore_background(s->visual, window, gfx_rect(argv[5].toSint16(), argv[4].toSint16() + s->wm_port->_bounds.y, argv[7].toSint16() - argv[5].toSint16(), argv[6].toSint16() - argv[4].toSint16())); - - ADD_TO_WINDOW_PORT(window); - FULL_REDRAW(); - - window->draw(gfxw_point_zero); - gfxop_update(s->gfx_state); - - s->port = window; // Set active port - - return make_reg(0, window->_ID); + return s->gui->newWindow(rect1, rect2, style, priority, colorPen, colorBack, title.c_str()); } #define K_ANIMATE_CENTER_OPEN_H 0 // horizontally open from center @@ -3130,208 +2853,21 @@ reg_t kShakeScreen(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -#define K_DISPLAY_SET_COORDS 100 -#define K_DISPLAY_SET_ALIGNMENT 101 -#define K_DISPLAY_SET_COLOR 102 -#define K_DISPLAY_SET_BGCOLOR 103 -#define K_DISPLAY_SET_GRAYTEXT 104 -#define K_DISPLAY_SET_FONT 105 -#define K_DISPLAY_WIDTH 106 -#define K_DISPLAY_SAVE_UNDER 107 -#define K_DISPLAY_RESTORE_UNDER 108 -#define K_DONT_UPDATE_IMMEDIATELY 121 - reg_t kDisplay(EngineState *s, int argc, reg_t *argv) { - int argpt; reg_t textp = argv[0]; int index = (argc > 1) ? argv[1].toUint16() : 0; - int temp; - bool save_under = false; - gfx_color_t transparent = { PaletteEntry(), 0, -1, -1, 0 }; - Common::String text; - GfxPort *port = (s->port) ? s->port : s->picture_port; - bool update_immediately = true; - gfx_color_t color0, *color1, bg_color; - gfx_alignment_t halign = ALIGN_LEFT; - rect_t area = gfx_rect(port->draw_pos.x, port->draw_pos.y, 320 - port->draw_pos.x, 200 - port->draw_pos.y); - int gray = port->gray_text; - int font_nr = port->_font; - GfxText *text_handle; - - color0 = port->_color; - bg_color = port->_bgcolor; - // TODO: in SCI1VGA the default colors for text and background are #0 (black) - // SCI0 case should be checked + Common::String text; if (textp.segment) { - argpt = 1; + argc--; argv++; text = s->segMan->getString(textp); } else { - argpt = 2; + argc--; argc--; argv++; argv++; text = kernel_lookup_text(s, textp, index); } -#if 0 - if (!text) { - error("Display with invalid reference %04x:%04x", PRINT_REG(textp)); - return NULL_REG; - } -#endif - - while (argpt < argc) { - switch (argv[argpt++].toUint16()) { - - case K_DISPLAY_SET_COORDS: - - area.x = argv[argpt++].toUint16(); - area.y = argv[argpt++].toUint16(); - debugC(2, kDebugLevelGraphics, "Display: set_coords(%d, %d)\n", area.x, area.y); - break; - - case K_DISPLAY_SET_ALIGNMENT: - - halign = (gfx_alignment_t)argv[argpt++].toSint16(); - debugC(2, kDebugLevelGraphics, "Display: set_align(%d)\n", halign); - break; - - case K_DISPLAY_SET_COLOR: - - temp = argv[argpt++].toSint16(); - debugC(2, kDebugLevelGraphics, "Display: set_color(%d)\n", temp); - if (!s->resMan->isVGA() && temp >= 0 && temp <= 15) - color0 = (s->ega_colors[temp]); - else - if (s->resMan->isVGA() && temp >= 0 && temp < 256) { - color0.visual = get_pic_color(s, temp); - color0.mask = GFX_MASK_VISUAL; - } else - if (temp == -1) - color0 = transparent; - else - warning("Display: Attempt to set invalid fg color %d", temp); - break; - - case K_DISPLAY_SET_BGCOLOR: - - temp = argv[argpt++].toSint16(); - debugC(2, kDebugLevelGraphics, "Display: set_bg_color(%d)\n", temp); - if (!s->resMan->isVGA() && temp >= 0 && temp <= 15) - bg_color = s->ega_colors[temp]; - else - if (s->resMan->isVGA() && temp >= 0 && temp <= 256) { - bg_color.visual = get_pic_color(s, temp); - bg_color.mask = GFX_MASK_VISUAL; - } else - if (temp == -1) - bg_color = transparent; - else - warning("Display: Attempt to set invalid fg color %d", temp); - break; - - case K_DISPLAY_SET_GRAYTEXT: - - gray = argv[argpt++].toSint16(); - debugC(2, kDebugLevelGraphics, "Display: set_graytext(%d)\n", gray); - break; - - case K_DISPLAY_SET_FONT: - - font_nr = argv[argpt++].toUint16(); - - debugC(2, kDebugLevelGraphics, "Display: set_font(\"font.%03d\")\n", font_nr); - break; - - case K_DISPLAY_WIDTH: - - area.width = argv[argpt++].toUint16(); - if (area.width == 0) - area.width = MAX_TEXT_WIDTH_MAGIC_VALUE; - - debugC(2, kDebugLevelGraphics, "Display: set_width(%d)\n", area.width); - break; - - case K_DISPLAY_SAVE_UNDER: - - save_under = true; - debugC(2, kDebugLevelGraphics, "Display: set_save_under()\n"); - break; - - case K_DISPLAY_RESTORE_UNDER: - - debugC(2, kDebugLevelGraphics, "Display: restore_under(%04x)\n", argv[argpt].toUint16()); - graph_restore_box(s, argv[argpt++]); - update_immediately = true; - argpt++; - return s->r_acc; - - case K_DONT_UPDATE_IMMEDIATELY: - - update_immediately = false; - debugC(2, kDebugLevelGraphics, "Display: set_dont_update()\n"); - argpt++; - break; - - default: - debugC(2, kDebugLevelGraphics, "Unknown Display() command %x\n", argv[argpt - 1].toUint16()); - return NULL_REG; - } - } - - if (halign == ALIGN_LEFT) { - // If the text does not fit on the screen, move it to the left and upwards until it does - gfxop_get_text_params(s->gfx_state, font_nr, text.c_str(), area.width, &area.width, &area.height, 0, NULL, NULL, NULL); - - // Make the text fit on the screen - if (area.x + area.width > 320) - area.x += 320 - area.x - area.width; // Plus negative number = subtraction - - if (area.y + area.height > 200) - area.y += 200 - area.y - area.height; // Plus negative number = subtraction - } else { - // If the text does not fit on the screen, clip it till it does - if (area.x + area.width > s->gfx_state->pic_port_bounds.width) - area.width = s->gfx_state->pic_port_bounds.width - area.x; - - if (area.y + area.height > s->gfx_state->pic_port_bounds.height) - area.height = s->gfx_state->pic_port_bounds.height - area.y; - } - - if (gray) - color1 = &bg_color; - else - color1 = &color0; - - assert_primary_widget_lists(s); - - text_handle = gfxw_new_text(s->gfx_state, area, font_nr, s->strSplit(text.c_str()).c_str(), halign, ALIGN_TOP, color0, *color1, bg_color, 0); - - if (!text_handle) { - error("Display: Failed to create text widget"); - return NULL_REG; - } - - if (save_under) { // Backup - rect_t save_area = text_handle->_bounds; - save_area.x += port->_bounds.x; - save_area.y += port->_bounds.y; - - s->r_acc = graph_save_box(s, save_area); - text_handle->_serial++; // This is evil! - - debugC(2, kDebugLevelGraphics, "Saving (%d, %d) size (%d, %d) as %04x:%04x\n", save_area.x, save_area.y, save_area.width, save_area.height, PRINT_REG(s->r_acc)); - } - - debugC(2, kDebugLevelGraphics, "Display: Commiting text '%s'\n", text.c_str()); - - //ADD_TO_CURRENT_PICTURE_PORT(text_handle); - - ADD_TO_CURRENT_PICTURE_PORT(text_handle); - if ((!s->pic_not_valid) && update_immediately) { // Refresh if drawn to valid picture - FULL_REDRAW(); - debugC(2, kDebugLevelGraphics, "Refreshing display...\n"); - } - + s->gui->display(s->strSplit(text.c_str()).c_str(), argc, argv); return s->r_acc; } @@ -3488,4 +3024,16 @@ reg_t kSetVideoMode(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +// New calls for SCI11. Using those is only needed when using text-codes so that one is able to change +// font and/or color multiple times during kDisplay and kDrawControl +reg_t kTextFonts(EngineState *s, int argc, reg_t *argv) { + s->gui->textFonts(argc, argv); + return s->r_acc; +} + +reg_t kTextColors(EngineState *s, int argc, reg_t *argv) { + s->gui->textColors(argc, argv); + return s->r_acc; +} + } // End of namespace Sci diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 4d0bd8a73a..e46f707aae 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -131,7 +131,8 @@ reg_t kGetTime(EngineState *s, int argc, reg_t *argv) { switch (mode) { case K_NEW_GETTIME_TICKS : - retval = start_time * 60 / 1000; + retval = s->gui->getTimeTicks(); // FIXME + //retval = start_time * 60 / 1000; debugC(2, kDebugLevelTime, "GetTime(elapsed) returns %d", retval); break; case K_NEW_GETTIME_TIME_12HOUR : diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index cf7e1635d5..a8dbce53f1 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -44,6 +44,7 @@ namespace Common { #include "sci/engine/seg_manager.h" #include "sci/gfx/gfx_system.h" #include "sci/sfx/core.h" +#include "sci/gui/gui.h" namespace Sci { @@ -175,6 +176,8 @@ public: /* Non-VM information */ + SciGUI *gui; /* Currently active GUI */ + GfxState *gfx_state; /**< Graphics state and driver */ gfx_pixmap_t *old_screen; /**< Old screen content: Stored during kDrawPic() for kAnimate() */ @@ -319,6 +322,12 @@ private: */ PaletteEntry get_pic_color(EngineState *s, int color); +/* Functions used in gui32\gui32.cpp */ +reg_t graph_save_box(EngineState *s, rect_t area); +void graph_restore_box(EngineState *s, reg_t handle); +void assert_primary_widget_lists(EngineState *s); +void reparentize_primary_widget_lists(EngineState *s, GfxPort *newport); + } // End of namespace Sci #endif // SCI_INCLUDE_ENGINE_H diff --git a/engines/sci/gfx/gfx_driver.cpp b/engines/sci/gfx/gfx_driver.cpp index 15704b636c..ccf15f3e30 100644 --- a/engines/sci/gfx/gfx_driver.cpp +++ b/engines/sci/gfx/gfx_driver.cpp @@ -248,4 +248,19 @@ void GfxDriver::setPointer(gfx_pixmap_t *pointer, Common::Point *hotspot) { cursorData = 0; } +void GfxDriver::animatePalette(int fromColor, int toColor, int stepCount) { + int i; + PaletteEntry firstColor = _mode->palette->getColor(fromColor); + PaletteEntry loopColor; + for (i=fromColor+1; i<=toColor; i++) { + loopColor = _mode->palette->getColor(i); + loopColor.r = 0; + loopColor.g = 0; + loopColor.b = 0; + _mode->palette->makeSystemColor(i-1, loopColor); // loopColor.r, loopColor.g, loopColor.b); + } +// _mode->palette->setColor(toColor, firstColor.r, firstColor.g, firstColor.b); + _mode->palette->makeSystemColor(toColor, firstColor); +} + } // End of namespace Sci diff --git a/engines/sci/gfx/gfx_driver.h b/engines/sci/gfx/gfx_driver.h index ede48a6b34..1143d8e66d 100644 --- a/engines/sci/gfx/gfx_driver.h +++ b/engines/sci/gfx/gfx_driver.h @@ -228,6 +228,11 @@ public: gfx_mode_t *getMode() { return _mode; } byte *getVisual0() { return _visual[0]; } + /** + * Animates palette + */ + void animatePalette(int fromColor, int toColor, int stepCount); + private: gfx_pixmap_t *_priority[2]; byte *_visual[2]; diff --git a/engines/sci/gfx/res_view.cpp b/engines/sci/gfx/res_view.cpp index 95f6919b0c..cbe26b97d6 100644 --- a/engines/sci/gfx/res_view.cpp +++ b/engines/sci/gfx/res_view.cpp @@ -365,6 +365,12 @@ gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *reso return retval; } +// SCI1: +// [LoopCount:WORD] [MirrorMask:WORD] [??:WORD] [PaletteOffset:WORD] [LoopOffset0:WORD] [LoopOffset1:WORD]... +// Loop-data: +// [CellCount:WORD] [Unknown:WORD] [CellOffset0:WORD] [CellOffset1:WORD]... +// SCI11: +// [HeaderSize:WORD] [LoopCount:BYTE] [Unknown:BYTE] [??:WORD] [??:WORD] [PaletteOffset:WORD] gfxr_view_t *getVGAView(int id, byte *resource, int size, ViewType viewType) { uint16 palOffset = READ_LE_UINT16(resource + V1_PALETTE_OFFSET + ((viewType == kViewVga11) ? 2 : 0)); uint16 headerSize = (viewType == kViewVga11) ? READ_LE_UINT16(resource + V2_HEADER_SIZE) : 0; diff --git a/engines/sci/gui/gui.cpp b/engines/sci/gui/gui.cpp new file mode 100644 index 0000000000..9ba4ebe37a --- /dev/null +++ b/engines/sci/gui/gui.cpp @@ -0,0 +1,330 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/gui/gui_screen.h" +#include "sci/gui/gui_gfx.h" +#include "sci/gui/gui_windowmgr.h" +#include "sci/gui/gui_memmgr.h" +#include "sci/gui/gui_view.h" + +#include "sci/gfx/operations.h" + +namespace Sci { + +SciGUI::SciGUI(OSystem *system, EngineState *state) + : _system(system), _s(state) { + _screen = new SciGUIscreen(_system, _s); + _gfx = new SciGUIgfx(_system, _s, _screen); + _windowMgr = new SciGUIwindowMgr(_s, _gfx); +} + +SciGUI::SciGUI() { +} + +SciGUI::~SciGUI() { +} + +void SciGUI::init(bool oldGfxFunctions) { + _usesOldGfxFunctions = oldGfxFunctions; + + /* Set default SCI0 palette */ +} + +int16 SciGUI::getTimeTicks() { + return _gfx->_sysTicks; +} + +void SciGUI::wait(int16 ticks) { + uint32 waitto = _gfx->_sysTicks + ticks; + do { + //eventMgr->pollEvents(); + _system->delayMillis(_gfx->_sysSpeed >> 11); + } while (_gfx->_sysTicks < waitto); +} + +void SciGUI::setPort(uint16 portPtr) { + switch (portPtr) { + case 0: _gfx->SetPort(_windowMgr->_wmgrPort); break; + case 0xFFFF: _gfx->SetPort(_gfx->_menuPort); break; + default: + _gfx->SetPort((sciPort *)heap2Ptr(portPtr)); + }; +} + +void SciGUI::setPortPic(Common::Rect rect, int16 picTop, int16 picLeft) { + _windowMgr->_picWind->rect = rect; + _windowMgr->_picWind->top = picTop; + _windowMgr->_picWind->left = picLeft; + //if (argc >= 7) + //InitPri(42,190); +} + +reg_t SciGUI::getPort() { + return make_reg(0, ptr2heap((byte *)_gfx->GetPort())); +} + +void SciGUI::globalToLocal(int16 *x, int16 *y) { + sciPort *curPort = _gfx->GetPort(); + *x = *x - curPort->left; + *y = *y - curPort->top; +} + +void SciGUI::localToGlobal(int16 *x, int16 *y) { + sciPort *curPort = _gfx->GetPort(); + *x = *x + curPort->left; + *y = *y + curPort->top; +} + +reg_t SciGUI::newWindow(Common::Rect rect1, Common::Rect rect2, uint16 style, int16 priority, int16 colorPen, int16 colorBack, const char *title) { + sciWnd *wnd = NULL; + + if (rect2.top != 0 && rect2.left != 0 && rect2.height() != 0 && rect2.width() != 0) + wnd = _windowMgr->NewWindow(&rect1, &rect2, "", style, priority, 0); + else + wnd = _windowMgr->NewWindow(&rect1, NULL, "", style, priority, 0); + wnd->penClr = colorPen; + wnd->backClr = colorBack; + _windowMgr->DrawWindow(wnd); + return make_reg(0, ptr2heap((byte *)wnd)); +} + +void SciGUI::disposeWindow(uint16 windowPtr, int16 arg2) { + sciWnd *wnd = (sciWnd *)heap2Ptr(windowPtr); + _windowMgr->DisposeWindow(wnd, arg2); +} + +void SciGUI::display(const char *text, int argc, reg_t *argv) { + int displayArg; + sciPort oldPort; + int16 align = 0; + int16 bgcolor = -1, width = 0xFFFF, bRedraw = 1; + byte bSaveUnder = false; + Common::Rect rect, *orect = &((sciWnd *)_gfx->GetPort())->rect0; + + memcpy(&oldPort, _gfx->GetPort(), sizeof(sciPort)); + // setting defaults + _gfx->PenMode(0); + _gfx->PenColor(0); + _gfx->TextFace(0); + // processing codes in argv + while (argc > 0) { + displayArg = argv[0].toUint16(); + argc--; argv++; + switch (displayArg - 100) { + case 0: + _gfx->MoveTo(argv[0].toUint16(), argv[1].toUint16()); + argc -= 2; argv += 2; + break;// move pen + case 1: + align = argv[0].toUint16(); + argc--; argv++; + break;// set alignment + case 2: + _gfx->PenColor(argv[0].toUint16()); + argc--; argv++; + break;// set pen color + case 3: + bgcolor = argv[0].toUint16(); + argc--; argv++; + break; + case 4: + _gfx->TextFace(argv[0].toUint16()); + argc--; argv++; + break;// set text grayout flag + case 5: + _gfx->SetFont(argv[0].toUint16()); + argc--; argv++; + break;// set font + case 6: + width = argv[0].toUint16(); + argc--; argv++; + break; + case 7: + bSaveUnder = 1; + break; + case 8: // restore under +// if (hunk2Ptr(*pArgs)) { +// memcpy(&rect, hunk2Ptr(*pArgs), sizeof(Common::Rect)); +// // rect is now absolute. Have to move it to be port-relative +// rect.translate(-_gfx->RGetPort()->left, -_gfx->RGetPort()->top); +// _gfx->RestoreBits(*pArgs); +// ReAnimate(&rect); +// } + // finishing loop + argc = 0; + break; + case 0x15: + bRedraw = 0; + break; + default: + warning("Unknown kDisplay argument %X", displayArg); + break; + } + } + // now drawing the text + _gfx->TextSize(rect, text, -1, width); + _gfx->Move((orect->left <= 320 ? 0 : 320 - orect->left), (orect->top <= 200 ? 0 : 200 - orect->top)); // move port to (0,0) + rect.moveTo(_gfx->GetPort()->curLeft, _gfx->GetPort()->curTop); +// if (bSaveUnder) +// _acc = _gfx->SaveBits(rect, 1); + if (bgcolor != -1) + _gfx->FillRect(rect, 1, bgcolor, 0, 0); + _gfx->TextBox(text, 0, rect, align, 0xFFFF); +// if (_picNotValid == 0 && bRedraw) +// _gfx->ShowBits(rect, 1); + // restoring port and cursor pos + sciPort *currport = _gfx->GetPort(); + uint16 tTop = currport->curTop; + uint16 tLeft = currport->curLeft; + memcpy(currport, &oldPort, sizeof(sciPort)); + currport->curTop = tTop; + currport->curLeft = tLeft; + + _screen->UpdateWhole(); +} + +void SciGUI::textSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) { + Common::Rect rect(0, 0, *textWidth, *textHeight); + _gfx->TextSize(rect, text, font, maxWidth); + *textWidth = rect.width(); *textHeight = rect.height(); +} + +// Used SCI1+ for text codes +void SciGUI::textFonts(int argc, reg_t *argv) { +} + +// Used SCI1+ for text codes +void SciGUI::textColors(int argc, reg_t *argv) { +} + +void SciGUI::drawPicture(sciResourceId pictureId, uint16 style, uint16 flags, int16 EGApaletteNo) { + bool addToFlag = flags ? true : false; + + sciPort *oldPort = _gfx->SetPort((sciPort *)_windowMgr->_picWind); + + if (_windowMgr->isFrontWindow(_windowMgr->_picWind)) { + _gfx->drawPicture(pictureId, style, addToFlag, EGApaletteNo); + } else { + _windowMgr->BeginUpdate(_windowMgr->_picWind); + _gfx->drawPicture(pictureId, style, addToFlag, EGApaletteNo); + _windowMgr->EndUpdate(_windowMgr->_picWind); + } + _screen->UpdateWhole(); + + _gfx->SetPort(oldPort); + _s->pic_not_valid = 1; +} + +void SciGUI::drawCell(sciResourceId viewId, uint16 loopNo, uint16 cellNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo) { + _gfx->drawCell(viewId, loopNo, cellNo, leftPos, topPos, priority, paletteNo); + _gfx->SetCLUT(&_gfx->_sysPalette); + _screen->UpdateWhole(); +} + +void SciGUI::drawControlButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool inverse) { + rect.grow(1); + _gfx->EraseRect(rect); + _gfx->FrameRect(rect); + rect.grow(-2); + _gfx->TextFace(style & 1 ? 0 : 1); + _gfx->TextBox(text, 0, rect, 1, fontId); + _gfx->TextFace(0); + if (style & 8) { // selected + rect.grow(1); + _gfx->FrameRect(rect); + } + _screen->UpdateWhole(); +} + +void SciGUI::drawControlText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, bool inverse) { + rect.grow(1); + _gfx->EraseRect(rect); + rect.grow(-1); + _gfx->TextBox(text, 0, rect, mode, fontId); + if (style & 8) { // selected + _gfx->FrameRect(rect); + } + _screen->UpdateWhole(); +} + +void SciGUI::graphFillBoxForeground(Common::Rect rect) { + _gfx->PaintRect(rect); + _screen->UpdateWhole(); +} + +void SciGUI::graphFillBoxBackground(Common::Rect rect) { + _gfx->EraseRect(rect); + _screen->UpdateWhole(); +} + +void SciGUI::graphFillBox(Common::Rect rect, uint16 colorMask, int16 color, int16 priority, int16 control) { + _gfx->FillRect(rect, colorMask, color, priority, control); + _screen->UpdateWhole(); +} + +void SciGUI::graphDrawLine(Common::Rect rect, int16 color, int16 priority, int16 control) { + _gfx->Draw_Line(rect.left, rect.top, rect.right, rect.bottom, color, priority, control); + _screen->UpdateWhole(); +} + +reg_t SciGUI::graphSaveBox(Common::Rect rect, uint16 flags) { + return _gfx->SaveBits(rect, flags); +} + +void SciGUI::graphRestoreBox(reg_t handle) { + _gfx->RestoreBits(handle); + _screen->UpdateWhole(); +} + +void SciGUI::paletteSet(int resourceNo, int flags) { + _gfx->SetResPalette(resourceNo, flags); +} + +int16 SciGUI::paletteFind(int r, int g, int b) { + return _gfx->MatchColor(&_gfx->_sysPalette, r, g, b) & 0xFF; +} + +void SciGUI::paletteAnimate(int fromColor, int toColor, int speed) { + _gfx->animatePalette(fromColor, toColor, speed); +} + +void SciGUI::moveCursor(int16 x, int16 y) { + Common::Point newPos; + sciPort *curPort = _gfx->GetPort(); + + x += _windowMgr->_picWind->rect.left; + y += _windowMgr->_picWind->rect.top; + newPos.x = CLIP<int16> (x, _windowMgr->_picWind->rect.left, _windowMgr->_picWind->rect.right - 1); + newPos.y = CLIP<int16> (y, _windowMgr->_picWind->rect.top, _windowMgr->_picWind->rect.bottom - 1); + + gfxop_set_pointer_position(_s->gfx_state, newPos); +} + +} // End of namespace Sci diff --git a/engines/sci/gui/gui.h b/engines/sci/gui/gui.h new file mode 100644 index 0000000000..35165be377 --- /dev/null +++ b/engines/sci/gui/gui.h @@ -0,0 +1,86 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/gui/gui_helpers.h" + +namespace Sci { + +class SciGUIscreen; +class SciGUIgfx; +class SciGUIresources; +class SciGUIwindowMgr; +class SciGUI { +public: + SciGUI(OSystem *system, EngineState *s); + SciGUI(); + ~SciGUI(); + + virtual void init(bool oldGfxFunctions); + + virtual int16 getTimeTicks(); + virtual void wait(int16 ticks); + virtual void setPort(uint16 portPtr); + virtual void setPortPic(Common::Rect rect, int16 picTop, int16 picLeft); + virtual reg_t getPort(); + virtual void globalToLocal(int16 *x, int16 *y); + virtual void localToGlobal(int16 *x, int16 *y); + virtual reg_t newWindow(Common::Rect rect1, Common::Rect rect2, uint16 style, int16 priority, int16 colorPen, int16 colorBack, const char *title); + virtual void disposeWindow(uint16 windowPtr, int16 arg2); + + virtual void display(const char *text, int argc, reg_t *argv); + + virtual void textSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); + virtual void textFonts(int argc, reg_t *argv); + virtual void textColors(int argc, reg_t *argv); + + virtual void drawPicture(sciResourceId pictureId, uint16 showStyle, uint16 flags, int16 EGApaletteNo); + virtual void drawCell(sciResourceId viewId, uint16 loopNo, uint16 cellNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo); + virtual void drawControlButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool inverse); + virtual void drawControlText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, bool inverse); + + virtual void graphFillBoxForeground(Common::Rect rect); + virtual void graphFillBoxBackground(Common::Rect rect); + virtual void graphFillBox(Common::Rect rect, uint16 colorMask, int16 color, int16 priority, int16 control); + virtual void graphDrawLine(Common::Rect rect, int16 color, int16 priority, int16 control); + virtual reg_t graphSaveBox(Common::Rect rect, uint16 flags); + virtual void graphRestoreBox(reg_t handle); + + virtual void paletteSet(int resourceNo, int flags); + virtual int16 paletteFind(int r, int g, int b); + virtual void paletteAnimate(int fromColor, int toColor, int speed); + + virtual void moveCursor(int16 x, int16 y); + +private: + OSystem *_system; + EngineState *_s; + SciGUIscreen *_screen; + SciGUIgfx *_gfx; + SciGUIresources *_resources; + SciGUIwindowMgr *_windowMgr; + bool _usesOldGfxFunctions; +}; + +} // End of namespace Sci diff --git a/engines/sci/gui/gui_dbllist.cpp b/engines/sci/gui/gui_dbllist.cpp new file mode 100644 index 0000000000..c44130802e --- /dev/null +++ b/engines/sci/gui/gui_dbllist.cpp @@ -0,0 +1,257 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" + +#include "sci/sci.h" +#include "sci/gui/gui_helpers.h" +#include "sci/gui/gui_memmgr.h" +#include "sci/gui/gui_dbllist.h" + +namespace Sci { + +DblList::DblList() { + _hFirst = 0; + _hLast = 0; +} + +DblList::DblList(HEAPHANDLE heap) { + byte *ptr = heap2Ptr(heap); + _hFirst = READ_UINT16(ptr); + _hLast = READ_UINT16(ptr + 2); +} + +DblList::~DblList(void) { +} +//-------------------------------------- +// Prints all list contents +void DblList::Dump(char*caption) { + debug("DumpList %s:", caption); + debug(" First: %04X Last: %04X", _hFirst, _hLast); + HEAPHANDLE node = _hFirst; + while (node) { + sciNode *pNode = (sciNode *)heap2Ptr(node); + debug(" %04X key=%04X prev=%04X next=%04X add.data=%db", node, + pNode->key, pNode->prev, pNode->next, heapGetDataSize(node) - 6); + node = pNode->next; + } + debug("End of list"); +} +//-------------------------------------- +// Add a new node to front of the list +HEAPHANDLE DblList::AddToFront(HEAPHANDLE node, uint16 key) { + if (!node) { + warning("Bad node handler (%04X) passed to DblList::AddToFront !", + node); + return node; + } + sciNode *pNode = (sciNode *)heap2Ptr(node); + pNode->key = key; + if (_hFirst) { // we already have a 1st node + sciNode *pnext = (sciNode *)heap2Ptr(_hFirst); + pnext->prev = node; + pNode->next = _hFirst; + } else { // list is empty, to passed node becames 1st one + _hLast = node; + pNode->next = 0; + } + _hFirst = node; + pNode->prev = 0; + return node; +} + +//------------------------------------- +// +HEAPHANDLE DblList::AddToEnd(HEAPHANDLE node, uint16 key) { + if (!node) { + warning("Bad node handler (%04X) passed to DblList::AddToEnd !", node); + return node; + } + sciNode *pNode = (sciNode *)heap2Ptr(node); + if (_hFirst) { // list is not empty + sciNode *plast = (sciNode *)heap2Ptr(_hLast); + plast->next = node; + pNode->prev = _hLast; + } else { // list is empty, so the node becames 1st one + _hFirst = node; + pNode->prev = 0; + } + _hLast = node; + pNode->next = 0; + pNode->key = key; + + return node; +} + +//------------------------------------------------ +// returns node that contains the key +HEAPHANDLE DblList::FindKey(uint16 key) { + HEAPHANDLE node = _hFirst; + while (node) { + sciNode *pNode = (sciNode *)heap2Ptr(node); + if (pNode->key == key) + break; + node = pNode->next; + } + return node; +} +//------------------------------------------------ +// detaches node with specified key and returning the node +HEAPHANDLE DblList::DeleteKey(uint16 key) { + HEAPHANDLE node = FindKey(key); + if (node) + DeleteNode(node); + return node; +} +//------------------------------------------------ +// detaches specified node from list +byte DblList::DeleteNode(HEAPHANDLE node) { + if (!node) { + warning("Bad node handler (%04X) passed to DblList::AddToEnd !", node); + return node; + } + // updating the links + sciNode *pNode = (sciNode *)heap2Ptr(node); + if (pNode->prev) { + sciNode *pprev = (sciNode *)heap2Ptr(pNode->prev); + pprev->next = pNode->next; + } + if (pNode->next) { + sciNode *pnext = (sciNode *)heap2Ptr(pNode->next); + pnext->prev = pNode->prev; + } + // updating list head if needed + if (_hFirst == node) + _hFirst = pNode->next; + if (_hLast == node) + _hLast = pNode->prev; + pNode->prev = 0; + pNode->next = 0; + return 1; +} +//------------------------------------------------ +// Moves node to the end of the list +HEAPHANDLE DblList::MoveToEnd(HEAPHANDLE node) { + if (!node) { + warning("Bad node handler (%04X) passed to DblList::MoveToEnd !", node); + return node; + } + sciNode *pNode = (sciNode *)heap2Ptr(node); + if (pNode->next) { // node is not the last one in list + DeleteNode(node); + AddToEnd(node, pNode->key); + } + return node; +} +//------------------------------------------------ +// Moves node to the front of the list +HEAPHANDLE DblList::MoveToFront(HEAPHANDLE node) { + if (!node) { + warning("Bad node handler (%04X) passed to DblList::MoveToFront !", + node); + return node; + } + sciNode *pNode = (sciNode *)heap2Ptr(node); + if (pNode->prev) { // node is not 1st one in list + DeleteNode(node); + AddToFront(node, pNode->key); + } + return node; +} +//------------------------------------------------ +HEAPHANDLE DblList::AddAfter(HEAPHANDLE ref, HEAPHANDLE node, uint16 key) { + if (!node) { + warning("Bad node handler (%04X) passed to DblList::AddAfter !", node); + return node; + } + sciNode *pNode = (sciNode *)heap2Ptr(node); + sciNode *pref = (sciNode *)heap2Ptr(ref); + pNode->key = key; + if (pref->next == 0) { // ref node is the last one + pNode->next = 0; + _hLast = node; + } else { + sciNode *pnext = (sciNode *)heap2Ptr(pref->next); + pNode->next = pref->next; + pnext->prev = node; + } + pref->next = node; + pNode->prev = ref; + return node; +} +//------------------------------------------------ +// +HEAPHANDLE DblList::AddBefore(HEAPHANDLE ref, HEAPHANDLE node, uint16 key) { + if (!node) { + warning("Bad node handler (%04X) passed to DblList::AddBefore !", node); + return node; + } + sciNode *pNode = (sciNode *)heap2Ptr(node); + sciNode *pref = (sciNode *)heap2Ptr(ref); + pNode->key = key; + if (pref->prev == 0) { // ref node is the 1st one + pNode->prev = 0; + _hFirst = node; + } else { + sciNode*pprev = (sciNode *)heap2Ptr(pref->prev); + pNode->prev = pref->prev; + pprev->next = node; + } + pref->prev = node; + pNode->next = ref; + return node; +} +//------------------------------------------------ +void DblList::toHeap(HEAPHANDLE heap) { + byte *ptr = heap2Ptr(heap); + WRITE_UINT16(ptr, _hFirst); + WRITE_UINT16(ptr + 2, _hLast); +} +//------------------------------------------------ +void DblList::DeleteList() { + HEAPHANDLE node = getFirst(), next; + sciNode *pNode; + while (node) { + pNode = (sciNode *)heap2Ptr(node); + next = pNode->next; + heapDisposePtr(node); + node = next; + } + _hFirst = _hLast = 0; +} +//------------------------------------------------ +uint16 DblList::getSize() { + uint16 cnt = 0; + HEAPHANDLE node = getFirst(); + sciNode *pNode; + while (node) { + pNode = (sciNode *)heap2Ptr(node); + node = pNode->next; + cnt++; + } + return cnt; +} +//------------------------------------------------ +} // end of namespace diff --git a/engines/sci/gui/gui_dbllist.h b/engines/sci/gui/gui_dbllist.h new file mode 100644 index 0000000000..fe3cd36f7b --- /dev/null +++ b/engines/sci/gui/gui_dbllist.h @@ -0,0 +1,74 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + Each node contains handles to next and previous node and an optional key for searching + Head node contains handles to first and last node + */ + +namespace Sci { + +typedef uint16 HEAPHANDLE; + +class DblList { +public: + DblList(); + DblList(HEAPHANDLE heap); + ~DblList(void); +protected: + HEAPHANDLE _hFirst, _hLast; +public: + // Add a new node to front of the list + HEAPHANDLE AddToFront(HEAPHANDLE node, uint16 key = 0); + HEAPHANDLE AddToEnd(HEAPHANDLE node, uint16 key = 0); + HEAPHANDLE MoveToEnd(HEAPHANDLE node); + HEAPHANDLE MoveToFront(HEAPHANDLE node); + HEAPHANDLE AddAfter(HEAPHANDLE ref, HEAPHANDLE node, uint16 key = 0); + HEAPHANDLE AddBefore(HEAPHANDLE ref, HEAPHANDLE node, uint16 key = 0); + + HEAPHANDLE FindKey(uint16 key); + HEAPHANDLE DeleteKey(uint16 key); + byte DeleteNode(HEAPHANDLE node); + void DeleteList(); + void Dump(char*caption = ""); // for debug + HEAPHANDLE getFirst() { + return _hFirst; + } + HEAPHANDLE getLast() { + return _hLast; + } + void toHeap(HEAPHANDLE heap); + bool isEmpty() { + return (_hFirst == 0 && _hLast == 0); + } + uint16 getSize(); + void set(HEAPHANDLE first, HEAPHANDLE last){ + _hFirst = first; + _hLast = last; + } + +}; + +} // end of namespace diff --git a/engines/sci/gui/gui_font.cpp b/engines/sci/gui/gui_font.cpp new file mode 100644 index 0000000000..c27ae35930 --- /dev/null +++ b/engines/sci/gui/gui_font.cpp @@ -0,0 +1,100 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/gui/gui_screen.h" +#include "sci/gui/gui_font.h" + +namespace Sci { + +SciGUIfont::SciGUIfont(OSystem *system, EngineState *state, SciGUIscreen *screen, sciResourceId resourceId) + : _system(system), _s(state), _screen(screen), _resourceId(resourceId) { + assert(resourceId != -1); + initData(resourceId); +} + +SciGUIfont::~SciGUIfont() { +} + +void SciGUIfont::initData(sciResourceId resourceId) { + Resource *fontResource = _s->resMan->findResource(ResourceId(kResourceTypeFont, resourceId), false); + if (!fontResource) { + error("font resource %d not found", resourceId); + } + _resourceData = fontResource->data; + + mCharMax = READ_LE_UINT16(_resourceData + 2); + mFontH = READ_LE_UINT16(_resourceData + 4); + mChars = new charinfo[mCharMax]; + // filling info for every char + for (int16 i = 0; i < mCharMax; i++) { + mChars[i].offset = READ_LE_UINT16(_resourceData + 6 + i * 2); + mChars[i].w = _resourceData[mChars[i].offset]; + mChars[i].h = _resourceData[mChars[i].offset + 1]; + } +} + +sciResourceId SciGUIfont::getResourceId() { + return _resourceId; +} + +byte SciGUIfont::getHeight() { + return mFontH; +} +byte SciGUIfont::getCharWidth(byte chr) { + return chr < mCharMax ? mChars[chr].w : 0; +} +byte SciGUIfont::getCharHeight(byte chr) { + return chr < mCharMax ? mChars[chr].h : 0; +} +byte *SciGUIfont::getCharData(byte chr) { + return chr < mCharMax ? _resourceData + mChars[chr].offset + 2 : 0; +} + +void SciGUIfont::draw(int16 chr, int16 top, int16 left, byte color, byte textface) { + int charWidth = MIN<int>(getCharWidth(chr), _screen->_width - left); + int charHeight = MIN<int>(getCharHeight(chr), 200 - top); + byte b = 0, mask = 0xFF; + int pitch = _screen->_width; + int y = top; + + byte *pIn = getCharData(chr); + for (int i = 0; i < charHeight; i++, y++) { + if (textface & 1) // "grayed" output + mask = top++ % 2 ? 0xAA : 0x55; + for (int done = 0; done < charWidth; done++) { + if ((done & 7) == 0) // fetching next data byte + b = *(pIn++) & mask; + if (b & 0x80) // if MSB is set - paint it + _screen->Put_Pixel(left + done, y, 1, color, 0, 0); + b = b << 1; + } + } + +} + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_font.h b/engines/sci/gui/gui_font.h new file mode 100644 index 0000000000..437a572b43 --- /dev/null +++ b/engines/sci/gui/gui_font.h @@ -0,0 +1,59 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +namespace Sci { + +class SciGUIfont { +public: + SciGUIfont(OSystem *system, EngineState *state, SciGUIscreen *screen, sciResourceId resourceId); + ~SciGUIfont(); + + sciResourceId getResourceId(); + byte getHeight(); + byte getCharWidth(byte chr); + byte getCharHeight(byte chr); + byte *getCharData(byte chr); + void draw(int16 chr, int16 top, int16 left, byte color, byte textface); + +private: + void initData(sciResourceId resourceId); + + OSystem *_system; + EngineState *_s; + SciGUIscreen *_screen; + + sciResourceId _resourceId; + byte *_resourceData; + + struct charinfo { + byte w, h; + int16 offset; + }; + byte mFontH; + uint16 mCharMax; + charinfo* mChars; +}; + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_gfx.cpp b/engines/sci/gui/gui_gfx.cpp new file mode 100644 index 0000000000..56ce2ecfa1 --- /dev/null +++ b/engines/sci/gui/gui_gfx.cpp @@ -0,0 +1,1194 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/timer.h" +#include "common/util.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/gui/gui_font.h" +#include "sci/gui/gui_picture.h" +#include "sci/gui/gui_view.h" +#include "sci/gui/gui_screen.h" +#include "sci/gui/gui_gfx.h" + +namespace Sci { + +static uint32 _sysTicks; + +SciGUIgfx::SciGUIgfx(OSystem *system, EngineState *state, SciGUIscreen *screen) + : _system(system), _s(state), _screen(screen) { + init(); + initPalette(); + initTimer(); +} + +SciGUIgfx::~SciGUIgfx() { + _system->getTimerManager()->removeTimerProc(&timerHandler); +} + +void SciGUIgfx::init() { + uint16 a = 0; + + _font = NULL; + + _mainPort = mallocPort(); + SetPort(_mainPort); + OpenPort(_mainPort); + + _menuPort = mallocPort(); + OpenPort(_menuPort); + SetFont(0); + _menuPort->rect = Common::Rect(0, 0, _screen->_width, _screen->_height); + +// HEAPHANDLE theMenuBarH = heapNewPtr(34, kDataPort, "MenuBar"); +// heapClearPtr(theMenuBarH); +// _theMenuBar = (Common::Rect *)heap2Ptr(theMenuBarH); +// *_theMenuBar = Common::Rect(_gfx->RGetPort()->rect.right, 10); + + _sysTicks = 0; +} + +void SciGUIgfx::initPalette() { + int16 i; + for (i = 0; i < 256; i++) { + _sysPalette.colors[i].used = 0; + _sysPalette.colors[i].r = 0; + _sysPalette.colors[i].g = 0; + _sysPalette.colors[i].b = 0; + _sysPalette.intencity[i] = 100; + _sysPalette.mapping[i] = i; + } + _sysPalette.colors[0].used = 1; + _sysPalette.colors[255].used = 1; + _sysPalette.colors[255].r = 255; + _sysPalette.colors[255].g = 255; + _sysPalette.colors[255].b = 255; + //if (g_sci->getPlatform() == Common::kPlatformAmiga) + // setAmigaPalette(); + //else + + // Load default palette from resource 999 + if (!SetResPalette(999, 2)) { + // if not found, we set EGA palette + SetEGApalette(); + }; + + // Init _clrPowers used in MatchColor + for(int16 i = 0; i < 256; i++) + _clrPowers[i] = i*i; +} + +void SciGUIgfx::initTimer() { + _sysSpeed = 1000000 / 60; + Common::TimerManager *tm = _system->getTimerManager(); + tm->removeTimerProc(&timerHandler); + tm->installTimerProc(&timerHandler, _sysSpeed, this); +} + +void SciGUIgfx::timerHandler(void *ref) { + ((SciGUIgfx *)ref)->_sysTicks++; +} + +sciPort *SciGUIgfx::mallocPort () { + sciPort *newPort = (sciPort *)malloc(sizeof(sciPort)); + assert(newPort); + memset(newPort, 0, sizeof(sciPort)); + return newPort; +} + +#define SCI_PAL_FORMAT_CONSTANT 1 +#define SCI_PAL_FORMAT_VARIABLE 0 + +void SciGUIgfx::SetEGApalette() { + int i; + _sysPalette.colors[1].r = 0x000; _sysPalette.colors[1].g = 0x000; _sysPalette.colors[1].b = 0x0AA; + _sysPalette.colors[2].r = 0x000; _sysPalette.colors[2].g = 0x0AA; _sysPalette.colors[2].b = 0x000; + _sysPalette.colors[3].r = 0x000; _sysPalette.colors[3].g = 0x0AA; _sysPalette.colors[3].b = 0x0AA; + _sysPalette.colors[4].r = 0x0AA; _sysPalette.colors[4].g = 0x000; _sysPalette.colors[4].b = 0x000; + _sysPalette.colors[5].r = 0x0AA; _sysPalette.colors[5].g = 0x000; _sysPalette.colors[5].b = 0x0AA; + _sysPalette.colors[6].r = 0x0AA; _sysPalette.colors[6].g = 0x055; _sysPalette.colors[6].b = 0x000; + _sysPalette.colors[7].r = 0x0AA; _sysPalette.colors[7].g = 0x0AA; _sysPalette.colors[7].b = 0x0AA; + _sysPalette.colors[8].r = 0x055; _sysPalette.colors[8].g = 0x055; _sysPalette.colors[8].b = 0x055; + _sysPalette.colors[9].r = 0x055; _sysPalette.colors[9].g = 0x055; _sysPalette.colors[9].b = 0x0FF; + _sysPalette.colors[10].r = 0x055; _sysPalette.colors[10].g = 0x0FF; _sysPalette.colors[10].b = 0x055; + _sysPalette.colors[11].r = 0x055; _sysPalette.colors[11].g = 0x0FF; _sysPalette.colors[11].b = 0x0FF; + _sysPalette.colors[12].r = 0x0FF; _sysPalette.colors[12].g = 0x055; _sysPalette.colors[12].b = 0x055; + _sysPalette.colors[13].r = 0x0FF; _sysPalette.colors[13].g = 0x055; _sysPalette.colors[13].b = 0x0FF; + _sysPalette.colors[14].r = 0x0FF; _sysPalette.colors[14].g = 0x0FF; _sysPalette.colors[14].b = 0x055; + _sysPalette.colors[15].r = 0x0FF; _sysPalette.colors[15].g = 0x0FF; _sysPalette.colors[15].b = 0x0FF; + for (i = 0; i <= 15; i++) { + _sysPalette.colors[i].used = 1; + } + for (i = 16; i <= 254; i++) { + _sysPalette.colors[i].r = 200; + _sysPalette.colors[i].used = 1; + } + SetCLUT(&_sysPalette); +} + +void SciGUIgfx::CreatePaletteFromData(byte *data, sciPalette *paletteOut) { + int palFormat = 0; + int palOffset = 0; + int palColorStart = 0; + int palColorCount = 0; + int colorNo = 0; + + memset(paletteOut, 0, sizeof(sciPalette)); + if (data[0] == 0 && data[1] == 1) { + // SCI0/SCI1 palette + palFormat = SCI_PAL_FORMAT_VARIABLE; // CONSTANT; + palOffset = 260; + palColorStart = 0; palColorCount = 256; + } else { + // SCI1.1 palette + palFormat = data[32]; + palOffset = 37; + palColorStart = READ_LE_UINT16(data + 25); palColorCount = READ_LE_UINT16(data + 29); + } + switch (palFormat) { + case SCI_PAL_FORMAT_CONSTANT: + for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + paletteOut->colors[colorNo].used = 1; + paletteOut->colors[colorNo].r = data[palOffset++]; + paletteOut->colors[colorNo].g = data[palOffset++]; + paletteOut->colors[colorNo].b = data[palOffset++]; + } + break; + case SCI_PAL_FORMAT_VARIABLE: + for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + paletteOut->colors[colorNo].used = data[palOffset++]; + paletteOut->colors[colorNo].r = data[palOffset++]; + paletteOut->colors[colorNo].g = data[palOffset++]; + paletteOut->colors[colorNo].b = data[palOffset++]; + } + break; + } +} + +bool SciGUIgfx::SetResPalette(int16 resourceNo, int16 flag) { + Resource *palResource = _s->resMan->findResource(ResourceId(kResourceTypePalette, resourceNo), 0); + int palFormat = 0; + int palOffset = 0; + int palColorStart = 0; + int palColorCount = 0; + int colorNo = 0; + sciPalette palette = {0}; + + if (palResource) { + CreatePaletteFromData(palResource->data, &palette); + SetPalette(&palette, 2); + return true; + } + return false; +} + +void SciGUIgfx::SetPalette(sciPalette *sciPal, int16 flag) { + uint32 systime = _sysPalette.timestamp; + if (flag == 2 || sciPal->timestamp != systime) { + MergePalettes(sciPal, &_sysPalette, flag); + sciPal->timestamp = _sysPalette.timestamp; + if (_s->pic_not_valid == 0 && systime != _sysPalette.timestamp) + SetCLUT(&_sysPalette); + } +} + +void SciGUIgfx::MergePalettes(sciPalette *pFrom, sciPalette *pTo, uint16 flag) { + uint16 res; + int i,j; + // colors 0 (black) and 255 (white) are not affected by merging + for (i = 1 ; i < 255; i++) { + if (!pFrom->colors[i].used)// color is not used - so skip it + continue; + // forced palette merging or dest color is not used yet + if (flag == 2 || (!pTo->colors[i].used)) { + pTo->colors[i].used = pFrom->colors[i].used; + pTo->colors[i].r = pFrom->colors[i].r; + pTo->colors[i].g = pFrom->colors[i].g; + pTo->colors[i].b = pFrom->colors[i].b; + pFrom->mapping[i] = i; + continue; + } + // check if exact color could be matched + res = MatchColor(pTo, pFrom->colors[i].r, pFrom->colors[i].g, pFrom->colors[i].b); + if (res & 0x8000) { // exact match was found + pFrom->mapping[i] = res & 0xFF; + continue; + } + // no exact match - see if there is an unused color + for (j = 1; j < 256; j++) + if (!pTo->colors[j].used) { + pTo->colors[j].used = pFrom->colors[i].used; + pTo->colors[j].r = pFrom->colors[i].r; + pTo->colors[j].g = pFrom->colors[i].g; + pTo->colors[j].b = pFrom->colors[i].b; + pFrom->mapping[i] = j; + break; + } + // if still no luck - set an approximate color + if (j == 256) { + pFrom->mapping[i] = res & 0xFF; + pTo->colors[res & 0xFF].used |= 0x10; + } + } + pTo->timestamp = _sysTicks; +} + +uint16 SciGUIgfx::MatchColor(sciPalette*pPal, byte r, byte g, byte b) { + byte found = 0xFF; + int diff = 0x2FFFF, cdiff; + int16 dr,dg,db; + + for (int i = 0; i < 256; i++) { + if ((!pPal->colors[i].used)) + continue; + dr = pPal->colors[i].r - r; + dg = pPal->colors[i].g - g; + db = pPal->colors[i].b - b; +// minimum squares match + cdiff = _clrPowers[ABS(dr)] + _clrPowers[ABS(dg)] + _clrPowers[ABS(db)]; +// minimum sum match (Sierra's) +// cdiff = ABS(dr) + ABS(dg) + ABS(db); + if (cdiff < diff) { + if (cdiff == 0) + return i | 0x8000; // setting this flag to indicate exact match + found = i; + diff = cdiff; + } + } + return found; +} + +void SciGUIgfx::SetCLUT(sciPalette*pal) { + if (pal != &_sysPalette) + memcpy(&_sysPalette,pal,sizeof(sciPalette)); + // just copy palette to system + byte bpal[4 * 256]; + // Get current palette, update it and put back + _system->grabPalette(bpal, 0, 256); + for (int16 i = 0; i < 256; i++) { + if (!pal->colors[i].used) + continue; + bpal[i * 4] = pal->colors[i].r * pal->intencity[i] / 100; + bpal[i * 4 + 1] = pal->colors[i].g * pal->intencity[i] / 100; + bpal[i * 4 + 2] = pal->colors[i].b * pal->intencity[i] / 100; + bpal[i * 4 + 3] = 100; + } + _system->setPalette(bpal, 0, 256); + _system->updateScreen(); +} + +void SciGUIgfx::GetCLUT(sciPalette*pal) { + if (pal != &_sysPalette) + memcpy(pal,&_sysPalette,sizeof(sciPalette)); +} + +sciPort *SciGUIgfx::SetPort(sciPort *newPort) { + sciPort *oldPort = _curPort; + _curPort = newPort; + return oldPort; +} + +sciPort *SciGUIgfx::GetPort(void) { + return _curPort; +} + +void SciGUIgfx::SetOrigin(int16 left, int16 top) { + _curPort->left = left; + _curPort->top = top; +} + +void SciGUIgfx::MoveTo(int16 left, int16 top) { + _curPort->curTop = top; + _curPort->curLeft = left; +} + +void SciGUIgfx::Move(int16 left, int16 top) { + _curPort->curTop += top; + _curPort->curLeft += left; +} + +int16 SciGUIgfx::GetFontId() { + return _curPort->fontId; +} + +SciGUIfont *SciGUIgfx::GetFont() { + if ((_font == NULL) || (_font->getResourceId() != _curPort->fontId)) { + _font = new SciGUIfont(_system, _s, _screen, _curPort->fontId); + } + return _font; +} + +void SciGUIgfx::SetFont(int16 fontId) { + if ((_font == NULL) || (_font->getResourceId() != fontId)) { + _font = new SciGUIfont(_system, _s, _screen, fontId); + } + _curPort->fontId = fontId; + _curPort->fontH = _font->getHeight(); +} + +void SciGUIgfx::OpenPort(sciPort *port) { + port->fontId = 0; + port->fontH = 8; + + sciPort *tmp = _curPort; + _curPort = port; + SetFont(port->fontId); + _curPort = tmp; + + port->top = 0; + port->left = 0; + port->textFace = 0; + port->penClr = 0; + port->backClr = 0xFF; + port->penMode = 0; + memcpy(&port->rect, &_bounds, sizeof(_bounds)); +} + +void SciGUIgfx::PenColor(int16 color) { + _curPort->penClr = color; +} + +void SciGUIgfx::PenMode(int16 mode) { + _curPort->penMode = mode; +} + +void SciGUIgfx::TextFace(int16 textFace) { + _curPort->textFace = textFace; +} + +int16 SciGUIgfx::GetPointSize(void) { + return _curPort->fontH; +} + +void SciGUIgfx::ClearScreen(byte color) { + FillRect(_curPort->rect, SCI_SCREEN_MASK_ALL, color, 0, 0); +} + +void SciGUIgfx::InvertRect(const Common::Rect &rect) { + int16 oldpenmode = _curPort->penMode; + _curPort->penMode = 2; + FillRect(rect, 1, _curPort->penClr, _curPort->backClr); + _curPort->penMode = oldpenmode; +} +//----------------------------- +void SciGUIgfx::EraseRect(const Common::Rect &rect) { + FillRect(rect, 1, _curPort->backClr); +} +//----------------------------- +void SciGUIgfx::PaintRect(const Common::Rect &rect) { + FillRect(rect, 1, _curPort->penClr); +} + +void SciGUIgfx::FillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack, byte bControl) { + Common::Rect r(rect.left, rect.top, rect.right, rect.bottom); + r.clip(_curPort->rect); + if (r.isEmpty()) // nothing to fill + return; + + int16 oldPenMode = _curPort->penMode; + OffsetRect(r); + int16 w = r.width(); + int16 h = r.height(); + int16 x, y; + byte curVisual; + + // Doing visual first + if (drawFlags & SCI_SCREEN_MASK_VISUAL) { + if (oldPenMode == 2) { // invert mode + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + curVisual = _screen->Get_Visual(x, y); + if (curVisual == clrPen) { + _screen->Put_Pixel(x, y, 1, clrBack, 0, 0); + } else if (curVisual == clrBack) { + _screen->Put_Pixel(x, y, 1, clrPen, 0, 0); + } + } + } + } else { // just fill rect with ClrPen + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->Put_Pixel(x, y, 1, clrPen, 0, 0); + } + } + } + } + + if (drawFlags < 2) + return; + drawFlags &= SCI_SCREEN_MASK_PRIORITY|SCI_SCREEN_MASK_CONTROL; + + if (oldPenMode != 2) { + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->Put_Pixel(x, y, drawFlags, 0, clrBack, bControl); + } + } + } else { + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->Put_Pixel(x, y, drawFlags, 0, !_screen->Get_Priority(x, y), !_screen->Get_Control(x, y)); + } + } + } +} + +void SciGUIgfx::FrameRect(const Common::Rect &rect) { + Common::Rect r; + // left + r = rect; + r.right = rect.left + 1; + PaintRect(r); + // right + r.right = rect.right; + r.left = rect.right - 1; + PaintRect(r); + //top + r.left = rect.left; + r.bottom = rect.top + 1; + PaintRect(r); + //bottom + r.bottom = rect.bottom; + r.top = rect.bottom - 1; + PaintRect(r); +} + +void SciGUIgfx::OffsetRect(Common::Rect &r) { + r.top += _curPort->top; + r.bottom += _curPort->top; + r.left += _curPort->left; + r.right += _curPort->left; +} + +byte SciGUIgfx::CharHeight(int16 ch) { +#if 0 + CResFont *res = getResFont(); + return res ? res->getCharH(ch) : 0; +#endif + return 0; +} +//----------------------------- +byte SciGUIgfx::CharWidth(int16 ch) { + SciGUIfont *font = GetFont(); + return font ? font->getCharWidth(ch) : 0; +} +//----------------------------- +int16 SciGUIgfx::TextWidth(const char *text, int16 from, int16 len) { + SciGUIfont *font = GetFont(); + if (font) { + int16 width = 0; + for (int i = from; i < len; i++) + width += _font->getCharWidth(text[i]); + return width; + } + return 0; +} +//----------------------------- +void SciGUIgfx::ClearChar(int16 chr) { + if (_curPort->penMode != 1) + return; + Common::Rect rect; + rect.top = _curPort->curTop; + rect.bottom = rect.top + _curPort->fontH; + rect.left = _curPort->curLeft; + rect.right = rect.left + CharWidth(chr); + EraseRect(rect); +} +//----------------------------- +void SciGUIgfx::DrawChar(int16 chr) { + chr = chr & 0xFF; + ClearChar(chr); + StdChar(chr); + _curPort->curLeft += CharWidth(chr); +} +//----------------------------- +void SciGUIgfx::StdChar(int16 chr) { +#if 0 + CResFont*res = getResFont(); + if (res) + res->Draw(chr, _curPort->top + _curPort->curTop, _curPort->left + + _curPort->curLeft, _vSeg, 320, _curPort->penClr, + _curPort->textFace); +#endif +} + +SCILanguage SciGUIgfx::getSCILanguage() { + return kLangEnglish; +} + +char *SciGUIgfx::StrSplit(char *buff, const char *msg, const char *fmt) { + SCILanguage gameLang = getSCILanguage(); + SCILanguage subtitleLang = kLangNone; + char *retval; +// if (_theGame.getHandle()) + //subtitleLang = (SCILanguage)_theGame.getProperty(0x58); // subtitleLang property + + if (buff == msg) { + char str[2000]; + getIntlString(str, msg, fmt, gameLang, subtitleLang); + retval = strcpy(buff, str); + } else + retval = getIntlString(buff, msg, fmt, gameLang, subtitleLang); + return retval; +} +//-------------------------------- +// In multilanguage game the msg has format ___english_text__#I___italian_text___ +// The function should place in buff a translated part of msg or the 1st one if a translation +// does not exist +char *SciGUIgfx::getIntlString(char *buff, const char *msg, const char *fmt, SCILanguage gameLang, SCILanguage subtitleLang) { + + // prefer subtitleLang if set + SCILanguage lang = subtitleLang != kLangNone ? subtitleLang : gameLang; + const char *ptr = msg, *szFrom; + char ch; + int nLen = 0; + // searching for language code in msg + while (*ptr) { + ch = *(ptr + 1); + if(*ptr == '#' && (ch == 'I' || ch == 'F' || ch == 'G' || ch == 'S')) { + ptr +=2; + break; + } + ptr++; + } + // if a language code was found... + if (*ptr) { + if ((lang == kLangItalian && ch == 'I') || (lang == kLangFrench && ch == 'F') || + (lang == kLangGerman && ch == 'G') || (lang == kLangSpanish && ch == 'S')) { + nLen = (int)strlen(ptr); + szFrom = ptr; + } else { + nLen = ptr - msg - 2; + szFrom = msg; + } + } else { + nLen = ptr - msg; + szFrom = msg; + } + if (fmt && subtitleLang != kLangNone) { + strcpy(buff, fmt); + strncat(buff, szFrom, nLen); + buff[nLen + strlen(fmt)] = 0; + } else { + strncpy(buff, szFrom, nLen); + buff[nLen] = 0; + } + return buff; +} + +// TODO: implement codes +int16 SciGUIgfx::TextSize(Common::Rect &rect, const char *str, int16 fontId, int16 maxwidth) { + char buff[1000] = { 0 }; + int16 oldfont = GetFontId(); + if (fontId != -1) + SetFont(fontId); + rect.top = rect.left = 0; + + if (maxwidth < 0) { // force output as single line + rect.bottom = GetPointSize(); + rect.right = StringWidth(str); + } else { + // rect.right=found widest line with RTextWidth and GetLongest + // rect.bottom=num. lines * GetPointSize + rect.right = (maxwidth ? maxwidth : 192); + int16 height = 0, maxWidth = 0, width, nc; + const char*p = str; + while (*p) { + if (*p == 0xD || *p == 0xA) { + p++; + continue; + } + nc = GetLongest(p, rect.right); + if (nc == 0) + break; + width = TextWidth(p, 0, nc); + maxWidth = MAX(width, maxWidth); + p += nc; + height++; + } + rect.bottom = height * GetPointSize(); + rect.right = maxwidth ? maxwidth : MIN(rect.right, maxWidth); + } + SetFont(oldfont); + return rect.right; +} + +// TODO: implement codes +// return max # of chars to fit maxwidth with full words +int16 SciGUIgfx::GetLongest(const char *str, int16 maxWidth) { + SciGUIfont *font = GetFont(); + if (!font) + return 0; + + int16 chars = 0, to = 0; + uint16 width = 0; + while (width <= maxWidth) { + switch (str[to]) { + case ' ': + chars = to + 1; + break; + case 0: + case 0xD: + case 0xA: + return to; + } + width += font->getCharWidth(str[to]); + to++; + } + return chars; +} + +// TODO: implement codes +void SciGUIgfx::DrawText(const char *text, int16 from, int16 len) { + int16 chr, width; + SciGUIfont *font = GetFont(); + Common::Rect rect; + + if (!font) + return; + + text += from; + rect.top = _curPort->curTop; + rect.bottom = rect.top + _curPort->fontH; + while (len--) { + chr = (*text++) & 0xFF; + width = font->getCharWidth(chr); + // clear char + if (_curPort->penMode == 1) { + rect.left = _curPort->curLeft; + rect.right = rect.left + width; + EraseRect(rect); + } + // CharStd + font->draw(chr, _curPort->top + _curPort->curTop, _curPort->left + _curPort->curLeft, _curPort->penClr, _curPort->textFace); + _curPort->curLeft += width; + } +} + +void SciGUIgfx::ShowText(const char *text, int16 from, int16 len) { + Common::Rect rect; + + rect.top = _curPort->curTop; + rect.bottom = rect.top + GetPointSize(); + rect.left = _curPort->curLeft; + DrawText(text, from, len); + rect.right = _curPort->curLeft; + ShowBits(rect, 1); +} + +// Draws a text in rect. +// align : -1-right , 0-left, 1-center +void SciGUIgfx::TextBox(const char *text, int16 bshow, const Common::Rect &rect, int16 align, int16 fontId) { + int16 w, nc, offset; + int16 hline = 0; + int16 oldfont = GetFontId(); + int16 rectWidth = rect.width(); + + if (fontId != -1) + SetFont(fontId); + + while (*text) { + if (*text == 0xD || *text == 0xA) { + text++; + continue; + } + nc = GetLongest(text, rect.width()); + if (nc == 0) + break; + w = TextWidth(text, 0, nc); + switch (align) { + case -1: + offset = rect.width() - w; + break; + case 1: + offset = (rect.width() - w) / 2; + break; + default: + offset = 0; + } + MoveTo(rect.left + offset, rect.top + hline); + + if (bshow) + ShowText(text, 0, nc); + else + DrawText(text, 0, nc); + hline += GetPointSize(); + text += nc; + } + SetFont(oldfont); +} + +// Update (part of) screen +void SciGUIgfx::ShowBits(const Common::Rect &r, uint16 flags) { + Common::Rect rect(r.left, r.top, r.right, r.bottom); + rect.clip(_curPort->rect); + if (rect.isEmpty()) // nothing to show + return; + + OffsetRect(rect); + uint16 w = rect.width(); + uint16 h = rect.height(); + assert((flags&0x8000) == 0); + _screen->UpdateWhole(); +// _system->copyRectToScreen(GetSegment(flags) + _baseTable[rect.top] + rect.left, 320, rect.left, rect.top, w, h); +// _system->updateScreen(); +} + +sciMemoryHandle SciGUIgfx::SaveBits(const Common::Rect &rect, byte screenMask) { + sciMemoryHandle memoryId; + byte *memoryPtr; + int size; + + Common::Rect r(rect.left, rect.top, rect.right, rect.bottom); + r.clip(_curPort->rect); + if (r.isEmpty()) // nothing to save + return NULL_REG; + + OffsetRect(r); //local port coords to screen coords + + // now actually ask _screen how much space it will need for saving + size = _screen->BitsGetDataSize(r, screenMask); + + memoryId = kalloc(_s->segMan, "SaveBits()", size); + memoryPtr = kmem(_s->segMan, memoryId); + _screen->BitsSave(r, screenMask, memoryPtr); + return memoryId; +} + +void SciGUIgfx::RestoreBits(sciMemoryHandle memoryHandle) { + byte *memoryPtr = kmem(_s->segMan, memoryHandle);; + + if (memoryPtr) { + _screen->BitsRestore(memoryPtr); + kfree(_s->segMan, memoryHandle); + } +} + +void SciGUIgfx::Draw_Line(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) { + //set_drawing_flag + byte flag = _screen->GetDrawingMask(color, prio, control); + prio &= 0xF0; + control &= 0x0F; + + // offseting the line + left += _curPort->left; + right += _curPort->left; + top += _curPort->top; + bottom += _curPort->top; + // horizontal line + if (top == bottom) { + Draw_Horiz(left, right, top, flag, color, prio, control); + return; + } + // vertical line + if (left == right) { + Draw_Vert(top, bottom, left, flag, color, prio, control); + return; + } + // sloped line - draw with Bresenham algorithm + int dy = bottom - top; + int dx = right - left; + int stepy = dy < 0 ? -1 : 1; + int stepx = dx < 0 ? -1 : 1; + dy = ABS(dy) << 1; + dx = ABS(dx) << 1; + + // setting the 1st and last pixel + _screen->Put_Pixel(left, top, flag, color, prio, control); + _screen->Put_Pixel(right, bottom, flag, color, prio, control); + // drawing the line + if (dx > dy) // going horizontal + { + int fraction = dy - (dx >> 1); + while (left != right) { + if (fraction >= 0) { + top += stepy; + fraction -= dx; + } + left += stepx; + fraction += dy; + _screen->Put_Pixel(left, top, flag, color, prio, control); + } + } else // going vertical + { + int fraction = dx - (dy >> 1); + while (top != bottom) { + if (fraction >= 0) { + left += stepx; + fraction -= dy; + } + top += stepy; + fraction += dx; + _screen->Put_Pixel(left, top, flag, color, prio, control); + } + } + //g_sci->eventMgr->waitUntil(5); + //ShowBits(&_rThePort->rect,6); +} + +void SciGUIgfx::Draw_Horiz(int16 left, int16 right, int16 top, byte flag, byte color, byte prio, byte control) { + if (right < left) + SWAP(right, left); + for (int i = left; i <= right; i++) + _screen->Put_Pixel(i, top, flag, color, prio, control); +} + +//-------------------------------- +void SciGUIgfx::Draw_Vert(int16 top, int16 bottom, int16 left, byte flag, byte color, byte prio, byte control) { + if (top > bottom) + SWAP(top, bottom); + for (int i = top; i <= bottom; i++) + _screen->Put_Pixel(left, i, flag, color, prio, control); +} + +// Bitmap for drawing sierra circles +const byte pattern_Circles[8][15] = { + { 0x01 }, + { 0x03, 0x03, 0x03 }, + { 0x02, 0x07, 0x07, 0x07, 0x02 }, + { 0x06, 0x06, 0x0F, 0x0F, 0x0F, 0x06, 0x06 }, + { 0x04, 0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x04 }, + { 0x0C, 0x1E, 0x1E, 0x1E, 0x3F, 0x3F, 0x3F, 0x1E, 0x1E, 0x1E, 0x0C }, + { 0x1C, 0x3E, 0x3E, 0x3E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E, 0x3E, 0x3E, 0x1C }, + { 0x18, 0x3C, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x3C, 0x18 } +}; + +const bool pattern_Textures[32 * 8 * 2] = { + false, false, false, false, false, true, false, false, // 0x20 + false, false, true, false, true, false, false, true, // 0x94 + false, true, false, false, false, false, false, false, // 0x02 + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, true, false, false, true, // 0x90 + false, true, false, false, false, false, false, true, // 0x82 + false, false, true, false, false, true, false, true, // 0xA4 + false, true, false, false, false, true, false, true, // 0xA2 + false, true, false, false, false, false, false, true, // 0x82 + true, false, false, true, false, false, false, false, // 0x09 + false, true, false, true, false, false, false, false, // 0x0A + false, true, false, false, false, true, false, false, // 0x22 + false, true, false, false, true, false, false, false, // 0x12 + false, false, false, false, true, false, false, false, // 0x10 + false, true, false, false, false, false, true, false, // 0x42 + false, false, true, false, true, false, false, false, // 0x14 + true, false, false, false, true, false, false, true, // 0x91 + false, true, false, true, false, false, true, false, // 0x4A + true, false, false, false, true, false, false, true, // 0x91 + true, false, false, false, true, false, false, false, // 0x11 + false, false, false, true, false, false, false, false, // 0x08 + false, true, false, false, true, false, false, false, // 0x12 + true, false, true, false, false, true, false, false, // 0x25 + false, false, false, false, true, false, false, false, // 0x10 + false, true, false, false, false, true, false, false, // 0x22 + false, false, false, true, false, true, false, true, // 0xA8 + false, false, true, false, true, false, false, false, // 0x14 + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, false, false, false, false, // 0x00 + false, false, false, false, true, false, true, false, // 0x50 + false, false, true, false, false, true, false, false, // 0x24 + false, false, true, false, false, false, false, // 0x04 (last bit is not mentioned cause original interpreter also ignores that bit) + // Now the table is actually duplicated, so we won't need to wrap around + false, false, false, false, false, true, false, false, // 0x20 + false, false, true, false, true, false, false, true, // 0x94 + false, true, false, false, false, false, false, false, // 0x02 + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, true, false, false, true, // 0x90 + false, true, false, false, false, false, false, true, // 0x82 + false, false, true, false, false, true, false, true, // 0xA4 + false, true, false, false, false, true, false, true, // 0xA2 + false, true, false, false, false, false, false, true, // 0x82 + true, false, false, true, false, false, false, false, // 0x09 + false, true, false, true, false, false, false, false, // 0x0A + false, true, false, false, false, true, false, false, // 0x22 + false, true, false, false, true, false, false, false, // 0x12 + false, false, false, false, true, false, false, false, // 0x10 + false, true, false, false, false, false, true, false, // 0x42 + false, false, true, false, true, false, false, false, // 0x14 + true, false, false, false, true, false, false, true, // 0x91 + false, true, false, true, false, false, true, false, // 0x4A + true, false, false, false, true, false, false, true, // 0x91 + true, false, false, false, true, false, false, false, // 0x11 + false, false, false, true, false, false, false, false, // 0x08 + false, true, false, false, true, false, false, false, // 0x12 + true, false, true, false, false, true, false, false, // 0x25 + false, false, false, false, true, false, false, false, // 0x10 + false, true, false, false, false, true, false, false, // 0x22 + false, false, false, true, false, true, false, true, // 0xA8 + false, false, true, false, true, false, false, false, // 0x14 + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, false, false, false, false, // 0x00 + false, false, false, false, true, false, true, false, // 0x50 + false, false, true, false, false, true, false, false, // 0x24 + false, false, true, false, false, false, false, // 0x04 (last bit is not mentioned cause original interpreter also ignores that bit) +}; + +// Bit offsets into pattern_textures +const byte pattern_TextureOffset[128] = { + 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, + 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, + 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, + 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, + 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, + 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, + 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, + 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 }; + +void SciGUIgfx::Draw_Box(Common::Rect box, byte color, byte prio, byte control) { + byte flag = _screen->GetDrawingMask(color, prio, control); + int y, x; + + for (y = box.top; y < box.bottom; y++) { + for (x = box.left; x < box.right; x++) { + _screen->Put_Pixel(x, y, flag, color, prio, control); + } + } +} + +void SciGUIgfx::Draw_TexturedBox(Common::Rect box, byte color, byte prio, byte control, byte texture) { + byte flag = _screen->GetDrawingMask(color, prio, control); + const bool *textureData = &pattern_Textures[pattern_TextureOffset[texture]]; + int y, x; + + for (y = box.top; y < box.bottom; y++) { + for (x = box.left; x < box.right; x++) { + if (*textureData) { + _screen->Put_Pixel(x, y, flag, color, prio, control); + } + textureData++; + } + } +} + +void SciGUIgfx::Draw_Circle(Common::Rect box, byte size, byte color, byte prio, byte control) { + byte flag = _screen->GetDrawingMask(color, prio, control); + byte *circle = (byte *)&pattern_Circles[size]; + byte circleBitmap; + int y, x; + + for (y = box.top; y < box.bottom; y++) { + circleBitmap = *circle; + for (x = box.left; x < box.right; x++) { + if (circleBitmap & 1) { + _screen->Put_Pixel(x, y, flag, color, prio, control); + } + circleBitmap = circleBitmap >> 1; + } + circle++; + } +} + +void SciGUIgfx::Draw_TexturedCircle(Common::Rect box, byte size, byte color, byte prio, byte control, byte texture) { + byte flag = _screen->GetDrawingMask(color, prio, control); + byte *circle = (byte *)&pattern_Circles[size]; + byte circleBitmap; + const bool *textureData = &pattern_Textures[pattern_TextureOffset[texture]]; + int y, x; + + for (y = box.top; y < box.bottom; y++) { + circleBitmap = *circle; + for (x = box.left; x < box.right; x++) { + if (circleBitmap & 1) { + if (*textureData) { + _screen->Put_Pixel(x, y, flag, color, prio, control); + } + textureData++; + } + circleBitmap = circleBitmap >> 1; + } + circle++; + } +} + +void SciGUIgfx::Draw_Pattern(int16 x, int16 y, byte color, byte priority, byte control, byte code, byte texture) { + byte size = code & SCI_PATTERN_CODE_PENSIZE; + Common::Rect rect; + + // We need to adjust the given coordinates, because the ones given us do not define upper left but somewhat middle + y -= size; + x -= (size + 1) >> 1; + + rect.top = y; rect.left = x; + rect.setHeight((size*2)+1); rect.setWidth(size+1); + + if (code & SCI_PATTERN_CODE_RECTANGLE) { + // Rectangle + if (code & SCI_PATTERN_CODE_USE_TEXTURE) { + Draw_TexturedBox(rect, color, priority, control, texture); + } else { + Draw_Box(rect, color, priority, control); + } + + } else { + // Circle + if (code & SCI_PATTERN_CODE_USE_TEXTURE) { + Draw_TexturedCircle(rect, size, color, priority, control, texture); + } else { + Draw_Circle(rect, size, color, priority, control); + } + } +} + +void SciGUIgfx::Pic_Fill(int16 x, int16 y, byte color, byte prio, byte control) { + Common::Stack<Common::Point> stack; + Common::Point p, p1; + + byte flag = _screen->GetDrawingMask(color, prio, control), fmatch; + p.x = x + _curPort->left; + p.y = y + _curPort->top; + stack.push(p); + + // parameters check + if ((flag & 2 && prio == 0) || (flag & 3 && control == 0)) + return; + + byte t_col = _screen->Get_Visual(p.x, p.y); + byte t_pri = _screen->Get_Priority(p.x, p.y); + byte t_con = _screen->Get_Control(p.x, p.y); + int16 w, e, a_set, b_set; + // if in 1st point priority,control or color is already set to target, clear the flag + if (!_s->resMan->isVGA()) { + // EGA 16 colors + if (flag & 1 && ((t_col == (color & 0x0F)) || (t_col == (color >> 4)))) + flag ^= 1; + } else { + // VGA 256 colors + if (flag & 1 && t_col == color) + flag ^= 1; + } + if (flag & 2 && t_pri == prio) + flag ^= 2; + if (flag & 4 && t_con == control) + flag ^= 4; + if (flag == 0)// nothing to fill + return; + + // hard borders for filling + int l = _curPort->rect.left + _curPort->left; + int t = _curPort->rect.top + _curPort->top; + int r = _curPort->rect.right + _curPort->left - 1; + int b = _curPort->rect.bottom + _curPort->top - 1; + while (stack.size()) { + p = stack.pop(); + if ((fmatch = _screen->IsFillMatch(p.x, p.y, flag, t_col, t_pri, t_con)) == 0) // already filled + continue; + _screen->Put_Pixel(p.x, p.y, flag, color, prio, control); + w = p.x; + e = p.x; + // moving west and east pointers as long as there is a matching color to fill + while (w > l && (fmatch = _screen->IsFillMatch(w - 1, p.y, flag, t_col, t_pri, t_con))) + _screen->Put_Pixel(--w, p.y, fmatch, color, prio, control); + while (e < r && (fmatch = _screen->IsFillMatch(e + 1, p.y, flag, t_col, t_pri, t_con))) + _screen->Put_Pixel(++e, p.y, fmatch, color, prio, control); + // checking lines above and below for possible flood targets + a_set = b_set = 0; + while (w <= e) { + if (p.y > t && _screen->IsFillMatch(w, p.y - 1, flag, t_col, t_pri, t_con)) { // one line above + if (a_set == 0) { + p1.x = w; + p1.y = p.y - 1; + stack.push(p1); + a_set = 1; + } + } else + a_set = 0; + + if (p.y < b && _screen->IsFillMatch(w, p.y + 1, flag, t_col, t_pri, t_con)) { // one line below + if (b_set == 0) { + p1.x = w; + p1.y = p.y + 1; + stack.push(p1); + b_set = 1; + } + } else + b_set = 0; + w++; + } + } +} + +void SciGUIgfx::drawPicture(sciResourceId pictureId, uint16 style, bool addToFlag, sciResourceId paletteId) { + SciGUIpicture *picture; + + picture = new SciGUIpicture(_system, _s, this, _screen, pictureId); + // do we add to a picture? if not -> clear screen + if (!addToFlag) { + ClearScreen(0); + } + picture->draw(style, addToFlag, paletteId); +} + +void SciGUIgfx::drawCell(sciResourceId viewId, uint16 loopNo, uint16 cellNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo) { + SciGUIview *view = new SciGUIview(_system, _s, this, _screen, viewId); + Common::Rect rect(0, 0); + Common::Rect clipRect(0, 0); + if (view) { + rect.left = leftPos; + rect.top = topPos; + rect.right = rect.left + view->getWidth(loopNo, cellNo); + rect.bottom = rect.top + view->getHeight(loopNo, cellNo); + clipRect = rect; + clipRect.clip(_curPort->rect); + if (clipRect.isEmpty()) // nothing to draw + return; + view->draw(rect, clipRect, loopNo, cellNo, priority, paletteNo); + //if (_picNotValid == 0) + // _gfx->ShowBits(rect, 1); + } +} + +void SciGUIgfx::animatePalette(byte fromColor, byte toColor, int speed) { + sciColor col; + int len = toColor - fromColor - 1; + uint32 now = _sysTicks; + // search for sheduled animations with the same 'from' value + int sz = _palSchedules.size(); + for (int i = 0; i < sz; i++) { + if (_palSchedules[i].from == fromColor) { + if (_palSchedules[i].schedule < now) { + if (speed > 0) { + col = _sysPalette.colors[fromColor]; + memmove(&_sysPalette.colors[fromColor], &_sysPalette.colors[fromColor + 1], len * sizeof(sciColor)); + _sysPalette.colors[toColor - 1] = col; + } else { + col = _sysPalette.colors[toColor - 1]; + memmove(&_sysPalette.colors[fromColor+1], &_sysPalette.colors[fromColor], len * sizeof(sciColor)); + _sysPalette.colors[fromColor] = col; + } + // removing schedule + _palSchedules.remove_at(i); + } + SetCLUT(&_sysPalette); + return; + } + } + // adding a new schedule + sciPalSched sched; + sched.from = fromColor; + sched.schedule = now + ABS(speed); + _palSchedules.push_back(sched); +} + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_gfx.h b/engines/sci/gui/gui_gfx.h new file mode 100644 index 0000000000..ac64d71af3 --- /dev/null +++ b/engines/sci/gui/gui_gfx.h @@ -0,0 +1,150 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +namespace Sci { + +#define SCI_PATTERN_CODE_RECTANGLE 0x10 +#define SCI_PATTERN_CODE_USE_TEXTURE 0x20 +#define SCI_PATTERN_CODE_PENSIZE 0x07 + +class SciGUIscreen; +class SciGUIfont; +class SciGUIpicture; +class SciGUIview; +class SciGUIgfx { +public: + SciGUIgfx(OSystem *system, EngineState *state, SciGUIscreen *screen); + ~SciGUIgfx(); + + void init(void); + void initPalette(); + virtual void initTimer(); + static void timerHandler(void*ref); + + sciPort *mallocPort (); + byte *GetSegment(byte seg); + void ResetScreen(); + void SetEGApalette(); + void CreatePaletteFromData(byte *paletteData, sciPalette *paletteOut); + bool SetResPalette(int16 resourceNo, int16 flag); + void SetPalette(sciPalette *sciPal, int16 flag); + void MergePalettes(sciPalette*pFrom, sciPalette*pTo, uint16 flag); + uint16 MatchColor(sciPalette*pPal, byte r, byte g, byte b); + void SetCLUT(sciPalette*pal); + void GetCLUT(sciPalette*pal); + + sciPort *SetPort(sciPort *port); + sciPort *GetPort(); + void SetOrigin(int16 left, int16 top); + void MoveTo(int16 left, int16 top); + void Move(int16 left, int16 top); + void SetFont(int16 fontId); + void OpenPort(sciPort *port); + void PenColor(int16 color); + void PenMode(int16 mode); + void TextFace(int16 textFace); + int16 GetPointSize(void); + int16 GetFontId(); + SciGUIfont *GetFont(); + + void ClearScreen(byte color = 255); + void InvertRect(const Common::Rect &rect); + void EraseRect(const Common::Rect &rect); + void PaintRect(const Common::Rect &rect); + void FillRect(const Common::Rect &rect, int16 arg2, byte clrPen, byte clrBack = 0, byte bControl = 0); + void FrameRect(const Common::Rect &rect); + void OffsetRect(Common::Rect &r); + + byte CharHeight(int16 ch); + byte CharWidth(int16 ch); + int16 TextWidth(const char*text, int16 from, int16 len); + int16 StringWidth(const char*str) { + return TextWidth(str, 0, (int16)strlen(str)); + } + void ClearChar(int16 chr); + void DrawChar(int16 chr); + void StdChar(int16 chr); + SCILanguage getSCILanguage(); + char* StrSplit(char*buff, const char*msg, const char*fmt); + char* getIntlString(char*buff, const char*msg, const char*fmt, SCILanguage lang, SCILanguage prop); + int16 TextSize(Common::Rect &rect, const char *str, int16 fontId, int16 maxwidth); + int16 GetLongest(const char *str, int16 maxwidth); + void DrawText(const char *str, int16 from, int16 len); + void ShowText(const char *str, int16 from, int16 len); + void ShowString(const char *str) { + ShowText(str, 0, (int16)strlen(str)); + } + void DrawString(const char *str) { + DrawText(str, 0, (int16)strlen(str)); + } + void TextBox(const char *str, int16 bshow, const Common::Rect &rect, int16 align, int16 fontId); + void ShowBits(const Common::Rect &r, uint16 flags); + sciMemoryHandle SaveBits(const Common::Rect &rect, byte screenFlags); + void RestoreBits(sciMemoryHandle memoryHandle); + + void Draw_Line(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control); + void Draw_Horiz(int16 left, int16 right, int16 top, byte flag, byte color, byte prio, byte control); + void Draw_Vert(int16 top, int16 bottom, int16 left, byte flag, byte color, byte prio, byte control); + void Draw_Box(Common::Rect box, byte color, byte prio, byte control); + void Draw_TexturedBox(Common::Rect box, byte color, byte prio, byte control, byte texture); + void Draw_Circle(Common::Rect box, byte size, byte color, byte prio, byte control); + void Draw_TexturedCircle(Common::Rect box, byte size, byte color, byte prio, byte control, byte texture); + void Draw_Pattern(int16 x, int16 y, byte pic_color, byte pic_priority, byte pic_control, byte code, byte texture); + void Pic_Fill(int16 x, int16 y, byte color, byte prio, byte control); + + void drawPicture(sciResourceId pictureId, uint16 style, bool addToFlag, sciResourceId paletteId); + void drawCell(sciResourceId viewId, uint16 loopNo, uint16 cellNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo); + + void animatePalette(byte fromColor, byte toColor, int speed); + + sciPort *_menuPort; + uint32 _sysTicks; + int32 _sysSpeed; // ticker timer in ms + sciPalette _sysPalette; + + uint16 _resolutionWidth; + uint16 _resolutionHeight; + uint _resolutionPixels; + +private: + OSystem *_system; + EngineState *_s; + SciGUIscreen *_screen; + + Common::Rect _bounds; + sciPort *_mainPort; + sciPort *_curPort; +// byte *_visualScreen; +// byte *_pcSeg; + uint16 _clrPowers[256]; + + byte bMapColors; + sciPalette *pPicPal; + Common::Array<sciPalSched> _palSchedules; + + SciGUIfont *_font; +}; + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_helpers.h b/engines/sci/gui/gui_helpers.h new file mode 100644 index 0000000000..3f80d0cd75 --- /dev/null +++ b/engines/sci/gui/gui_helpers.h @@ -0,0 +1,150 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/rect.h" +#include "sci/engine/vm_types.h" + +namespace Sci { + +typedef int sciResourceId; // is a resource-number and -1 means no parameter given +typedef reg_t sciMemoryHandle; +typedef uint16 SCIHANDLE; + +struct sciNode { + SCIHANDLE next; // heap handle to next node + SCIHANDLE prev; // heap handle to data + uint16 key; // maybe also a heap handle +}; +struct sciNode1 : sciNode { + uint16 value; +}; + +// sciPort and sciWnd need to be binary identical, so if you change anything in one, you have to change it in the other one +// as well! +struct sciPort { + sciNode node; // node struct for list operations + int16 top, left; + Common::Rect rect; + int16 curTop, curLeft; + int16 fontH; + sciResourceId fontId; + int16 textFace, penClr, backClr; + int16 penMode; +}; + +struct sciWnd { + // begins like sciPort (needs to be binary identical!!) + sciNode node; // node struct for list operations + int16 top, left; + Common::Rect rect; + int16 curTop, curLeft; + int16 fontH; + sciResourceId fontId; + int16 textFace, penClr, backClr; + int16 penMode; + // window specific members + Common::Rect rect0; // client area of window + Common::Rect rect1; // total area of window including borders + uint16 wndStyle; + uint16 uSaveFlag; + reg_t hSaved1; + reg_t hSaved2; + SCIHANDLE hTitle; + bool bDrawed; +}; + +struct sciCast { + sciNode node; + uint16 view; + uint16 loop; + uint16 cel; + uint16 z; + uint16 pal; + SCIHANDLE hSaved; + Common::Rect rect; +}; + +struct sciColor { + byte used; + byte r, g, b; +}; + +struct sciPalette { + byte mapping[256]; + uint32 timestamp; + sciColor colors[256]; + byte intencity[256]; +}; + +struct sciPalSched { + byte from; + uint32 schedule; +}; + +#define STUB(str) debug("STUB: '%s' at file %s line %d",str,__FILE__,__LINE__) + + +// FIXME: The following feature enums and macros should be reconsidered. +// The way they are done right now is highly error prone. + +enum { + FTR_WINDOWMGR_SCI0 = (0<<0), // SCI0 based window manager + FTR_WINDOWMGR_SCI1 = (1<<0), // SCI1 based window manager + FTR_CAN_BEHERE = (0<<1), // Kernel77 is kCanBeHere (SCI0) + FTR_CANT_BEHERE = (1<<1), // Kernel77 is kCantBeHere(SCI1) + FTR_SOUND_SCI0 = (0<<2), // SCI0 Sound functions + FTR_SOUND_SCI01 = (1<<2), // SCI0+ Sound functions + FTR_SOUND_SCI1 = (2<<2), // SCI1 Sound functions + FTR_SHOWPIC_SCI0 = (0<<4), // SCI0 ShowPic (44 effect codes) + FTR_SHOWPIC_SCI1 = (1<<4), // SCI1 ShowPic (15 effect codes) + FTR_GL_ANIMATE = (1<<5) // Animate can be paused by global flag +}; + +#define GETFTR_WINDOWMGR(x) (x & 0x00000001) +#define GETFTR_CANBEHERE(x) (x & 0x00000002) +#define GETFTR_SOUND(x) (x & 0x0000000C) +#define GETFTR_SHOWPIC(x) (x & 0x00000010) + +enum { + GFX_STOPUPDATE = 0x01, + GFX_VIEWUPDATED = 0x02, + GFX_NOUPDATE = 0x04, + GFX_HIDDEN = 0x08, + GFX_FIXEDPRIO=0x10, + GFX_ALWAYSUPDATE = 0x20, + GFX_FORCEUPDATE = 0x40, + GFX_REMOVEVIEW = 0x80 +}; + +enum SCILanguage{ + kLangNone = 0, + kLangEnglish = 1, + kLangFrench = 33, + kLangSpanish = 34, + kLangItalian = 39, + kLangGerman = 49 +}; + +} diff --git a/engines/sci/gui/gui_memmgr.cpp b/engines/sci/gui/gui_memmgr.cpp new file mode 100644 index 0000000000..3b42da274e --- /dev/null +++ b/engines/sci/gui/gui_memmgr.cpp @@ -0,0 +1,373 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sci.h" +#include "sci/gui/gui_helpers.h" +#include "sci/gui/gui_memmgr.h" + +namespace Sci { + +static tagHandle *pHandles = 0; +static int16 nHandles = 0; +static byte *_heap = 0; +SCIHANDLE _firstfree = 0; +Common::HashMap<HEAPHANDLE, tagHeapInfo> heapInfo; +#define HEAP_BOTTOM 1000 + +//---------------------- +void FreeMem(void) { + // deleting handles + if (pHandles) { + for (uint16 i = 0; i < nHandles; i++) + hunkDisposeHandle(i); + delete[] pHandles; + pHandles = 0; + } + // deleting heap + if (_heap) { + delete[] _heap; + _heap = 0; + } +} +//---------------------- +bool InitMem(int16 max_handles) { + // heap + _heap = new byte[HEAP_SIZE]; + memset(_heap, 0x55, HEAP_SIZE); + _firstfree = HEAP_START; + heapSetBlockSize(_firstfree, HEAP_SIZE - 1 - HEAP_START); + heapSetBlockNext(_firstfree, (SCIHANDLE)(HEAP_SIZE - 1)); + //hunk + pHandles = new tagHandle[max_handles]; + if (pHandles) { + nHandles = max_handles; + memset(pHandles, 0, sizeof(tagHandle) * max_handles); // zerofy all + return 1; + } + return 0; +} +//---------------------- +SCIHANDLE hunkNeedHandle(uint16 size, uint32 resId) { + SCIHANDLE newh = 0; + // see if there is an empty handle available + for (int16 i = 1; i < nHandles; i++) + if (pHandles[i].ptr == 0) { + newh = i; + break; + } + // if unused handle was found - allocate memory and return it + if (newh == nHandles) + return 0; + pHandles[newh].ptr = (byte*)malloc(size); + assert(pHandles[newh].ptr); + if (pHandles[newh].ptr) { + pHandles[newh].size = size; + pHandles[newh].resId = resId; + debug( + 5, + " MemMgr: Requested %6db for res %08X, allocated handle %04X", + size, resId, newh); + return newh; + } + return 0; +} +//---------------------- +void hunkDisposeHandle(SCIHANDLE handle) { +// if (handle > 0 && handle < nHandles && pHandles[handle].ptr) { +// debug( +// 5, +// " MemMgr: disposing handle 0x%04X, size=%8db, associated res %08X", +// handle, pHandles[handle].size, pHandles[handle].resId); +// free(pHandles[handle].ptr); +// pHandles[handle].ptr = 0; +// // deleting associated resource handler +// // Check that this don't fail on delete as ResGetLoaded could return 0; +// if (pHandles[handle].resId != 0xFFFFFFFF) +// delete g_sci->ResMgr.ResGetLoaded(pHandles[handle].resId); +// } +} +//---------------------- +byte *hunk2Ptr(SCIHANDLE handle) { + if (handle > 0 && handle < nHandles && pHandles[handle].ptr) + return (byte *)pHandles[handle].ptr; + return 0; +} +//---------------------- +SCIHANDLE ptr2hunk(byte *ptr) { + for (int i = 0; i < nHandles; i++) { + if (ptr >= pHandles[i].ptr && ptr <= pHandles[i].ptr + pHandles[i].size) + return i; + } +return 0; +} +//---------------------- +uint32 hunkHandleSize(SCIHANDLE handle) { + if (handle > 0 && handle < nHandles && pHandles[handle].ptr) + return pHandles[handle].size; + return 0; +} +//---------------------- +// int16 hunkResourceNum(SCIHANDLE handle) { +// if (handle > 0 && handle < nHandles && pHandles[handle].ptr) +// return RES_ID2NUM(pHandles[handle].resId); +// return -1; +// } + +//---------------------- +void hunkDump() { + debug("\nMemMgr: Hunk dump:"); + uint32 size = 0; + for (int i = 0; i < nHandles; i++) + if (pHandles[i].ptr) { + debug(" %04X, size=%8db, associated res %08X", i, + pHandles[i].size, pHandles[i].resId); + size += pHandles[i].size; + } + debug("Total memory allocated: %db", size); + debug("End dump"); +} + +uint32 hunkUsed() { + uint32 size = 0; + for (int i = 0; i < nHandles; i++) + if (pHandles[i].ptr) + size += pHandles[i].size; + return size; +} +//---------------------- +// HEAP +//---------------------- +//--------------------------------------------- +// TODO : make sure that STRING, STACK and SCRIPT DATA is never allocated below HEAP_BOTTOM=1000 +// otherwise it will cause problems with kernel string fuctions that assumes that anything below 1000 is res number +HEAPHANDLE heapNewPtr(uint16 size, kDataType type, const char *info) { + if (size == 0) + warning("Zero Heap Allocation Request!"); + + HEAPHANDLE ptr, prev, next; + ptr = prev = _firstfree; + // 2 bytes block header header + block size must be odd + size += 2 + (size & 1); + // looking for an empty block to use + uint16 blocksize; + bool bBottomSafe = !(type == kDataString || type == kDataUnknown); + + while (ptr < HEAP_SIZE - 1) { + blocksize = heapGetBlockSize(ptr); + next = heapGetBlockNext(ptr); + if (blocksize >= size) { + if (bBottomSafe || (!bBottomSafe && ptr > HEAP_BOTTOM)) { + if (blocksize <= size + 4) { // use all block + size = blocksize; + heapSetBlockNext(prev, next); + } else { // split block in 2 blocks + HEAPHANDLE newblock = ptr + size; + heapSetBlockNext(prev, newblock); + heapSetBlockSize(newblock, blocksize - size); + heapSetBlockNext(newblock, next); + next = newblock; + } + // setting allocated block + heapSetBlockSize(ptr, size); + // updating firstfree pointer + if (ptr == _firstfree) + _firstfree = next; + setHeapInfo(ptr, type, info); + return ptr; + } //if (bBottomSafe || (!bBottomSafe && ptr>HEAP_BOTTOM)) + else { // !bottomsafe && ptr < HEAP_BOTTOM + if (blocksize + ptr - HEAP_BOTTOM >= size) { + // splitting the block into 3 parts + // [2][ptr...999] [2][1002...1000+size-1] [2][1002+size...ptr+blocksize] + // free returned free + heapSetBlockSize(ptr, HEAP_BOTTOM-ptr + 2); + heapSetBlockSize(HEAP_BOTTOM+2, size); + heapSetBlockSize(HEAP_BOTTOM+2 + size, blocksize - size + - (HEAP_BOTTOM-ptr + 2)); + + heapSetBlockNext(HEAP_BOTTOM+2 + size, next); + heapSetBlockNext(ptr, HEAP_BOTTOM+2 + size); + setHeapInfo(HEAP_BOTTOM+2, type, info); + return HEAP_BOTTOM + 2; + } + } + } // if (blocksize >= size) + // block too small - moving to next one + prev = ptr; + ptr = next; + } + // allocation error - out of heap + warning("Out of heap space"); + return 0; +} +//-------------------------------------------- +void heapDisposePtr(HEAPHANDLE handle) { + HEAPHANDLE prev, next; + prev = next = _firstfree; + // searching for prev and next free blocks (before & after deleted block) + while (next < handle) { + prev = next; + next = heapGetBlockNext(prev); + } + // if deleted block is before 1st free space then it'll be 1st free space + if (handle < _firstfree) { + next = _firstfree; + _firstfree = handle; + } else + heapSetBlockNext(prev, handle); + + heapSetBlockNext(handle, next); + //Try to merge with previous + if (prev + heapGetBlockSize(prev) == handle) { + heapSetBlockSize(prev, heapGetBlockSize(prev) + + heapGetBlockSize(handle)); + heapSetBlockNext(prev, next); + handle = prev; + } + //Try to merge with next + if (handle + heapGetBlockSize(handle) == next && next != (HEAP_SIZE - 1)) { + heapSetBlockSize(handle, heapGetBlockSize(handle) + heapGetBlockSize( + next)); + heapSetBlockNext(handle, heapGetBlockNext(next)); + } +} +//------------------------------------- +uint16 heapFreeSize() { + HEAPHANDLE free = _firstfree; + uint16 szFree = 0; + while (free < HEAP_SIZE - 1) { + int size = heapGetBlockSize(free); + free = heapGetBlockNext(free); + szFree += size; + } + return szFree; +} +//------------------------------------- +uint16 heapLargestFreeSize() { + HEAPHANDLE free = _firstfree; + uint16 maxFree = 0; + while (free < HEAP_SIZE - 1) { + int size = heapGetBlockSize(free); + free = heapGetBlockNext(free); + if (size > maxFree) + maxFree = size; + } + return maxFree ? maxFree - 2 : 0; +} +//------------------------------------- +void heapDump() { + debug("\nMemMgr:Heap dump:"); + HEAPHANDLE ptr = HEAP_START; + HEAPHANDLE free = _firstfree; + + uint16 szFree = 0, szUsed = 0; + while (ptr < HEAP_SIZE - 1) { + int size = heapGetBlockSize(ptr); + if (ptr == free) { + free = heapGetBlockNext(free); + debug(" %04X %6u size:%6d FREE next=%04X", ptr, ptr, + heapGetDataSize(ptr), free); + szFree += size; + } else { + debug(" %04X %6u size:%6d USED", ptr, ptr, heapGetDataSize(ptr)); + szUsed += size; + } + ptr += size; + } + debug("Total %db used, %db free\nEnd Dump", szUsed, szFree); +} +//---------------------------- +inline byte *heap2Ptr(HEAPHANDLE ptr) { + return (ptr >= HEAP_START) ? (byte *)(_heap + ptr) : NULL; +} +//---------------------------- +HEAPHANDLE ptr2heap(byte *ptr) { + return ptr > _heap && ptr < (_heap + HEAP_SIZE) ? (HEAPHANDLE)(ptr - _heap) + : 0; +} +//---------------------------- +uint16 heapGetBlockSize(HEAPHANDLE ptr) { + return READ_UINT16(_heap + ptr - 2); +} +//---------------------------- +uint16 heapGetDataSize(HEAPHANDLE ptr) { + return heapGetBlockSize(ptr) - 2; +} +//---------------------------- +void heapFillPtr(HEAPHANDLE ptr, byte filler) { + memset(heap2Ptr(ptr), filler, heapGetDataSize(ptr)); +} +//---------------------------- +void heapClearPtr(HEAPHANDLE ptr) { + heapFillPtr(ptr, 0); +} +//---------------------------- +void heapSetBlockSize(HEAPHANDLE ptr, uint16 nbytes) { + WRITE_UINT16(_heap + ptr - 2, nbytes); +} +//---------------------------- +HEAPHANDLE heapGetBlockNext(HEAPHANDLE ptr) { + return READ_UINT16(_heap + ptr); +} +//---------------------------- +void heapSetBlockNext(HEAPHANDLE ptr, SCIHANDLE next) { + WRITE_UINT16(_heap + ptr, next); +} +//---------------------------- +void heapDisposePtr(byte *ptr) { + heapDisposePtr(ptr - _heap); +} +//--------------------------------------------- +// +// +void setHeapInfo(HEAPHANDLE hnd, kDataType type, const char *szinfo) { + tagHeapInfo info = { kDataUnknown, 0 }; + info.type = type; + if (szinfo) + strncpy(info.info, szinfo, 20); + heapInfo.setVal(hnd, info); +} +//-------------------------------- +bool saveMemState(Common::OutSaveFile *pFile) { + pFile->writeString("MEMORY\n"); + // saving heap + pFile->write(_heap, HEAP_SIZE); + pFile->writeUint16LE(_firstfree); + // TODO : process and write hunk handles + //pFile->writeString("HUNK\n"); + return true; +} +//-------------------------------- +bool restoreMemState(Common::InSaveFile *pFile) { + if (pFile->readLine() != "MEMORY") + return false; + pFile->read(_heap, HEAP_SIZE); + _firstfree = pFile->readUint16LE(); + + return true; +} + +//------------------------------- +}// end of namespace SCI diff --git a/engines/sci/gui/gui_memmgr.h b/engines/sci/gui/gui_memmgr.h new file mode 100644 index 0000000000..4a1631cadf --- /dev/null +++ b/engines/sci/gui/gui_memmgr.h @@ -0,0 +1,123 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SCI_MEMMGR_H +#define SCI_MEMMGR_H + +#include "common/savefile.h" +#include "common/endian.h" +#include "common/hashmap.h" + +/* + Memory management functions for SCI engine; + All fuctions are simplified as there is no 16-bit limitations as in + original SCI. Although it may cause problems. + + SCI Heap functionality. + Heap size is limited to 65535 bytes to be consistent with SCI scripts + Free block header is [wBlockSize][wNextFree] + Used block header is [wBlockSize][data.....] + ^-----returned HEAPHANDLE + */ + +namespace Sci { + +typedef uint16 SCIHANDLE; +typedef uint16 HEAPHANDLE; + +enum { + HEAP_SIZE = 0x10000l, + HEAP_START = 2 +}; + +struct tagHandle { + byte *ptr; // data pointer + uint32 size; // memory block size + uint32 resId; // associated resource +}; +//--------------------------------------------- +// for debugger +enum kDataType { + kDataUnknown = 0, + kDataClass, + kDataObject, + kDataRect, + kDataWindow, + kDataPort, + kDataString, + kDataListHdr, + kDataListNode, + kDataCast, + kDataPalette, + kDataScript, + kDataFile +}; + +struct tagHeapInfo { + kDataType type; + char info[21]; +}; + +void setHeapInfo(HEAPHANDLE hnd, kDataType type, const char *info = 0); + +bool InitMem(int16 max_handles); +void FreeMem(void); + +// hunk functions +SCIHANDLE hunkNeedHandle(uint16 size, uint32 resId = 0xFFFFFFFF); +void hunkDisposeHandle(SCIHANDLE handle); + +byte *hunk2Ptr(SCIHANDLE handle); +SCIHANDLE ptr2hunk(byte *ptr); +uint32 hunkHandleSize(SCIHANDLE handle); +int16 hunkResourceNum(SCIHANDLE handle); +void hunkDump(); +uint32 hunkUsed(); + +// heap functions +HEAPHANDLE heapNewPtr(uint16 size, kDataType type/*=kDataUnknown*/, + const char *info = 0); +void heapDisposePtr(HEAPHANDLE handle); +void heapDisposePtr(byte *ptr); +byte *heap2Ptr(HEAPHANDLE ptr); +HEAPHANDLE ptr2heap(byte *ptr); +uint16 heapGetBlockSize(HEAPHANDLE ptr); +uint16 heapGetDataSize(HEAPHANDLE ptr); +void heapFillPtr(HEAPHANDLE ptr, byte filler); +void heapClearPtr(HEAPHANDLE ptr); +void heapDump(); +uint16 heapFreeSize(); +uint16 heapLargestFreeSize(); + +void heapSetBlockSize(HEAPHANDLE ptr, uint16 nbytes); +HEAPHANDLE heapGetBlockNext(HEAPHANDLE ptr); +void heapSetBlockNext(HEAPHANDLE ptr, SCIHANDLE next); + +bool saveMemState(Common::OutSaveFile *pFile); +bool restoreMemState(Common::InSaveFile *pFile); + +} // end of namespace SCI + +#endif diff --git a/engines/sci/gui/gui_picture.cpp b/engines/sci/gui/gui_picture.cpp new file mode 100644 index 0000000000..1f2218ad84 --- /dev/null +++ b/engines/sci/gui/gui_picture.cpp @@ -0,0 +1,592 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/gui/gui_screen.h" +#include "sci/gui/gui_gfx.h" +#include "sci/gui/gui_picture.h" + +namespace Sci { + +SciGUIpicture::SciGUIpicture(OSystem *system, EngineState *state, SciGUIgfx *gfx, SciGUIscreen *screen, sciResourceId resourceId) + : _system(system), _s(state), _gfx(gfx), _screen(screen), _resourceId(resourceId) { + assert(resourceId != -1); + initData(resourceId); +} + +SciGUIpicture::~SciGUIpicture() { +} + +void SciGUIpicture::initData(sciResourceId resourceId) { + _resource = _s->resMan->findResource(ResourceId(kResourceTypePic, resourceId), false); + if (!_resource) { + error("picture resource %d not found", resourceId); + } +} + +sciResourceId SciGUIpicture::getResourceId() { + return _resourceId; +} + +#define PALETTE_SIZE 1284 +#define CEL_HEADER_SIZE 7 +#define EXTRA_MAGIC_SIZE 15 + +void SciGUIpicture::draw(uint16 style, bool addToFlag, int16 EGApaletteNo) { + _style = style; + _addToFlag = addToFlag; + _EGApaletteNo = EGApaletteNo; + _curPort = _gfx->GetPort(); + _priority = 0; + + if (READ_LE_UINT16(_resource->data) == 0x26) { + // SCI 1.1 picture + draw11(); + } else { + // Just directly draw the vector data + _gfx->SetEGApalette(); + drawVectorData(_resource->data, _resource->size); + } +} + +void SciGUIpicture::reset() { + int16 x, y; + for (y = _curPort->top; y < _screen->_height; y++) { + for (x = 0; x < _screen->_width; x++) { + _screen->Put_Pixel(x, y, SCI_SCREEN_MASK_ALL, 255, 0, 0); + } + } +} + +void SciGUIpicture::draw11() { + byte *inbuffer = _resource->data; + int size = _resource->size; + int has_view = READ_LE_UINT16(inbuffer + 4); + int vector_data_ptr = READ_LE_UINT16(inbuffer + 16); + int vector_size = size - vector_data_ptr; + int palette_data_ptr = READ_LE_UINT16(inbuffer + 28); + int view_data_ptr = READ_LE_UINT16(inbuffer + 32); + int view_size = palette_data_ptr - view_data_ptr; + int view_rle_ptr = READ_LE_UINT16(inbuffer + view_data_ptr + 24); + int view_pixel_ptr = READ_LE_UINT16(inbuffer + view_data_ptr + 28); + byte *view = NULL; + sciPalette palette; + + // Create palette and set it + _gfx->CreatePaletteFromData(inbuffer + palette_data_ptr, &palette); + _gfx->SetPalette(&palette, 2); +// drawPalette11(inbuffer + palette_data_ptr); + + // display Cel-data + if (has_view) { + view = (byte *)malloc(size*2); // is there a way to know how much decoded view-data there will be? + if (!view) return; + memcpy(view, inbuffer + view_data_ptr, 8); + decodeRLE(inbuffer + view_rle_ptr, inbuffer + view_pixel_ptr, view + 8, view_size - 8); + drawCel(0, 0, view, size * 2); + free(view); + } + + // process vector data + // ?? if we process vector data first some things in sq4 dont seem right, but this way we wont get _priority set + drawVectorData(inbuffer + vector_data_ptr, vector_size); +} + +void SciGUIpicture::drawPalette11(byte *data) { + int start_color = data[25]; + int format = data[32]; + byte *pal_data = &data[37]; + int colors_nr = READ_LE_UINT16(data + 29); + int i; + sciPalette palette = {0}; + + switch (format) { + case SCI_PAL_FORMAT_VARIABLE_FLAGS: + for (i = start_color; i < start_color + colors_nr; i ++) { + palette.colors[i].used = pal_data[0]; + palette.colors[i].r = pal_data[1]; + palette.colors[i].g = pal_data[2]; + palette.colors[i].b = pal_data[3]; + pal_data += 4; + } + break; + case SCI_PAL_FORMAT_CONSTANT_FLAGS: + for (i = start_color; i < start_color + colors_nr; i ++) { + palette.colors[i].used = 1; + palette.colors[i].r = pal_data[0]; + palette.colors[i].g = pal_data[1]; + palette.colors[i].b = pal_data[2]; + pal_data += 3; + } + break; + } + _gfx->SetPalette(&palette, 2); +} + +void SciGUIpicture::decodeRLE(byte *rledata, byte *pixeldata, byte *outbuffer, int size) { + int pos = 0; + byte nextbyte; + byte *rd = rledata; + byte *ob = outbuffer; + byte *pd = pixeldata; + + while (pos < size) { + nextbyte = *(rd++); + *(ob++) = nextbyte; + pos ++; + switch (nextbyte&0xC0) { + case 0x40 : + case 0x00 : + memcpy(ob, pd, nextbyte); + pd += nextbyte; + ob += nextbyte; + pos += nextbyte; + break; + case 0xC0 : + break; + case 0x80 : + nextbyte = *(pd++); + *(ob++) = nextbyte; + pos ++; + break; + } + } +} + +void SciGUIpicture::drawCel(int16 x, int16 y, byte *pdata, int size) { + byte* pend = pdata + size; + uint16 width = READ_LE_UINT16(pdata + 0); + uint16 height = READ_LE_UINT16(pdata + 2); + signed char dx = *(pdata + 4); + signed char dy = *(pdata + 5); + byte priority = _addToFlag ? _priority : 0; + byte clr = *(pdata + 6); + if (dx || dy || width != 320) + debug("Warning: embedded picture cel has width=%d dx=%d dy=%d", width, dx, dy); + byte *ptr = pdata + 8; // offset to data + + y += _curPort->top; + + uint16 j = 0, lasty = MIN<int16>(height + y, _curPort->rect.bottom) + _curPort->top; + byte b, brun; + + while (y < lasty && ptr < pend) { + b = *ptr++; + brun = b & 0x3F; // bytes run length on this step + switch (b & 0xC0) { + case 0: // copy bytes as-is but skip transparent ones + while (brun-- && y < lasty && ptr < pend) { + if ((b = *ptr++) != clr && priority >= _screen->Get_Priority(x, y)) { + _screen->Put_Pixel(x, y, 3, b, priority, 0); + } + x++; + if (x >= _screen->_width) { + x -= _screen->_width; y++; + } + } + break; + case 0x80: // fill with color + b = *ptr++; + while (brun-- && y < lasty) { + if (priority >= _screen->Get_Priority(x, y)) { + _screen->Put_Pixel(x, y, 3, b, priority, 0); + } + x++; + if (x >= _screen->_width) { + x -= _screen->_width; y++; + } + } + break; + case 0xC0: // fill with transparent - skip + x += brun; + if (x >= _screen->_width) { + x -= _screen->_width; y++; + } + break; + } + } +} + +void SciGUIpicture::drawCelAmiga(int16 x, int16 y, byte *pdata, int size) { + byte* pend = pdata + size; + uint16 width = READ_LE_UINT16(pdata + 0); + uint16 height = READ_LE_UINT16(pdata + 2); + signed char dx = *(pdata + 4); + signed char dy = *(pdata + 5); + byte priority = _addToFlag ? _priority : 0; + //byte clr = *(pdata + 8); + if (dx || dy || width != 320) + debug("Warning : cel have w=%d dx=%d dy=%d", width, dx, dy); + byte *ptr = pdata + 8; // offset to data + + y += _curPort->top; + + uint16 j = 0, lasty = MIN<int16>(height + y, _curPort->rect.bottom) + _curPort->top; + byte op, col, bytes; + while (y < lasty && ptr < pend) { + op = *ptr++; + if (op & 0x07) { + bytes = op & 0x07; + col = op >> 3; + while (bytes-- && y < lasty) { + if (priority >= _screen->Get_Priority(x, y)) { + _screen->Put_Pixel(x, y, 3, col, priority, 0); + } + x++; + if (x >= _screen->_width) { + x -= _screen->_width; y++; + } + } + } else { + bytes = op >> 3; + x += bytes; + if (x >= _screen->_width) { + x -= _screen->_width; y++; + } + } + } +} + +enum { + PIC_OP_SET_COLOR = 0xf0, + PIC_OP_DISABLE_VISUAL = 0xf1, + PIC_OP_SET_PRIORITY = 0xf2, + PIC_OP_DISABLE_PRIORITY = 0xf3, + PIC_OP_SHORT_PATTERNS = 0xf4, + PIC_OP_MEDIUM_LINES = 0xf5, + PIC_OP_LONG_LINES = 0xf6, + PIC_OP_SHORT_LINES = 0xf7, + PIC_OP_FILL = 0xf8, + PIC_OP_SET_PATTERN = 0xf9, + PIC_OP_ABSOLUTE_PATTERN = 0xfa, + PIC_OP_SET_CONTROL = 0xfb, + PIC_OP_DISABLE_CONTROL = 0xfc, + PIC_OP_MEDIUM_PATTERNS = 0xfd, + PIC_OP_OPX = 0xfe, + PIC_OP_TERMINATE = 0xff +}; +#define PIC_OP_FIRST PIC_OP_SET_COLOR + +enum { + PIC_OPX_SCI0_SET_PALETTE_ENTRIES = 0, + PIC_OPX_SCI0_SET_PALETTE = 1, + PIC_OPX_SCI0_MONO0 = 2, + PIC_OPX_SCI0_MONO1 = 3, + PIC_OPX_SCI0_MONO2 = 4, + PIC_OPX_SCI0_MONO3 = 5, + PIC_OPX_SCI0_MONO4 = 6, + PIC_OPX_SCI0_EMBEDDED_VIEW = 7, + PIC_OPX_SCI0_SET_PRIORITY_TABLE = 8 +}; + +enum { + PIC_OPX_SCI1_SET_PALETTE_ENTRIES = 0, + PIC_OPX_SCI1_EMBEDDED_VIEW = 1, + PIC_OPX_SCI1_SET_PALETTE = 2, + PIC_OPX_SCI1_PRIORITY_TABLE_EQDIST = 3, + PIC_OPX_SCI1_PRIORITY_TABLE_EXPLICIT = 4 +}; + +#define PIC_EGAPALETTE_COUNT 4 +#define PIC_EGAPALETTE_SIZE 40 +#define PIC_EGAPALETTE_TOTALSIZE PIC_EGAPALETTE_COUNT*PIC_EGAPALETTE_SIZE + +const byte vector_defaultEGApalette[PIC_EGAPALETTE_SIZE] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x88, + 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x88, + 0x88, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x08, 0x91, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x88 +}; + +void SciGUIpicture::drawVectorData(byte *data, int dataSize) { + byte pic_op; + byte pic_color = 0, pic_priority = 0x0F, pic_control = 0x0F; + int16 x = 0, y = 0, oldx, oldy; + byte EGApalette = 0; + byte EGAindex = 0; + byte EGApalettes[PIC_EGAPALETTE_TOTALSIZE] = {0}; + bool EGAmapping = false; + int curPos = 0; + uint16 size; + byte byte; + int i; + sciPalette palette = {0}; + int16 pattern_Code = 0, pattern_Texture = 0; + bool sci1 = false; + + if (_EGApaletteNo >= PIC_EGAPALETTE_COUNT) + _EGApaletteNo = 0; + + if (getSciVersion() >= SCI_VERSION_1_EGA) + sci1 = true; + + for (i = 0; i < PIC_EGAPALETTE_TOTALSIZE; i += PIC_EGAPALETTE_SIZE) + memcpy(&EGApalettes[i], &vector_defaultEGApalette, sizeof(vector_defaultEGApalette)); + + // Drawing + while (curPos < dataSize) { + warning("%X at %d", data[curPos], curPos); + switch (pic_op = data[curPos++]) { + case PIC_OP_SET_COLOR: + byte = data[curPos++]; + pic_color = EGAmapping ? EGApalettes[byte] : byte; + break; + case PIC_OP_DISABLE_VISUAL: + pic_color = 0xFF; + break; + + case PIC_OP_SET_PRIORITY: + pic_priority = data[curPos++]; + break; + case PIC_OP_DISABLE_PRIORITY: + pic_priority = 255; + break; + + case PIC_OP_SET_CONTROL: + pic_control = data[curPos++]; + break; + case PIC_OP_DISABLE_CONTROL: + pic_control = 255; + break; + + case PIC_OP_SHORT_LINES: // short line + vectorGetAbsCoords(data, curPos, oldx, oldy); + while (vectorIsNonOpcode(data[curPos])) { + vectorGetRelCoords(data, curPos, oldx, oldy, x, y); + warning("line %d %d -> %d %d", oldy, oldx, y, x); + _gfx->Draw_Line(oldx, oldy, x, y, pic_color, pic_priority, pic_control); + oldx = x; oldy = y; + } + break; + case PIC_OP_MEDIUM_LINES: // medium line + vectorGetAbsCoords(data, curPos, oldx, oldy); + while (vectorIsNonOpcode(data[curPos])) { + vectorGetRelCoordsMed(data, curPos, oldx, oldy, x, y); + warning("line %d %d -> %d %d", oldy, oldx, y, x); + _gfx->Draw_Line(oldx, oldy, x, y, pic_color, pic_priority, pic_control); + oldx = x; oldy = y; + } + break; + case PIC_OP_LONG_LINES: // long line + vectorGetAbsCoords(data, curPos, oldx, oldy); + while (vectorIsNonOpcode(data[curPos])) { + vectorGetAbsCoords(data, curPos, x, y); + warning("line %d %d -> %d %d", oldy, oldx, y, x); + _gfx->Draw_Line(oldx, oldy, x, y, pic_color, pic_priority, pic_control); + oldx = x; oldy = y; + } + break; + + case PIC_OP_FILL: //fill + while (vectorIsNonOpcode(data[curPos])) { + vectorGetAbsCoords(data, curPos, x, y); + warning("fill %d %d", y, x); + _gfx->Pic_Fill(x, y, pic_color, pic_priority, pic_control); + } + break; + + case PIC_OP_SET_PATTERN: + pattern_Code = data[curPos++]; + break; + case PIC_OP_SHORT_PATTERNS: + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetAbsCoords(data, curPos, x, y); + warning("pattern %d %d", y, x); + _gfx->Draw_Pattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + while (vectorIsNonOpcode(data[curPos])) { + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetRelCoords(data, curPos, x, y, x, y); + warning("pattern %d %d", y, x); + _gfx->Draw_Pattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + } + break; + case PIC_OP_MEDIUM_PATTERNS: + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetAbsCoords(data, curPos, x, y); + warning("pattern %d %d", y, x); + _gfx->Draw_Pattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + while (vectorIsNonOpcode(data[curPos])) { + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetRelCoordsMed(data, curPos, x, y, x, y); + warning("pattern %d %d", y, x); + _gfx->Draw_Pattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + } + break; + case PIC_OP_ABSOLUTE_PATTERN: + while (vectorIsNonOpcode(data[curPos])) { + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetAbsCoords(data, curPos, x, y); + warning("pattern %d %d", y, x); + //_gfx->Draw_Pattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + } + break; + + case PIC_OP_OPX: // Extended functions + if (sci1) { + warning("OPX SCI1 %X at %d", data[curPos], curPos); + switch (pic_op = data[curPos++]) { + case PIC_OPX_SCI1_SET_PALETTE_ENTRIES: + while (vectorIsNonOpcode(data[curPos])) { + curPos++; // skip commands + } + break; + case PIC_OPX_SCI1_SET_PALETTE: + curPos += 256 + 4; // Skip over mapping and timestamp + for (i = 0; i < 256; i++) { + palette.colors[i].used = data[curPos++]; + palette.colors[i].r = data[curPos++]; palette.colors[i].g = data[curPos++]; palette.colors[i].b = data[curPos++]; + } + _gfx->SetPalette(&palette, 2); + break; + case PIC_OPX_SCI1_EMBEDDED_VIEW: // draw cel + vectorGetAbsCoords(data, curPos, x, y); + size = READ_LE_UINT16(data + curPos); curPos += 2; + drawCel(x, y, data + curPos, size); + curPos += size; + break; + case PIC_OPX_SCI1_PRIORITY_TABLE_EQDIST: + //FIXME + //g_sci->InitPri(READ_LE_UINT16(ptr), READ_LE_UINT16(ptr + 2)); + debug(5, "DrawPic::InitPri %d %d", + READ_LE_UINT16(data + curPos), READ_LE_UINT16(data + curPos + 2)); + curPos += 4; + break; + case PIC_OPX_SCI1_PRIORITY_TABLE_EXPLICIT: + //FIXME + //g_sci->PriBands(ptr); + curPos += 14; + break; + default: + error("Unsupported sci1 extended pic-operation %X", pic_op); + } + } else { + switch (pic_op = data[curPos++]) { + case PIC_OPX_SCI0_SET_PALETTE_ENTRIES: + while (vectorIsNonOpcode(data[curPos])) { + byte = data[curPos++]; + if (byte >= PIC_EGAPALETTE_TOTALSIZE) { + error("picture trying to write to invalid EGA-palette"); + } + EGApalettes[byte] = data[curPos++]; + } + break; + case PIC_OPX_SCI0_SET_PALETTE: + byte = data[curPos++]; + if (EGApalette >= PIC_EGAPALETTE_COUNT) { + error("picture trying to write to invalid palette %d", EGApalette); + } + byte *= PIC_EGAPALETTE_SIZE; + for (i = 0; i < PIC_EGAPALETTE_SIZE; i++) { + EGApalettes[byte + i] = data[curPos++]; + } + break; + case PIC_OPX_SCI0_MONO0: + curPos += 41; + break; + case PIC_OPX_SCI0_MONO1: + case PIC_OPX_SCI0_MONO3: + curPos++; + break; + case PIC_OPX_SCI0_MONO2: + case PIC_OPX_SCI0_MONO4: + break; + case PIC_OPX_SCI0_EMBEDDED_VIEW: + vectorGetAbsCoords(data, curPos, x, y); + size = READ_LE_UINT16(data + curPos); curPos += 2; + drawCel(x, y, data + curPos, size); + curPos += size; + break; + case PIC_OPX_SCI0_SET_PRIORITY_TABLE: + //FIXME + //g_sci->PriBands(ptr); + curPos += 14; + break; + default: + error("Unsupported sci1 extended pic-operation %X", pic_op); + } + } + break; + case PIC_OP_TERMINATE: + _priority = pic_priority; + return; + default: + error("Unsupported pic-operation %X", pic_op); + } + } + error("picture vector data without terminator"); +} + +bool SciGUIpicture::vectorIsNonOpcode(byte byte) { + if (byte >= PIC_OP_FIRST) + return false; + return true; +} + +void SciGUIpicture::vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y) { + byte byte = data[curPos++]; + x = data[curPos++] + ((byte & 0xF0) << 4); + y = data[curPos++] + ((byte & 0x0F) << 8); + if (_style & PIC_STYLE_MIRRORED) x = 319 - x; +} + +void SciGUIpicture::vectorGetRelCoords(byte *data, int &curPos, int16 oldx, int16 oldy, int16 &x, int16 &y) { + byte byte = data[curPos++]; + if (byte & 0x80) { + x = oldx - ((byte >> 4) & 7) * (_style & PIC_STYLE_MIRRORED ? -1 : 1); + } else { + x = oldx + (byte >> 4) * (_style & PIC_STYLE_MIRRORED ? -1 : 1); + } + if (byte & 0x08) { + y = oldy - (byte & 7); + } else { + y = oldy + (byte & 7); + } +} + +void SciGUIpicture::vectorGetRelCoordsMed(byte *data, int &curPos, int16 oldx, int16 oldy, int16 &x, int16 &y) { + byte byte = data[curPos++]; + if (byte & 0x80) { + y = oldy - (byte & 0x7F); + } else { + y = oldy + byte; + } + byte = data[curPos++]; + if (byte & 0x80) { + x = oldx - (128 - (byte & 0x7F)) * (_style & PIC_STYLE_MIRRORED ? -1 : 1); + } else { + x = oldx + byte * (_style & PIC_STYLE_MIRRORED ? -1 : 1); + } +} + +void SciGUIpicture::vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture) { + if (pattern_Code & SCI_PATTERN_CODE_USE_TEXTURE) { + pattern_Texture = (data[curPos++] >> 1) & 0x7f; + } +} + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_picture.h b/engines/sci/gui/gui_picture.h new file mode 100644 index 0000000000..815172ed44 --- /dev/null +++ b/engines/sci/gui/gui_picture.h @@ -0,0 +1,71 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +namespace Sci { + +#define SCI_PAL_FORMAT_VARIABLE_FLAGS 0 +#define SCI_PAL_FORMAT_CONSTANT_FLAGS 1 + +#define PIC_STYLE_MIRRORED 0x4000 + +class SciGUIpicture { +public: + SciGUIpicture(OSystem *system, EngineState *state, SciGUIgfx *gfx, SciGUIscreen *screen, sciResourceId resourceId); + ~SciGUIpicture(); + + sciResourceId getResourceId(); + void draw(uint16 style, bool addToFlag, int16 EGApaletteNo); + +private: + void initData(sciResourceId resourceId); + void reset(); + void draw11(); + void decodeRLE(byte *rledata, byte *pixeldata, byte *outbuffer, int size); + void drawPalette11(byte *data); + void drawCel(int16 x, int16 y, byte *pdata, int size); + void drawCelAmiga(int16 x, int16 y, byte *pdata, int size); + void drawVectorData(byte *data, int size); + bool vectorIsNonOpcode(byte byte); + void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y); + void vectorGetRelCoords(byte *data, int &curPos, int16 oldx, int16 oldy, int16 &x, int16 &y); + void vectorGetRelCoordsMed(byte *data, int &curPos, int16 oldx, int16 oldy, int16 &x, int16 &y); + void vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture); + + OSystem *_system; + EngineState *_s; + SciGUIgfx *_gfx; + SciGUIscreen *_screen; + + int16 _resourceId; + Resource *_resource; + + sciPort *_curPort; + uint16 _style; + bool _addToFlag; + int16 _EGApaletteNo; + byte _priority; +}; + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_screen.cpp b/engines/sci/gui/gui_screen.cpp new file mode 100644 index 0000000000..9f4a9e6ce2 --- /dev/null +++ b/engines/sci/gui/gui_screen.cpp @@ -0,0 +1,209 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/timer.h" +#include "common/util.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/gui/gui_screen.h" + +namespace Sci { + +SciGUIscreen::SciGUIscreen(OSystem *system, EngineState *state) + : _system(system), _s(state) { + init(); +} + +SciGUIscreen::~SciGUIscreen() { +} + +void SciGUIscreen::init() { + int i; + uint16 base = 0; + + _width = 320; + _height = 200; + _pixels = _width * _height; + + // if you want to do scaling, adjust Put_Pixel() accordingly + _displayWidth = 320; + _displayHeight = 200; + _displayPixels = _displayWidth * _displayHeight; + _bytesPerDisplayPixel = 1; + + _visualScreen = initScreen(_pixels); + _priorityScreen = initScreen(_pixels); + _controlScreen = initScreen(_pixels); + _displayScreen = initScreen(_displayPixels); + + for (i = 0; i < _height; i++) { + _baseTable[i] = base; _baseDisplayTable[i] = base; + base += _width; + } +} + +byte *SciGUIscreen::initScreen(uint16 pixelCount) { + byte *screen = (byte *)malloc(pixelCount); + memset(screen, 0, pixelCount); + return screen; +} + +void SciGUIscreen::UpdateWhole() { + _system->copyRectToScreen(_displayScreen, _displayWidth, 0, 0, _displayWidth, _displayHeight); + _system->updateScreen(); +} + +byte SciGUIscreen::GetDrawingMask(byte color, byte prio, byte control) { + byte flag = 0; + if (color != 255) + flag |= SCI_SCREEN_MASK_VISUAL; + if (prio != 255) + flag |= SCI_SCREEN_MASK_PRIORITY; + if (control != 255) + flag |= SCI_SCREEN_MASK_CONTROL; + return flag; +} + +void SciGUIscreen::Put_Pixel(int x, int y, byte drawMask, byte color, byte priority, byte control) { + int offset = _baseTable[y] + x; + + if (drawMask & SCI_SCREEN_MASK_VISUAL) { + if (!_s->resMan->isVGA()) { + // EGA output (16 colors, dithered) + color = ((x^y) & 1) ? color >> 4 : color & 0x0F; + } + *(_visualScreen + offset) = color; + _displayScreen[_baseDisplayTable[y] + x] = color; + } + if (drawMask & SCI_SCREEN_MASK_PRIORITY) + *(_priorityScreen + offset) = priority; + if (drawMask & SCI_SCREEN_MASK_CONTROL) + *(_controlScreen + offset) = control; +} + +byte SciGUIscreen::Get_Visual(int x, int y) { + return _visualScreen[_baseTable[y] + x]; +} + +byte SciGUIscreen::Get_Priority(int x, int y) { + return _priorityScreen[_baseTable[y] + x]; +} + +byte SciGUIscreen::Get_Control(int x, int y) { + return _controlScreen[_baseTable[y] + x]; +} + +byte SciGUIscreen::IsFillMatch(int16 x, int16 y, byte flag, byte t_color, byte t_pri, byte t_con) { + int offset = _baseTable[y] + x; + byte match = 0; + + if (flag & SCI_SCREEN_MASK_VISUAL && *(_visualScreen + offset) == t_color) + match |= SCI_SCREEN_MASK_VISUAL; + if (flag & SCI_SCREEN_MASK_PRIORITY && *(_priorityScreen + offset) == t_pri) + match |= SCI_SCREEN_MASK_PRIORITY; + if (flag & SCI_SCREEN_MASK_CONTROL && *(_controlScreen + offset) == t_con) + match |= SCI_SCREEN_MASK_CONTROL; + return match; +} + +int SciGUIscreen::BitsGetDataSize(Common::Rect rect, byte mask) { + int byteCount = sizeof(rect) + sizeof(mask); + int pixels = rect.width() * rect.height(); + if (mask & SCI_SCREEN_MASK_VISUAL) { + byteCount += pixels + (pixels * _bytesPerDisplayPixel); + } + if (mask & SCI_SCREEN_MASK_PRIORITY) { + byteCount += pixels; + } + if (mask & SCI_SCREEN_MASK_CONTROL) { + byteCount += pixels; + } + return byteCount; +} + +void SciGUIscreen::BitsSave(Common::Rect rect, byte mask, byte *memoryPtr) { + memcpy(memoryPtr, (void *)&rect, sizeof(rect)); memoryPtr += sizeof(rect); + memcpy(memoryPtr, (void *)&mask, sizeof(mask)); memoryPtr += sizeof(mask); + + if (mask & SCI_SCREEN_MASK_VISUAL) { + BitsSaveScreen(rect, _visualScreen, memoryPtr); + BitsSaveScreen(rect, _displayScreen, memoryPtr); + } + if (mask & SCI_SCREEN_MASK_PRIORITY) { + BitsSaveScreen(rect, _priorityScreen, memoryPtr); + } + if (mask & SCI_SCREEN_MASK_CONTROL) { + BitsSaveScreen(rect, _controlScreen, memoryPtr); + } +} + +void SciGUIscreen::BitsSaveScreen(Common::Rect rect, byte *screen, byte *&memoryPtr) { + int width = rect.width(); + int height = rect.height(); + int y; + + screen += (rect.top * _width) + rect.left; + + for (y=rect.top; y<rect.bottom; y++) { + memcpy(memoryPtr, (void*)screen, width); memoryPtr += width; + screen += _width; + } +} + +void SciGUIscreen::BitsRestore(byte *memoryPtr) { + Common::Rect rect; + byte mask; + + memcpy((void *)&rect, memoryPtr, sizeof(rect)); memoryPtr += sizeof(rect); + memcpy((void *)&mask, memoryPtr, sizeof(mask)); memoryPtr += sizeof(mask); + + if (mask & SCI_SCREEN_MASK_VISUAL) { + BitsRestoreScreen(rect, memoryPtr, _visualScreen); + BitsRestoreScreen(rect, memoryPtr, _displayScreen); + } + if (mask & SCI_SCREEN_MASK_PRIORITY) { + BitsRestoreScreen(rect, memoryPtr, _priorityScreen); + } + if (mask & SCI_SCREEN_MASK_CONTROL) { + BitsRestoreScreen(rect, memoryPtr, _controlScreen); + } +} + +void SciGUIscreen::BitsRestoreScreen(Common::Rect rect, byte *&memoryPtr, byte *screen) { + int width = rect.width(); + int height = rect.height(); + int y; + + screen += (rect.top * _width) + rect.left; + + for (y=rect.top; y<rect.bottom; y++) { + memcpy((void*) screen, memoryPtr, width); memoryPtr += width; + screen += _width; + } +} + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_screen.h b/engines/sci/gui/gui_screen.h new file mode 100644 index 0000000000..242948ed8f --- /dev/null +++ b/engines/sci/gui/gui_screen.h @@ -0,0 +1,88 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +namespace Sci { + +#define SCI_SCREEN_MAXHEIGHT 400 + +#define SCI_SCREEN_MASK_VISUAL 1 +#define SCI_SCREEN_MASK_PRIORITY 2 +#define SCI_SCREEN_MASK_CONTROL 4 +#define SCI_SCREEN_MASK_ALL SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY|SCI_SCREEN_MASK_CONTROL +#define SCI_SCREEN_MASK_DITHERED 128 + +class SciGUIscreen { +public: + SciGUIscreen(OSystem *system, EngineState *state); + ~SciGUIscreen(); + + void init(void); + byte *initScreen(uint16 pixelCount); + + void UpdateWhole(); + + byte GetDrawingMask(byte color, byte prio, byte control); + void Put_Pixel(int x, int y, byte drawMask, byte color, byte prio, byte control); + byte Get_Visual(int x, int y); + byte Get_Priority(int x, int y); + byte Get_Control(int x, int y); + byte IsFillMatch(int16 x, int16 y, byte drawMask, byte t_color, byte t_pri, byte t_con); + + int BitsGetDataSize(Common::Rect rect, byte mask); + void BitsSave(Common::Rect rect, byte mask, byte *memoryPtr); + void BitsRestore(byte *memoryPtr); + + sciPalette _sysPalette; + + uint16 _width; + uint16 _height; + uint _pixels; + uint16 _displayWidth; + uint16 _displayHeight; + uint _displayPixels; + byte _bytesPerDisplayPixel; + +private: + void BitsRestoreScreen(Common::Rect rect, byte *&memoryPtr, byte *screen); + void BitsSaveScreen(Common::Rect rect, byte *screen, byte *&memoryPtr); + + OSystem *_system; + EngineState *_s; + + uint16 _baseTable[SCI_SCREEN_MAXHEIGHT]; + uint16 _baseDisplayTable[SCI_SCREEN_MAXHEIGHT]; + + // these screens have the real resolution of the game engine (320x200 for SCI0/SCI1/SCI11 games, 640x480 for SCI2 games) + // SCI0 games will be dithered in here at any time + byte *_visualScreen; + byte *_priorityScreen; + byte *_controlScreen; + + // this screen is the one that is actually displayed to the user. It may be 640x480 for japanese SCI1 games + // SCI0 games may be undithered in here. Only read from this buffer for Save/ShowBits usage. + byte *_displayScreen; +}; + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_view.cpp b/engines/sci/gui/gui_view.cpp new file mode 100644 index 0000000000..0dacfb37d6 --- /dev/null +++ b/engines/sci/gui/gui_view.cpp @@ -0,0 +1,296 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/gui/gui_gfx.h" +#include "sci/gui/gui_screen.h" +#include "sci/gui/gui_view.h" + +namespace Sci { + +SciGUIview::SciGUIview(OSystem *system, EngineState *state, SciGUIgfx *gfx, SciGUIscreen *screen, sciResourceId resourceId) + : _system(system), _s(state), _gfx(gfx), _screen(screen), _resourceId(resourceId) { + assert(resourceId != -1); + initData(resourceId); +} + +SciGUIview::~SciGUIview() { +} + +void SciGUIview::initData(sciResourceId resourceId) { + Resource *viewResource = _s->resMan->findResource(ResourceId(kResourceTypeView, resourceId), false); + if (!viewResource) { + error("view resource %d not found", resourceId); + } + _resourceData = viewResource->data; + + byte *cellData, *loopData; + uint16 cellOffset; + sciViewCellInfo *cell; + uint16 cellCount = 0; + uint16 mirrorBits = 0; + uint16 palOffset = 0; + uint16 headerSize = 0; + uint16 loopSize = 0, cellSize = 0; + int loopNo, cellNo; + int16 version; + byte seekEntry; + + _embeddedPal = false; + _loopCount = 0; + + version = READ_LE_UINT16(_resourceData + 4); + switch (version) { + case 0: // View-format SCI1 + // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... + + // bit 0x8000 of _resourceData[1] means palette is set + _loopCount = _resourceData[0]; + mirrorBits = READ_LE_UINT16(_resourceData + 2); + palOffset = READ_LE_UINT16(_resourceData + 6); + + if (palOffset && palOffset != 0x100) { + _gfx->CreatePaletteFromData(_resourceData + palOffset, &_palette); + _embeddedPal = true; + } + + _loop = new sciViewLoopInfo[_loopCount]; + for (loopNo = 0; loopNo < _loopCount; loopNo++) { + loopData = _resourceData + READ_LE_UINT16(_resourceData + 8 + loopNo * 2); + // CellCount:WORD Unknown:WORD CellOffset0:WORD CellOffset1:WORD... + + cellCount = READ_LE_UINT16(loopData); + _loop[loopNo].cellCount = cellCount; + _loop[loopNo].mirrorFlag = mirrorBits & 1 ? true : false; + mirrorBits >>= 1; + + // read cel info + _loop[loopNo].cell = new sciViewCellInfo[cellCount]; + for (cellNo = 0; cellNo < cellCount; cellNo++) { + cellOffset = READ_LE_UINT16(loopData + 4 + cellNo * 2); + cellData = _resourceData + cellOffset; + + cell = &_loop[loopNo].cell[cellNo]; + cell->width = READ_LE_UINT16(cellData); + cell->height = READ_LE_UINT16(cellData + 2); + cell->displaceX = cellData[4]; + cell->displaceY = cellData[5]; + cell->clearKey = cellData[6]; + cell->offsetRLE = cellOffset + 8; + cell->offsetLiteral = 0; + cell->rawBitmap = 0; + if (_loop[loopNo].mirrorFlag) + cell->displaceX = -cell->displaceX; + } + } + break; + + case 1: // View-format SCI1.1 + // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... + // HeaderSize:WORD LoopCount:WORD Version:WORD Unknown:WORD PaletteOffset:WORD + headerSize = READ_LE_UINT16(_resourceData + 0); + _loopCount = READ_LE_UINT16(_resourceData + 2); + palOffset = READ_LE_UINT16(_resourceData + 8); + + loopData = _resourceData + headerSize; + loopSize = _resourceData[12]; + cellSize = _resourceData[13]; + + if (palOffset) { + _gfx->CreatePaletteFromData(_resourceData + palOffset, &_palette); + _embeddedPal = true; + } + + _loop = new sciViewLoopInfo[_loopCount]; + for (loopNo = 0; loopNo < _loopCount; loopNo++) { + loopData = _resourceData + headerSize + (loopNo * loopSize); + + seekEntry = loopData[2]; + if (seekEntry != 255) { + loopData = _resourceData + headerSize + (seekEntry * loopNo); + } + + cellCount = loopData[4]; + _loop[loopNo].cellCount = cellCount; + _loop[loopNo].mirrorFlag = false; + + cellData = _resourceData + READ_LE_UINT16(loopData + 14); + + // read cel info + _loop[loopNo].cell = new sciViewCellInfo[cellCount]; + for (cellNo = 0; cellNo < cellCount; cellNo++) { + cell = &_loop[loopNo].cell[cellNo]; + cell->width = READ_LE_UINT16(cellData); + cell->height = READ_LE_UINT16(cellData + 2); + cell->displaceX = READ_LE_UINT16(cellData + 4); + cell->displaceY = READ_LE_UINT16(cellData + 6); + cell->clearKey = cellData[8]; + cell->offsetRLE = READ_LE_UINT16(cellData + 24); + cell->offsetLiteral = READ_LE_UINT16(cellData + 28); + cell->rawBitmap = 0; + if (_loop[loopNo].mirrorFlag) + cell->displaceX = -cell->displaceX; + + cellData += cellSize; + } + } + break; + } +} + +sciResourceId SciGUIview::getResourceId() { + return _resourceId; +} + +int16 SciGUIview::getWidth(uint16 loopNo, uint16 cellNo) { + loopNo = CLIP<int16>(loopNo, 0, _loopCount -1); + if (cellNo < 0 || cellNo >= _loop[loopNo].cellCount) + cellNo = 0; + return _loopCount ? _loop[loopNo].cell[cellNo].width : 0; +} + +int16 SciGUIview::getHeight(uint16 loopNo, uint16 cellNo) { + loopNo = CLIP<int16>(loopNo, 0, _loopCount -1); + if (cellNo < 0 || cellNo >= _loop[loopNo].cellCount) + cellNo = 0; + return _loopCount ? _loop[loopNo].cell[cellNo].height : 0; +} + +sciViewCellInfo *SciGUIview::getCellInfo(uint16 loopNo, uint16 cellNo) { + loopNo = CLIP<int16>(loopNo, 0, _loopCount -1); + if (cellNo < 0 || cellNo >= _loop[loopNo].cellCount) + cellNo = 0; + return _loopCount ? &_loop[loopNo].cell[cellNo] : NULL; +} + +void SciGUIview::unpackView(uint16 loopNo, uint16 cellNo, byte *outPtr, uint16 pixelCount) { + byte *rlePtr = _resourceData + _loop[loopNo].cell[cellNo].offsetRLE; + byte *literalPtr = _resourceData + _loop[loopNo].cell[cellNo].offsetLiteral; + uint16 pixelNo = 0, brun; + byte b; + + if (literalPtr == _resourceData) { // no extra literal data + while (pixelNo < pixelCount) { + b = *rlePtr++; + brun = b & 0x3F; // bytes run length on this step + switch (b & 0xC0) { + case 0: // copy bytes as-is + while (brun-- && pixelNo < pixelCount) + outPtr[pixelNo++] = *rlePtr++; + break; + case 0x80: // fill with color + memset(outPtr + pixelNo, *rlePtr++, MIN<uint16>(brun, pixelCount - pixelNo)); + pixelNo += brun; + break; + case 0xC0: // fill with transparent + pixelNo += brun; + break; + } + } + } else { + while (pixelNo < pixelCount) { + b = *rlePtr++; + brun = b & 0x3F; // bytes run length on this step + switch (b & 0xC0) { + case 0: // copy bytes as-is + while (brun-- && pixelNo < pixelCount) + outPtr[pixelNo++] = *literalPtr++; + break; + case 0x80: // fill with color + memset(outPtr + pixelNo, *literalPtr++, MIN<uint16>(brun, pixelCount - pixelNo)); + pixelNo += brun; + break; + case 0xC0: // fill with transparent + pixelNo += brun; + break; + } + } + } +} + +byte *SciGUIview::getBitmap(uint16 loopNo, uint16 cellNo) { + loopNo = CLIP<int16>(loopNo, 0, _loopCount -1); + if (cellNo < 0 || cellNo >= _loop[loopNo].cellCount) + cellNo = 0; + if (_loop[loopNo].cell[cellNo].rawBitmap) + return _loop[loopNo].cell[cellNo].rawBitmap; + + uint16 width = _loop[loopNo].cell[cellNo].width; + uint16 height = _loop[loopNo].cell[cellNo].height; +// byte *ptr = _resourceData + _loop[loopNo].cell[cellNo].offset; + // allocating memory to store cel's bitmap + assert(width * height <= 64000); + uint16 pixelCount = width * height; + _loop[loopNo].cell[cellNo].rawBitmap = new byte[pixelCount]; + byte *pOut = _loop[loopNo].cell[cellNo].rawBitmap; + + memset(pOut, _loop[loopNo].cell[cellNo].clearKey, pixelCount); + //if (g_sci->getPlatform() == Common::kPlatformAmiga) + // unpackViewAmiga(ptr, pOut, pixelCount); + //else + unpackView(loopNo, cellNo, pOut, pixelCount); + + // mirroring the view if needed + if (_loop[loopNo].mirrorFlag) { + for (int i = 0; i < height; i++, pOut += width) + for (int j = 0; j < width / 2; j++) + SWAP(pOut[j], pOut[width - j - 1]); + } + return _loop[loopNo].cell[cellNo].rawBitmap; +} + +void SciGUIview::draw(Common::Rect rect, Common::Rect clipRect, uint16 loopNo, uint16 cellNo, byte priority, uint16 paletteNo) { + sciPalette *palette = _embeddedPal ? &_palette : &_gfx->_sysPalette; + sciViewCellInfo *cellInfo = getCellInfo(loopNo, cellNo); + byte *bitmap = getBitmap(loopNo, cellNo); + int16 cellHeight = cellInfo->height, cellWidth = cellInfo->width; + int16 width, height; + byte clearKey = cellInfo->clearKey; + byte color; + byte drawMask = priority == 255 ? SCI_SCREEN_MASK_VISUAL : SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY; + int x, y; + + // Merge view palette in... + if (_embeddedPal) + _gfx->SetPalette(&_palette, 1); + + width = MIN(clipRect.width(), cellWidth); + height = MIN(clipRect.height(), cellHeight); + + bitmap += (clipRect.top - rect.top) * cellWidth + (clipRect.left - rect.left); + _gfx->OffsetRect(clipRect); + + for (y = clipRect.top; y < clipRect.top + height; y++, bitmap += cellWidth) { + for (x = 0; x < width; x++) { + color = bitmap[x]; + if (color != clearKey && priority >= _screen->Get_Priority(clipRect.left + x, y)) + _screen->Put_Pixel(clipRect.left + x, y, drawMask, palette->mapping[color], priority, 0); + } + } +} + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_view.h b/engines/sci/gui/gui_view.h new file mode 100644 index 0000000000..62ac4a7442 --- /dev/null +++ b/engines/sci/gui/gui_view.h @@ -0,0 +1,77 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +namespace Sci { + +struct sciViewCellInfo { + int16 width, height; + char displaceX; + byte displaceY; + byte clearKey; + uint16 offsetRLE; + uint16 offsetLiteral; + byte *rawBitmap; +}; + +struct sciViewLoopInfo { + bool mirrorFlag; + int16 cellCount; + sciViewCellInfo *cell; +}; + +class SciGUIview { +public: + SciGUIview(OSystem *system, EngineState *state, SciGUIgfx *gfx, SciGUIscreen *screen, sciResourceId resourceId); + ~SciGUIview(); + + // TODO: Remove gfx reference after putting palette things into SciGUIscreen + + sciResourceId getResourceId(); + int16 getWidth(uint16 loopNo, uint16 cellNo); + int16 getHeight(uint16 loopNo, uint16 cellNo); + sciViewCellInfo *getCellInfo(uint16 loop, uint16 cel); + sciViewLoopInfo *getLoopInfo(uint16 loop); + byte *getBitmap(uint16 loopNo, uint16 cellNo); + void draw(Common::Rect rect, Common::Rect clipRect, uint16 loopNo, uint16 cellNo, byte priority, uint16 paletteNo); + +private: + void initData(sciResourceId resourceId); + void unpackView(uint16 loopNo, uint16 cellNo, byte *outPtr, uint16 pixelCount); + + OSystem *_system; + EngineState *_s; + SciGUIgfx *_gfx; + SciGUIscreen *_screen; + + sciResourceId _resourceId; + byte *_resourceData; + + uint16 _loopCount; + sciViewLoopInfo *_loop; + bool _embeddedPal; + sciPalette _palette; +}; + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_windowmgr.cpp b/engines/sci/gui/gui_windowmgr.cpp new file mode 100644 index 0000000000..3a474a1a38 --- /dev/null +++ b/engines/sci/gui/gui_windowmgr.cpp @@ -0,0 +1,326 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/gui/gui_gfx.h" +#include "sci/gui/gui_windowmgr.h" +#include "sci/gui/gui_memmgr.h" + +namespace Sci { + +Common::Rect _picRect(0,10,320, 200); + +// window styles +enum { + TRANSPARENT = 1, + NOFRAME = 2, + TITLE = 4, + TOPMOST = 8, + USER = 0x80 +}; + +SciGUIwindowMgr::SciGUIwindowMgr(EngineState *state, SciGUIgfx *gfx) + : _s(state), _gfx(gfx) { + + // FIXME: remove memmgr + InitMem(0x320); + + HEAPHANDLE wmgrPortH = heapNewPtr(sizeof(sciPort), kDataPort, "wmgrPort"); + heapClearPtr(wmgrPortH); + _wmgrPort = (sciPort *)heap2Ptr(wmgrPortH); + + int16 offTop = 20; + + _gfx->OpenPort(_wmgrPort); + _gfx->SetPort(_wmgrPort); + _gfx->SetOrigin(0, offTop); + _wmgrPort->rect.bottom = 200 - offTop; + _wmgrPort->rect.right = 320; + _wmgrPort->rect.moveTo(0, 0); + _wmgrPort->curTop = 0; + _wmgrPort->curLeft = 0; + + windowList.AddToFront(wmgrPortH); + + _picWind = NewWindow(&_picRect, 0, 0, TRANSPARENT | NOFRAME, 0, 1); +} + +SciGUIwindowMgr::~SciGUIwindowMgr() { +} + +int16 SciGUIwindowMgr::isFrontWindow(sciWnd *pWnd) { + if (heap2Ptr(windowList.getLast()) == (byte *)pWnd) + return 1; + return 0; +} + +void SciGUIwindowMgr::SelectWindow(HEAPHANDLE hh) { + sciPort *port = (sciPort *)heap2Ptr(hh); + _gfx->SetPort(port); + if (hh != windowList.getLast()) { // selecting not topmost window + sciWnd *prevwnd = (sciWnd *)heap2Ptr(port->node.prev); + BeginUpdate(prevwnd); + windowList.MoveToEnd(hh); + EndUpdate(prevwnd); + } + _gfx->SetPort(port); +} + +void SciGUIwindowMgr::BeginUpdate(sciWnd *wnd) { + sciPort *oldPort = _gfx->SetPort(_wmgrPort); + sciWnd *node = (sciWnd *)heap2Ptr(windowList.getLast()); + while (node != wnd) { + UpdateWindow(node); + node = (sciWnd *)heap2Ptr(node->node.prev); + } + _gfx->SetPort(oldPort); +} + +void SciGUIwindowMgr::EndUpdate(sciWnd *wnd) { + sciPort *oldPort = _gfx->SetPort(_wmgrPort); + sciWnd *last = (sciWnd *)heap2Ptr(windowList.getLast()); + while (wnd != last) { + wnd = (sciWnd *)heap2Ptr(wnd->node.next); + UpdateWindow(wnd); + } + _gfx->SetPort(oldPort); +} + +SCILanguage SciGUIwindowMgr::getSCILanguage() { + return kLangEnglish; +} + +char *SciGUIwindowMgr::StrSplit(char *buff, const char *msg, const char *fmt) { + SCILanguage gameLang = getSCILanguage(); + SCILanguage subtitleLang = kLangNone; + char *retval; +// if (_theGame.getHandle()) + //subtitleLang = (SCILanguage)_theGame.getProperty(0x58); // subtitleLang property + + if (buff == msg) { + char str[2000]; + getIntlString(str, msg, fmt, gameLang, subtitleLang); + retval = strcpy(buff, str); + } else + retval = getIntlString(buff, msg, fmt, gameLang, subtitleLang); + return retval; +} +//-------------------------------- +// In multilanguage game the msg has format ___english_text__#I___italian_text___ +// The function should place in buff a translated part of msg or the 1st one if a translation +// does not exist +char *SciGUIwindowMgr::getIntlString(char *buff, const char *msg, const char *fmt, + SCILanguage gameLang, SCILanguage subtitleLang) { + + // prefer subtitleLang if set + SCILanguage lang = subtitleLang != kLangNone ? subtitleLang : gameLang; + const char *ptr = msg, *szFrom; + char ch; + int nLen = 0; + // searching for language code in msg + while (*ptr) { + ch = *(ptr + 1); + if(*ptr == '#' && (ch == 'I' || ch == 'F' || ch == 'G' || ch == 'S')) { + ptr +=2; + break; + } + ptr++; + } + // if a language code was found... + if (*ptr) { + if ((lang == kLangItalian && ch == 'I') || (lang == kLangFrench && ch == 'F') || + (lang == kLangGerman && ch == 'G') || (lang == kLangSpanish && ch == 'S')) { + nLen = (int)strlen(ptr); + szFrom = ptr; + } else { + nLen = ptr - msg - 2; + szFrom = msg; + } + } else { + nLen = ptr - msg; + szFrom = msg; + } + if (fmt && subtitleLang != kLangNone) { + strcpy(buff, fmt); + strncat(buff, szFrom, nLen); + buff[nLen + strlen(fmt)] = 0; + } else { + strncpy(buff, szFrom, nLen); + buff[nLen] = 0; + } + return buff; +} + +sciWnd *SciGUIwindowMgr::NewWindow(Common::Rect *rect, Common::Rect *rect2, const char *title, uint16 style, uint16 arg8, uint16 argA) { + HEAPHANDLE hWnd = heapNewPtr(sizeof(sciWnd), kDataWindow, title); + Common::Rect r; + + if (!hWnd) { + warning("Can't open window!"); + return 0; + } + heapClearPtr(hWnd); + if (style & TOPMOST) + windowList.AddToFront(hWnd); + else + windowList.AddToEnd(hWnd); + sciWnd *pwnd = (sciWnd *)heap2Ptr(hWnd); + _gfx->OpenPort((sciPort *)pwnd); + r = *rect; + pwnd->rect = *rect; + if (rect2) + pwnd->rect1 = *rect2; + + pwnd->wndStyle = style; + pwnd->hSaved1 = pwnd->hSaved2 = NULL_REG; + pwnd->bDrawed = false; + if ((style & TRANSPARENT) == 0) + pwnd->uSaveFlag = (arg8 == 0xFFFF ? 1 : 3); + + if (title && (style & TITLE)) { + HEAPHANDLE hTitle = heapNewPtr((uint16)strlen(title) + 1, kDataString, title); + if (!hTitle) { + warning("Can't open window!"); + return 0; + } + pwnd->hTitle = hTitle; + StrSplit((char *)heap2Ptr(hTitle), title, NULL); + } + + r = *rect; + if (style == USER || (style & NOFRAME) == 0) { + r.grow(1); + if (style & TITLE) { + r.top -= 10; + r.bottom++; + } + } + + pwnd->rect0 = r; + const Common::Rect *wmprect = &_wmgrPort->rect; + int16 oldtop = pwnd->rect0.top; + int16 oldleft = pwnd->rect0.left; + if (wmprect->top > pwnd->rect0.top) + pwnd->rect0.moveTo(pwnd->rect0.left, wmprect->top); + + if (wmprect->bottom < pwnd->rect0.bottom) + pwnd->rect0.moveTo(pwnd->rect0.left, wmprect->bottom + - pwnd->rect0.bottom + pwnd->rect0.top); + + if (wmprect->right < pwnd->rect0.right) + pwnd->rect0.moveTo(wmprect->right + pwnd->rect0.left + - pwnd->rect0.right, pwnd->rect0.top); + + if (wmprect->left > pwnd->rect0.left) + pwnd->rect0.moveTo(wmprect->left, pwnd->rect0.top); + + pwnd->rect.moveTo(pwnd->rect.left + pwnd->rect0.left - oldleft, + pwnd->rect.top + pwnd->rect0.top - oldtop); + if (rect2 == 0) + pwnd->rect1 = pwnd->rect0; + + if (argA) + DrawWindow(pwnd); + _gfx->SetPort((sciPort *)pwnd); + _gfx->SetOrigin(pwnd->rect.left, pwnd->rect.top + _wmgrPort->top); + pwnd->rect.moveTo(0, 0); + return pwnd; +} + +void SciGUIwindowMgr::DrawWindow(sciWnd *pWnd) { + if (pWnd->bDrawed) + return; + Common::Rect r; + int16 wndStyle = pWnd->wndStyle; + + pWnd->bDrawed = true; + sciPort *oldport = _gfx->SetPort(_wmgrPort); + _gfx->PenColor(0); + if ((wndStyle & TRANSPARENT) == 0) { + pWnd->hSaved1 = _gfx->SaveBits(pWnd->rect1, 1); + if (pWnd->uSaveFlag & 2) { + pWnd->hSaved2 = _gfx->SaveBits(pWnd->rect1, 2); + if ((wndStyle & USER) == 0) + _gfx->FillRect(pWnd->rect1, 2, 0, 0xF); + } + } + + // drawing frame,shadow and title + if ((wndStyle & USER) == 0) { + r = pWnd->rect0; + if ((wndStyle & NOFRAME) == 0) { + r.translate(1, 1); + _gfx->FrameRect(r);// shadow + r.translate(-1, -1); + _gfx->FrameRect(r);// window frame + if (wndStyle & TITLE) { + _gfx->FrameRect(r); + r.grow(-1); + _gfx->FillRect(r, 1, 0); + if (pWnd->hTitle) { + int16 oldcolor = _gfx->GetPort()->penClr; + _gfx->PenColor(255); + _gfx->TextBox((char *)heap2Ptr(pWnd->hTitle), 1, r, 1, 0); + _gfx->PenColor(oldcolor); + } + + r = pWnd->rect0; + r.top += 9; + } + + r.grow(-1); + } + + if ((wndStyle & TRANSPARENT) == 0) + _gfx->FillRect(r, 1, pWnd->backClr); + _gfx->ShowBits(pWnd->rect0, 1); + } + _gfx->SetPort(oldport); +} + +void SciGUIwindowMgr::DisposeWindow(sciWnd *pWnd, int16 arg2) { + _gfx->SetPort(_wmgrPort); + _gfx->RestoreBits(pWnd->hSaved1); + _gfx->RestoreBits(pWnd->hSaved2); + if (arg2) + _gfx->ShowBits(pWnd->rect0, 1); +// else +// g_sci->ReAnimate(&pwnd->rect0); + HEAPHANDLE hh = ptr2heap((byte *)pWnd); + windowList.DeleteNode(hh); + SelectWindow(windowList.getLast()); + if (pWnd->hTitle) + heapDisposePtr(pWnd->hTitle); + heapDisposePtr(hh); +} + +void SciGUIwindowMgr::UpdateWindow(sciWnd *wnd) { +} + +} // end of namespace Sci diff --git a/engines/sci/gui/gui_windowmgr.h b/engines/sci/gui/gui_windowmgr.h new file mode 100644 index 0000000000..bc7ea47c20 --- /dev/null +++ b/engines/sci/gui/gui_windowmgr.h @@ -0,0 +1,57 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/gui/gui_dbllist.h" + +namespace Sci { + +class SciGUIwindowMgr { +public: + SciGUIwindowMgr(EngineState *state, SciGUIgfx *gfx); + ~SciGUIwindowMgr(); + + int16 isFrontWindow(sciWnd *wnd); + void SelectWindow(HEAPHANDLE hh); + void BeginUpdate(sciWnd *wnd); + void EndUpdate(sciWnd *wnd); + SCILanguage getSCILanguage(); + char* StrSplit(char*buff, const char*msg, const char*fmt); + char* getIntlString(char*buff, const char*msg, const char*fmt, SCILanguage lang, SCILanguage prop); + sciWnd *NewWindow(Common::Rect *rect, Common::Rect *rect2, const char *title, uint16 style, uint16 arg8, uint16 argA); + void DrawWindow(sciWnd *wnd); + void DisposeWindow(sciWnd *pWnd, int16 arg2); + void UpdateWindow(sciWnd *wnd); + + sciPort *_wmgrPort; + sciWnd *_picWind; + +private: + EngineState *_s; + SciGUIgfx *_gfx; + + DblList windowList; +}; + +} // end of namespace Sci diff --git a/engines/sci/gui32/gui32.cpp b/engines/sci/gui32/gui32.cpp new file mode 100644 index 0000000000..5205d7fe30 --- /dev/null +++ b/engines/sci/gui32/gui32.cpp @@ -0,0 +1,732 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/tools.h" +#include "sci/debug.h" // for g_debug_sleeptime_factor +#include "sci/resource.h" +#include "sci/engine/state.h" +#include "sci/engine/kernel.h" +#include "sci/gfx/gfx_gui.h" +#include "sci/gfx/gfx_widgets.h" +#include "sci/gfx/gfx_state_internal.h" // required for GfxContainer, GfxPort, GfxVisual +#include "sci/gui32/gui32.h" + +// This is the real width of a text with a specified width of 0 +#define MAX_TEXT_WIDTH_MAGIC_VALUE 192 + +#define ADD_TO_CURRENT_PORT(widget) \ + {if (s->port) \ + s->port->add((GfxContainer *)s->port, widget); \ + else \ + s->picture_port->add((GfxContainer *)s->visual, widget);} + +#define ADD_TO_CURRENT_PICTURE_PORT(widget) \ + {if (s->port) \ + s->port->add((GfxContainer *)s->port, widget); \ + else \ + s->picture_port->add((GfxContainer *)s->picture_port, widget);} + +#define ADD_TO_WINDOW_PORT(widget) \ + s->wm_port->add((GfxContainer *)s->wm_port, widget); + +#define FULL_REDRAW()\ + if (s->visual) \ + s->visual->draw(gfxw_point_zero); \ + gfxop_update(s->gfx_state); + +#define K_DRAWPIC_FLAG_MIRRORED (1 << 14) + +namespace Sci { + +SciGUI32::SciGUI32(OSystem *system, EngineState *state) + : _system(system), s(state) { +} + +SciGUI32::~SciGUI32() { +} + +void SciGUI32::init(bool oldGfxFunctions) { + _usesOldGfxFunctions = oldGfxFunctions; + activated_icon_bar = false; + port_origin_x = 0; + port_origin_y = 0; +} + +int16 SciGUI32::getTimeTicks() { + uint32 start_time; + start_time = _system->getMillis() - s->game_start_time; + return start_time * 60 / 1000; +} + +void SciGUI32::wait(int16 ticks) { + uint32 time; + + time = g_system->getMillis(); + s->r_acc = make_reg(0, ((long)time - (long)s->last_wait_time) * 60 / 1000); + s->last_wait_time = time; + + ticks *= g_debug_sleeptime_factor; + gfxop_sleep(s->gfx_state, ticks * 1000 / 60); + + + // Reset speed throttler: Game is playing along nicely anyway + if (ticks > 0) + s->speedThrottler->reset(); +} + +void SciGUI32::setPort(uint16 portPtr) { + GfxPort *new_port; + + /* We depart from official semantics here, sorry! + Reasoning: Sierra SCI does not clip ports while we do. + Therefore a draw to the titlebar port (which is the + official semantics) would cut off the lower part of the + icons in an SCI1 icon bar. Instead we have an + iconbar_port that does not exist in SSCI. */ + if (portPtr == 65535) portPtr = s->iconbar_port->_ID; + + new_port = s->visual->getPort(portPtr); + + if (!new_port) { + warning("Invalid port %04x requested", portPtr); + return; + } + + s->port->draw(gfxw_point_zero); // Update the port we're leaving + s->port = new_port; +} + +void SciGUI32::setPortPic(Common::Rect rect, int16 picTop, int16 picLeft) { + if (activated_icon_bar) { + port_origin_x = port_origin_y = 0; + activated_icon_bar = false; + return; + } + port_origin_y = rect.top; + port_origin_x = rect.left; + + if (rect.top == -10) { + s->port->draw(gfxw_point_zero); // Update the port we're leaving + s->port = s->iconbar_port; + activated_icon_bar = true; + return; + } + + // Notify the graphics resource manager that the pic port bounds changed + s->gfx_state->gfxResMan->changePortBounds(picLeft, picTop, rect.right + picLeft, rect.bottom + picTop); + + // LSL6 calls kSetPort to extend the screen to draw the GUI. If we free all resources + // here, the background picture is freed too, and this makes everything a big mess. + // FIXME/TODO: This code really needs to be rewritten to conform to the original behavior + if (s->_gameName != "lsl6") { + s->gfx_state->pic_port_bounds = gfx_rect(picLeft, picTop, rect.right, rect.bottom); + + // FIXME: Should really only invalidate all loaded pic resources here; + // this is overkill + s->gfx_state->gfxResMan->freeAllResources(); + } else { + // WORKAROUND for LSL6 + warning("SetPort case 6 called in LSL6."); + } +} + +reg_t SciGUI32::getPort() { + return make_reg(0, s->port->_ID); +} + +void SciGUI32::globalToLocal(int16 *x, int16 *y) { + *x = *x - s->port->zone.x; + *y = *y - s->port->zone.y; +} + +void SciGUI32::localToGlobal(int16 *x, int16 *y) { + *x = *x + s->port->zone.x; + *y = *y + s->port->zone.y; +} + +reg_t SciGUI32::newWindow(Common::Rect rect1, Common::Rect rect2, uint16 style, int16 priority, int16 colorPen, int16 colorBack, const char *title) { + GfxPort *window; + int x, y, xl, yl; + gfx_color_t bgcolor; + gfx_color_t fgcolor; + gfx_color_t black; + gfx_color_t lWhite; + + y = rect1.top; + x = rect1.left; + yl = rect1.height(); + xl = rect1.width(); + + y += s->wm_port->_bounds.y; + + if (x + xl > 319) + x -= ((x + xl) - 319); + + bgcolor.mask = 0; + + if (colorBack >= 0) { + if (!s->resMan->isVGA()) + bgcolor.visual = get_pic_color(s, MIN<int>(colorBack, 15)); + else + bgcolor.visual = get_pic_color(s, colorBack); + bgcolor.mask = GFX_MASK_VISUAL; + } else { + bgcolor.visual = PaletteEntry(0,0,0); + } + + bgcolor.priority = priority; + bgcolor.mask |= priority >= 0 ? GFX_MASK_PRIORITY : 0; + bgcolor.alpha = 0; + bgcolor.control = -1; + debugC(2, kDebugLevelGraphics, "New window with params %d, %d, %d, %d\n", rect1.top, rect1.left, rect1.height(), rect1.width()); + + fgcolor.visual = get_pic_color(s, colorPen); + fgcolor.mask = GFX_MASK_VISUAL; + fgcolor.control = -1; + fgcolor.priority = -1; + fgcolor.alpha = 0; + black.visual = get_pic_color(s, 0); + black.mask = GFX_MASK_VISUAL; + black.alpha = 0; + black.control = -1; + black.priority = -1; + lWhite.visual = get_pic_color(s, !s->resMan->isVGA() ? 15 : 255); + lWhite.mask = GFX_MASK_VISUAL; + lWhite.alpha = 0; + lWhite.priority = -1; + lWhite.control = -1; + + window = sciw_new_window(s, gfx_rect(x, y, xl, yl), s->titlebar_port->_font, fgcolor, bgcolor, + s->titlebar_port->_font, lWhite, black, title ? s->strSplit(title, NULL).c_str() : NULL, style); + + // PQ3 and SCI1.1 games have the interpreter store underBits implicitly + if (rect2.top != 0 && rect2.left != 0 && rect2.height() != 0 && rect2.width() != 0) + gfxw_port_auto_restore_background(s->visual, window, gfx_rect(rect2.left, rect2.top + s->wm_port->_bounds.y, rect2.width(), rect2.height())); + + ADD_TO_WINDOW_PORT(window); + FULL_REDRAW(); + + window->draw(gfxw_point_zero); + gfxop_update(s->gfx_state); + + s->port = window; // Set active port + + return make_reg(0, window->_ID); +} + +void SciGUI32::disposeWindow(uint16 windowPtr, int16 arg2) { + GfxPort *goner; + GfxPort *pred; + + goner = s->visual->getPort(windowPtr); + if ((windowPtr < 3) || (goner == NULL)) { + error("Removal of invalid window %04x requested", windowPtr); + return; + } + + if (s->dyn_views && (GfxContainer *)s->dyn_views->_parent == (GfxContainer *)goner) { + reparentize_primary_widget_lists(s, (GfxPort *) goner->_parent); + } + + if (s->drop_views && (GfxContainer *)s->drop_views->_parent == (GfxContainer *)goner) + s->drop_views = NULL; // Kill it + + pred = gfxw_remove_port(s->visual, goner); + + if (goner == s->port) // Did we kill the active port? + s->port = pred; + + // Find the last port that exists and that isn't marked no-switch + int id = s->visual->_portRefs.size() - 1; + while (id > 0 && (!s->visual->_portRefs[id] || (s->visual->_portRefs[id]->_flags & GFXW_FLAG_NO_IMPLICIT_SWITCH))) + id--; + + debugC(2, kDebugLevelGraphics, "Activating port %d after disposing window %d\n", id, windowPtr); + s->port = (id >= 0) ? s->visual->_portRefs[id] : 0; + + if (!s->port) + s->port = gfxw_find_default_port(s->visual); + + gfxop_update(s->gfx_state); +} + +#define K_DISPLAY_SET_COORDS 100 +#define K_DISPLAY_SET_ALIGNMENT 101 +#define K_DISPLAY_SET_COLOR 102 +#define K_DISPLAY_SET_BGCOLOR 103 +#define K_DISPLAY_SET_GRAYTEXT 104 +#define K_DISPLAY_SET_FONT 105 +#define K_DISPLAY_WIDTH 106 +#define K_DISPLAY_SAVE_UNDER 107 +#define K_DISPLAY_RESTORE_UNDER 108 +#define K_DONT_UPDATE_IMMEDIATELY 121 + +void SciGUI32::display(const char *text, int argc, reg_t *argv) { + int argpt = 0; + int temp; + bool save_under = false; + gfx_color_t transparent = { PaletteEntry(), 0, -1, -1, 0 }; + GfxPort *port = (s->port) ? s->port : s->picture_port; + bool update_immediately = true; + + gfx_color_t color0, *color1, bg_color; + gfx_alignment_t halign = ALIGN_LEFT; + rect_t area = gfx_rect(port->draw_pos.x, port->draw_pos.y, 320 - port->draw_pos.x, 200 - port->draw_pos.y); + int gray = port->gray_text; + int font_nr = port->_font; + GfxText *text_handle; + + color0 = port->_color; + bg_color = port->_bgcolor; + // TODO: in SCI1VGA the default colors for text and background are #0 (black) + // SCI0 case should be checked + if (s->resMan->isVGA()) { + // This priority check fixes the colors in the menus in KQ5 + // TODO/FIXME: Is this correct? + if (color0.priority >= 0) + color0.visual = get_pic_color(s, 0); + if (bg_color.priority >= 0) + bg_color.visual = get_pic_color(s, 0); + } + + while (argpt < argc) { + switch (argv[argpt++].toUint16()) { + + case K_DISPLAY_SET_COORDS: + + area.x = argv[argpt++].toUint16(); + area.y = argv[argpt++].toUint16(); + debugC(2, kDebugLevelGraphics, "Display: set_coords(%d, %d)\n", area.x, area.y); + break; + + case K_DISPLAY_SET_ALIGNMENT: + + halign = (gfx_alignment_t)argv[argpt++].toSint16(); + debugC(2, kDebugLevelGraphics, "Display: set_align(%d)\n", halign); + break; + + case K_DISPLAY_SET_COLOR: + + temp = argv[argpt++].toSint16(); + debugC(2, kDebugLevelGraphics, "Display: set_color(%d)\n", temp); + if (!s->resMan->isVGA() && temp >= 0 && temp <= 15) + color0 = (s->ega_colors[temp]); + else + if (s->resMan->isVGA() && temp >= 0 && temp < 256) { + color0.visual = get_pic_color(s, temp); + color0.mask = GFX_MASK_VISUAL; + } else + if (temp == -1) + color0 = transparent; + else + warning("Display: Attempt to set invalid fg color %d", temp); + break; + + case K_DISPLAY_SET_BGCOLOR: + + temp = argv[argpt++].toSint16(); + debugC(2, kDebugLevelGraphics, "Display: set_bg_color(%d)\n", temp); + if (!s->resMan->isVGA() && temp >= 0 && temp <= 15) + bg_color = s->ega_colors[temp]; + else + if (s->resMan->isVGA() && temp >= 0 && temp <= 256) { + bg_color.visual = get_pic_color(s, temp); + bg_color.mask = GFX_MASK_VISUAL; + } else + if (temp == -1) + bg_color = transparent; + else + warning("Display: Attempt to set invalid fg color %d", temp); + break; + + case K_DISPLAY_SET_GRAYTEXT: + + gray = argv[argpt++].toSint16(); + debugC(2, kDebugLevelGraphics, "Display: set_graytext(%d)\n", gray); + break; + + case K_DISPLAY_SET_FONT: + + font_nr = argv[argpt++].toUint16(); + + debugC(2, kDebugLevelGraphics, "Display: set_font(\"font.%03d\")\n", font_nr); + break; + + case K_DISPLAY_WIDTH: + + area.width = argv[argpt++].toUint16(); + if (area.width == 0) + area.width = MAX_TEXT_WIDTH_MAGIC_VALUE; + + debugC(2, kDebugLevelGraphics, "Display: set_width(%d)\n", area.width); + break; + + case K_DISPLAY_SAVE_UNDER: + + save_under = true; + debugC(2, kDebugLevelGraphics, "Display: set_save_under()\n"); + break; + + case K_DISPLAY_RESTORE_UNDER: + + debugC(2, kDebugLevelGraphics, "Display: restore_under(%04x)\n", argv[argpt].toUint16()); + graph_restore_box(s, argv[argpt++]); + update_immediately = true; + argpt++; + return; + + case K_DONT_UPDATE_IMMEDIATELY: + + update_immediately = false; + debugC(2, kDebugLevelGraphics, "Display: set_dont_update()\n"); + argpt++; + break; + + default: + debugC(2, kDebugLevelGraphics, "Unknown Display() command %x\n", argv[argpt - 1].toUint16()); + return; + } + } + + if (halign == ALIGN_LEFT) { + // If the text does not fit on the screen, move it to the left and upwards until it does + gfxop_get_text_params(s->gfx_state, font_nr, text, area.width, &area.width, &area.height, 0, NULL, NULL, NULL); + + // Make the text fit on the screen + if (area.x + area.width > 320) + area.x += 320 - area.x - area.width; // Plus negative number = subtraction + + if (area.y + area.height > 200) + area.y += 200 - area.y - area.height; // Plus negative number = subtraction + } else { + // If the text does not fit on the screen, clip it till it does + if (area.x + area.width > s->gfx_state->pic_port_bounds.width) + area.width = s->gfx_state->pic_port_bounds.width - area.x; + + if (area.y + area.height > s->gfx_state->pic_port_bounds.height) + area.height = s->gfx_state->pic_port_bounds.height - area.y; + } + + if (gray) + color1 = &bg_color; + else + color1 = &color0; + + assert_primary_widget_lists(s); + + text_handle = gfxw_new_text(s->gfx_state, area, font_nr, s->strSplit(text).c_str(), halign, ALIGN_TOP, color0, *color1, bg_color, 0); + + if (!text_handle) { + error("Display: Failed to create text widget"); + return; + } + + if (save_under) { // Backup + rect_t save_area = text_handle->_bounds; + save_area.x += port->_bounds.x; + save_area.y += port->_bounds.y; + + s->r_acc = graph_save_box(s, save_area); + text_handle->_serial++; // This is evil! + + debugC(2, kDebugLevelGraphics, "Saving (%d, %d) size (%d, %d) as %04x:%04x\n", save_area.x, save_area.y, save_area.width, save_area.height, PRINT_REG(s->r_acc)); + } + + debugC(2, kDebugLevelGraphics, "Display: Commiting text '%s'\n", text); + + //ADD_TO_CURRENT_PICTURE_PORT(text_handle); + + ADD_TO_CURRENT_PICTURE_PORT(text_handle); + if ((!s->pic_not_valid) && update_immediately) { // Refresh if drawn to valid picture + FULL_REDRAW(); + debugC(2, kDebugLevelGraphics, "Refreshing display...\n"); + } +} + +void SciGUI32::textSize(const char *text, int16 fontId, int16 maxWidth, int16 *textWidth, int16 *textHeight) { + int width, height; + if (maxWidth < 0) + maxWidth = 0; + gfxop_get_text_params(s->gfx_state, fontId, text, maxWidth ? maxWidth : MAX_TEXT_WIDTH_MAGIC_VALUE, + &width, &height, 0, NULL, NULL, NULL); + *textWidth = width; *textHeight = height; +} + +void SciGUI32::textFonts(int argc, reg_t *argv) { + // stub +} + +void SciGUI32::textColors(int argc, reg_t *argv) { + // stub +} + +void SciGUI32::drawPicture(sciResourceId pictureId, uint16 showStyle, uint16 flags, int16 EGApaletteNo) { + drawn_pic_t dp; + gfx_color_t transparent = s->wm_port->_bgcolor; + int picFlags = DRAWPIC01_FLAG_FILL_NORMALLY; + bool add_to_pic = flags; + + dp.nr = pictureId; + if (EGApaletteNo != -1) { + dp.palette = EGApaletteNo; + } else { + dp.palette = 0; + } + + if (showStyle & K_DRAWPIC_FLAG_MIRRORED) + picFlags |= DRAWPIC1_FLAG_MIRRORED; + + gfxop_disable_dirty_frames(s->gfx_state); + + if (NULL != s->old_screen) { + gfxop_free_pixmap(s->gfx_state, s->old_screen); + } + + s->old_screen = gfxop_grab_pixmap(s->gfx_state, gfx_rect(0, 10, 320, 190)); + + debugC(2, kDebugLevelGraphics, "Drawing pic.%03d\n", pictureId); + if (add_to_pic) { + gfxop_add_to_pic(s->gfx_state, dp.nr, picFlags, dp.palette); + } else { + gfxop_new_pic(s->gfx_state, dp.nr, picFlags, dp.palette); + } + + delete s->wm_port; + delete s->picture_port; + delete s->iconbar_port; + + s->wm_port = new GfxPort(s->visual, s->gfx_state->pic_port_bounds, s->ega_colors[0], transparent); + s->picture_port = new GfxPort(s->visual, s->gfx_state->pic_port_bounds, s->ega_colors[0], transparent); + + s->iconbar_port = new GfxPort(s->visual, gfx_rect(0, 0, 320, 200), s->ega_colors[0], transparent); + s->iconbar_port->_flags |= GFXW_FLAG_NO_IMPLICIT_SWITCH; + + s->visual->add((GfxContainer *)s->visual, s->picture_port); + s->visual->add((GfxContainer *)s->visual, s->wm_port); + s->visual->add((GfxContainer *)s->visual, s->iconbar_port); + + s->port = s->picture_port; + + s->pic_priority_table = gfxop_get_pic_metainfo(s->gfx_state); + + s->pic_animate = showStyle & 0xff; // The animation used during kAnimate() later on + + s->dyn_views = NULL; + s->drop_views = NULL; + + s->priority_first = 42; + + if (_usesOldGfxFunctions) + s->priority_last = 200; + else + s->priority_last = 190; + + s->pic_not_valid = 1; + s->pic_is_new = 1; +} + +void SciGUI32::drawCell(sciResourceId viewId, uint16 loopNo, uint16 cellNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo) { + int loop = loopNo; + int cel = cellNo; + GfxView *new_view; + + gfxop_check_cel(s->gfx_state, viewId, &loop, &cel); + + debugC(2, kDebugLevelGraphics, "DrawCel((%d,%d), (view.%d, %d, %d), p=%d)\n", leftPos, topPos, viewId, loop, cel, priority); + + new_view = gfxw_new_view(s->gfx_state, Common::Point(leftPos, topPos), viewId, loop, cel, 0, priority, -1, + ALIGN_LEFT, ALIGN_TOP, GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET); + + ADD_TO_CURRENT_PICTURE_PORT(new_view); + FULL_REDRAW(); +} + +void SciGUI32::drawControlButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool inverse) { + rect_t area = gfx_rect(rect.left, rect.top, rect.width(), rect.height()); + + ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, text, fontId, + (int8)(style & kControlStateFramed), (int8)inverse, (int8)(style & kControlStateDisabled))); + if (!s->pic_not_valid) FULL_REDRAW(); +} + +void SciGUI32::drawControlText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, bool inverse) { + rect_t area = gfx_rect(rect.left, rect.top, rect.width(), rect.height()); + + ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, text, fontId, (gfx_alignment_t) mode, + (int8)(!!(style & kControlStateDitherFramed)), (int8)inverse)); + if (!s->pic_not_valid) FULL_REDRAW(); +} + +static gfx_color_t graph_map_color(EngineState *s, int color, int priority, int control) { + gfx_color_t retval; + + if (!s->resMan->isVGA()) { + retval = s->ega_colors[(color >=0 && color < 16)? color : 0]; + gfxop_set_color(s->gfx_state, &retval, (color < 0) ? -1 : retval.visual.r, retval.visual.g, retval.visual.b, + (color == -1) ? 255 : 0, priority, control); + } else { + retval.visual = get_pic_color(s, color); + retval.alpha = 0; + retval.priority = priority; + retval.control = control; + retval.mask = GFX_MASK_VISUAL | ((priority >= 0) ? GFX_MASK_PRIORITY : 0) | ((control >= 0) ? GFX_MASK_CONTROL : 0); + }; + + return retval; +} + +void _k_graph_rebuild_port_with_color(EngineState *s, gfx_color_t newbgcolor) { + GfxPort *port = s->port; + GfxPort *newport; + + newport = sciw_new_window(s, port->zone, port->_font, port->_color, newbgcolor, + s->titlebar_port->_font, s->ega_colors[15], s->ega_colors[8], + port->_title_text.c_str(), port->port_flags & ~kWindowTransparent); + + if (s->dyn_views) { + int found = 0; + GfxContainer *parent = s->dyn_views->_parent; + + while (parent && !(found |= (parent == port))) + parent = parent->_parent; + + s->dyn_views = NULL; + } + + port->_parent->add((GfxContainer *)port->_parent, newport); + delete port; +} + +void SciGUI32::graphFillBoxForeground(Common::Rect rect) { + _k_graph_rebuild_port_with_color(s, s->port->_color); + //port = _s->port; + + FULL_REDRAW(); +} + +void SciGUI32::graphFillBoxBackground(Common::Rect rect) { + _k_graph_rebuild_port_with_color(s, s->port->_bgcolor); + //port = _s->port; + + FULL_REDRAW(); +} + +void SciGUI32::graphFillBox(Common::Rect rect, uint16 colorMask, int16 color, int16 priority, int16 control) { + gfx_color_t fillColor = graph_map_color(s, color, priority, control); + fillColor.mask = (byte)colorMask; + rect_t area = gfx_rect(rect.left, rect.top, rect.width(), rect.height()); + + //debugC(2, kDebugLevelGraphics, "fill_box_any((%d, %d), (%d, %d), col=%d, p=%d, c=%d, mask=%d)\n", + // argv[2].toSint16(), argv[1].toSint16(), argv[4].toSint16(), argv[3].toSint16(), argv[6].toSint16(), priority, control, argv[5].toUint16()); + + // FIXME/TODO: this is not right, as some of the dialogs are drawn *behind* some widgets. But at least it works for now + //ADD_TO_CURRENT_PICTURE_PORT(gfxw_new_box(s->gfx_state, area, color, color, GFX_BOX_SHADE_FLAT)); // old code + + // FillBox seems to be meant again s->port instead of s->picture_port, at least in QfG3 +// warning("Fillbox"); +// ADD_TO_CURRENT_PICTURE_PORT(gfxw_new_box(s->gfx_state, area, color, color, GFX_BOX_SHADE_FLAT)); + s->picture_port->add((GfxContainer *)s->picture_port, gfxw_new_box(s->gfx_state, area, fillColor, fillColor, GFX_BOX_SHADE_FLAT)); +} + +void SciGUI32::graphDrawLine(Common::Rect rect, int16 color, int16 priority, int16 control) { + gfx_color_t gfxcolor = graph_map_color(s, color, priority, control); + + debugC(2, kDebugLevelGraphics, "draw_line((%d, %d), (%d, %d), col=%d, p=%d, c=%d, mask=%d)\n", + rect.left, rect.top, rect.right, rect.bottom, color, priority, control, gfxcolor.mask); + + // Note: it's quite possible that the coordinates of the line will *not* form a valid rectangle (e.g. it might + // have negative width/height). The actual dirty rectangle is constructed in gfxdr_add_dirty(). + // FIXME/TODO: We need to change the semantics of this call, so that no fake rectangles are used. As it is, it's + // not possible change rect_t to Common::Rect, as we assume that Common::Rect forms a *valid* rectangle. + ADD_TO_CURRENT_PICTURE_PORT(gfxw_new_line(Common::Point(rect.left, rect.top), Common::Point(rect.right, rect.bottom), + gfxcolor, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL)); + FULL_REDRAW(); +} + +reg_t SciGUI32::graphSaveBox(Common::Rect rect, uint16 flags) { + rect_t area; + area.x = rect.left + s->port->zone.x + port_origin_x; + area.y = rect.top + s->port->zone.y + port_origin_y; + area.width = rect.width() - port_origin_x; + area.height = rect.height() - port_origin_y; + + return graph_save_box(s, area); +} + +void SciGUI32::graphRestoreBox(reg_t handle) { + graph_restore_box(s, handle); +} + +void SciGUI32::paletteSet(int resourceNo, int flags) { + //warning("STUB"); +} + +int16 SciGUI32::paletteFind(int r, int g, int b) { + int i, delta, bestindex = -1, bestdelta = 200000; + + for (i = 0; i < s->gfx_state->gfxResMan->getColorCount(); i++) { + int dr = abs(s->gfx_state->gfxResMan->getColor(i).r - r); + int dg = abs(s->gfx_state->gfxResMan->getColor(i).g - g); + int db = abs(s->gfx_state->gfxResMan->getColor(i).b - b); + + delta = dr * dr + dg * dg + db * db; + + if (delta < bestdelta) { + bestdelta = delta; + bestindex = i; + } + } + // Don't warn about inexact mappings -- it's actually the + // rule rather than the exception + return bestindex; +} + +void SciGUI32::paletteAnimate(int fromColor, int toColor, int speed) { + warning("STUB"); +} + +void SciGUI32::moveCursor(int16 x, int16 y) { + Common::Point newPos; + + // newPos = s->gfx_state->pointer_pos; + + newPos.x = x + s->port->zone.x; + newPos.y = y + s->port->zone.y; + + if (newPos.x > s->port->zone.x + s->port->zone.width) + newPos.x = s->port->zone.x + s->port->zone.width; + if (newPos.y > s->port->zone.y + s->port->zone.height) + newPos.y = s->port->zone.y + s->port->zone.height; + + if (newPos.x < 0) newPos.x = 0; + if (newPos.y < 0) newPos.y = 0; + gfxop_set_pointer_position(s->gfx_state, newPos); +} + +} // End of namespace Sci diff --git a/engines/sci/gui32/gui32.h b/engines/sci/gui32/gui32.h new file mode 100644 index 0000000000..d986883849 --- /dev/null +++ b/engines/sci/gui32/gui32.h @@ -0,0 +1,79 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +namespace Sci { + +class SciGUI32 : public SciGUI { +public: + SciGUI32(OSystem *system, EngineState *s); + ~SciGUI32(); + + void init(bool oldGfxFunctions); + + int16 getTimeTicks(); + void wait(int16 ticks); + void setPort(uint16 portPtr); + void setPortPic(Common::Rect rect, int16 picTop, int16 picLeft); + reg_t getPort(); + void globalToLocal(int16 *x, int16 *y); + void localToGlobal(int16 *x, int16 *y); + reg_t newWindow(Common::Rect rect1, Common::Rect rect2, uint16 style, int16 priority, int16 colorPen, int16 colorBack, const char *title); + void disposeWindow(uint16 windowPtr, int16 arg2); + + void display(const char *text, int argc, reg_t *argv); + + void textSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); + void textFonts(int argc, reg_t *argv); + void textColors(int argc, reg_t *argv); + + void drawPicture(sciResourceId pictureId, uint16 showStyle, uint16 flags, int16 EGApaletteNo); + void drawCell(sciResourceId viewId, uint16 loopNo, uint16 cellNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo); + void drawControlButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool inverse); + void drawControlText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, bool inverse); + + void graphFillBoxForeground(Common::Rect rect); + void graphFillBoxBackground(Common::Rect rect); + void graphFillBox(Common::Rect rect, uint16 colorMask, int16 color, int16 priority, int16 control); + void graphDrawLine(Common::Rect rect, int16 color, int16 priority, int16 control); + reg_t graphSaveBox(Common::Rect rect, uint16 flags); + void graphRestoreBox(reg_t handle); + + void paletteSet(int resourceNo, int flags); + virtual int16 paletteFind(int r, int g, int b); + void paletteAnimate(int fromColor, int toColor, int speed); + + void moveCursor(int16 x, int16 y); + +private: + OSystem *_system; + EngineState *s; + bool _usesOldGfxFunctions; + + bool activated_icon_bar; // FIXME: Avoid non-const global vars + int port_origin_x; // FIXME: Avoid non-const global vars + int port_origin_y; // FIXME: Avoid non-const global vars +}; + +} // End of namespace Sci diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 88c60b6c1c..fd5b7aaaed 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -55,6 +55,16 @@ MODULE_OBJS = \ gfx/res_pic.o \ gfx/res_view.o \ gfx/seq_decoder.o \ + gui/gui.o \ + gui/gui_dbllist.o \ + gui/gui_font.o \ + gui/gui_gfx.o \ + gui/gui_memmgr.o \ + gui/gui_picture.o \ + gui/gui_screen.o \ + gui/gui_view.o \ + gui/gui_windowmgr.o \ + gui32/gui32.o \ sfx/core.o \ sfx/iterator.o \ sfx/songlib.o \ diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index a8f130f674..11c86d8ed8 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -35,6 +35,8 @@ #include "sci/engine/state.h" #include "sci/engine/kernel.h" +#include "sci/gui32/gui32.h" + #include "sci/gfx/gfx_resource.h" #include "sci/gfx/gfx_tools.h" #include "sci/gfx/operations.h" @@ -44,7 +46,7 @@ namespace Sci { class GfxDriver; SciEngine::SciEngine(OSystem *syst, const SciGameDescription *desc) - : Engine(syst), _gameDescription(desc) { + : Engine(syst), _gameDescription(desc), _system(syst) { // Put your engine in a sane state, but do nothing big yet; // in particular, do not load data from files; rather, if you // need to do such things, do them from init(). @@ -152,6 +154,10 @@ Common::Error SciEngine::run() { GfxState gfx_state; _gamestate->gfx_state = &gfx_state; + // GUI change + //_gamestate->gui = new SciGUI(_system, _gamestate); // new + _gamestate->gui = new SciGUI32(_system, _gamestate); // old + // Assign default values to the config manager, in case settings are missing ConfMan.registerDefault("dither_mode", "0"); @@ -183,6 +189,8 @@ Common::Error SciEngine::run() { return Common::kUnknownError; } + _gamestate->gui->init(_kernel->usesOldGfxFunctions()); + printf("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion()).c_str()); game_run(&_gamestate); // Run the game diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 3dbafcede8..ffcef329f1 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -132,6 +132,7 @@ private: Kernel *_kernel; Vocabulary *_vocabulary; Console *_console; + OSystem *_system; }; /** |