aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorWillem Jan Palenstijn2009-10-03 20:49:18 +0000
committerWillem Jan Palenstijn2009-10-03 20:49:18 +0000
commitb9cdb1abb76c94723c24ca66eb8d47d96c8c5ebd (patch)
treed4f40b3f6a8f55aef1e24506bd3771f8269d64a1 /engines
parentf6de0b4ec9fcc240cdc0c46aedb2e2089e07bd5c (diff)
downloadscummvm-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
Diffstat (limited to 'engines')
-rw-r--r--engines/sci/engine/kernel.cpp6
-rw-r--r--engines/sci/engine/kernel.h3
-rw-r--r--engines/sci/engine/kevent.cpp20
-rw-r--r--engines/sci/engine/kgraphics.cpp774
-rw-r--r--engines/sci/engine/kmisc.cpp3
-rw-r--r--engines/sci/engine/state.h9
-rw-r--r--engines/sci/gfx/gfx_driver.cpp15
-rw-r--r--engines/sci/gfx/gfx_driver.h5
-rw-r--r--engines/sci/gfx/res_view.cpp6
-rw-r--r--engines/sci/gui/gui.cpp330
-rw-r--r--engines/sci/gui/gui.h86
-rw-r--r--engines/sci/gui/gui_dbllist.cpp257
-rw-r--r--engines/sci/gui/gui_dbllist.h74
-rw-r--r--engines/sci/gui/gui_font.cpp100
-rw-r--r--engines/sci/gui/gui_font.h59
-rw-r--r--engines/sci/gui/gui_gfx.cpp1194
-rw-r--r--engines/sci/gui/gui_gfx.h150
-rw-r--r--engines/sci/gui/gui_helpers.h150
-rw-r--r--engines/sci/gui/gui_memmgr.cpp373
-rw-r--r--engines/sci/gui/gui_memmgr.h123
-rw-r--r--engines/sci/gui/gui_picture.cpp592
-rw-r--r--engines/sci/gui/gui_picture.h71
-rw-r--r--engines/sci/gui/gui_screen.cpp209
-rw-r--r--engines/sci/gui/gui_screen.h88
-rw-r--r--engines/sci/gui/gui_view.cpp296
-rw-r--r--engines/sci/gui/gui_view.h77
-rw-r--r--engines/sci/gui/gui_windowmgr.cpp326
-rw-r--r--engines/sci/gui/gui_windowmgr.h57
-rw-r--r--engines/sci/gui32/gui32.cpp732
-rw-r--r--engines/sci/gui32/gui32.h79
-rw-r--r--engines/sci/module.mk10
-rw-r--r--engines/sci/sci.cpp10
-rw-r--r--engines/sci/sci.h1
33 files changed, 5658 insertions, 627 deletions
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;
};
/**