Initial commit
This commit is contained in:
217
engines/m4/graphics/gr_buff.cpp
Normal file
217
engines/m4/graphics/gr_buff.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m4/graphics/gr_buff.h"
|
||||
#include "m4/graphics/gr_pal.h"
|
||||
#include "m4/gui/gui_vmng_core.h"
|
||||
#include "m4/core/errors.h"
|
||||
#include "m4/mem/memman.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
GrBuff::GrBuff(int32 _w, int32 _h) {
|
||||
w = _w;
|
||||
h = _h;
|
||||
x_off = y_off = 0;
|
||||
pitch = _w;
|
||||
height = _h;
|
||||
alloc_pixmap();
|
||||
}
|
||||
|
||||
GrBuff::GrBuff(int32 _w, int32 _h, int32 _x_off, int32 _y_off, int32 _pitch, int32 _height) {
|
||||
w = _w;
|
||||
h = _h;
|
||||
x_off = _x_off;
|
||||
y_off = _y_off;
|
||||
pitch = _pitch;
|
||||
height = _height;
|
||||
alloc_pixmap();
|
||||
}
|
||||
|
||||
GrBuff::~GrBuff() {
|
||||
if (pixmap)
|
||||
DisposeHandle(pixmap);
|
||||
}
|
||||
|
||||
void GrBuff::lock() {
|
||||
if (!pixmap)
|
||||
return;
|
||||
|
||||
HLock(pixmap);
|
||||
}
|
||||
|
||||
void GrBuff::release() {
|
||||
if (pixmap)
|
||||
HUnLock(pixmap);
|
||||
}
|
||||
|
||||
void GrBuff::alloc_pixmap() {
|
||||
pixmap = NewHandle(pitch * height, "pixmap");
|
||||
HLock(pixmap);
|
||||
memset(*pixmap, __BLACK, pitch * height);
|
||||
HUnLock(pixmap);
|
||||
}
|
||||
|
||||
uint8 *GrBuff::get_pixmap() {
|
||||
if (pixmap) {
|
||||
lock();
|
||||
return (uint8 *)*pixmap;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Buffer *GrBuff::get_buffer() {
|
||||
if (pixmap) {
|
||||
lock();
|
||||
dummy.data = (uint8 *)*pixmap;
|
||||
dummy.w = w;
|
||||
dummy.h = h;
|
||||
dummy.encoding = 0;
|
||||
dummy.stride = pitch;
|
||||
|
||||
return &dummy;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GrBuff::refresh_video(int32 scrnX, int32 scrnY, int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
vmng_refresh_video(scrnX, scrnY, x1, y1, x2, y2, get_buffer());
|
||||
}
|
||||
|
||||
int32 gr_buffer_free(Buffer *buf) {
|
||||
buf->w = buf->h = buf->stride = 0;
|
||||
|
||||
if (buf->data != nullptr) {
|
||||
mem_free((char *)buf->data);
|
||||
buf->data = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
error_show(FL, 'BUF!');
|
||||
return false;
|
||||
}
|
||||
|
||||
byte *gr_buffer_pointer(Buffer *buf, int32 x, int32 y) {
|
||||
if (!buf || !buf->data || y < 0 || x < 0) {
|
||||
error_show(FL, 'BUF!', "buffer_pointer x,y = %d,%d", x, y);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (byte *)(buf->data + x + (y * buf->stride));
|
||||
}
|
||||
|
||||
const byte *gr_buffer_pointer(const Buffer *buf, int32 x, int32 y) {
|
||||
if (!buf || !buf->data || y < 0 || x < 0) {
|
||||
error_show(FL, 'BUF!', "buffer_pointer x,y = %d,%d", x, y);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (byte *)(buf->data + x + (y * buf->stride));
|
||||
}
|
||||
|
||||
int32 gr_buffer_init(Buffer *buf, const char *name, int32 w, int32 h) {
|
||||
if (buf->data)
|
||||
error_show(FL, 'BUFR', "buffer_init %s", name);
|
||||
|
||||
buf->w = w;
|
||||
buf->h = h;
|
||||
buf->stride = w;
|
||||
|
||||
buf->data = (uint8 *)mem_alloc(buf->stride * h, name);
|
||||
if (buf->data == nullptr)
|
||||
error_show(FL, 'OOM!', "buffer: %s - w:%d h:%d bytes:%d", name, buf->stride, h, buf->stride * h);
|
||||
|
||||
memset(buf->data, 0, buf->stride * h);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool gr_buffer_rect_copy_2(const Buffer *from, Buffer *to, int32 sx, int32 sy,
|
||||
int32 dx, int32 dy, int32 w, int32 h) {
|
||||
// stupid check for no data
|
||||
if (!from || !to || !from->data || !to->data)
|
||||
error_show(FL, 'BUF!', "buff_rect_copy2");
|
||||
|
||||
// CKB: if height is greater than source height, truncate!
|
||||
if (h > from->h)
|
||||
h = from->h;
|
||||
|
||||
// if source x,y or dest x,y won't touch dest or source buffers, we're done
|
||||
if ((sx > from->w) || (sy > from->h) || (dx > to->w) || (dy > to->h))
|
||||
return true;
|
||||
|
||||
// if dest request intersects dest buffer, clip dest request
|
||||
if ((dx + w) > to->w)
|
||||
w = to->w - dx;
|
||||
if ((dy + h) > to->h)
|
||||
h = to->h - dy;
|
||||
|
||||
// if our dest request is too small, we're done
|
||||
if ((w < 1) || (h < 1))
|
||||
return true;
|
||||
|
||||
// initialize pointers
|
||||
const byte *src = gr_buffer_pointer(from, sx, sy);
|
||||
byte *dest = gr_buffer_pointer(to, dx, dy);
|
||||
|
||||
// get stride
|
||||
int32 sIncr = from->stride;
|
||||
int32 dIncr = to->stride;
|
||||
|
||||
// copy one to d'other
|
||||
for (int i = 0; i < h; i++, dest += dIncr, src += sIncr)
|
||||
memmove(dest, src, w);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gr_buffer_rect_copy(Buffer *from, Buffer *to, int32 x, int32 y, int32 w, int32 h) {
|
||||
return (gr_buffer_rect_copy_2(from, to, x, y, x, y, w, h));
|
||||
}
|
||||
|
||||
int32 gr_buffer_rect_fill(Buffer *target, int32 x1, int32 y1, int32 w, int32 h) {
|
||||
const byte color = gr_color_get_current();
|
||||
|
||||
// if no data, bad.
|
||||
if (!target || !target->data)
|
||||
error_show(FL, 'BUF!', "buffer_rect_fill");
|
||||
|
||||
// if nothing to fill, we're done
|
||||
if ((w < 1) || (h < 1) || (x1 > target->w) || (y1 > target->h))
|
||||
return true;
|
||||
|
||||
// clip if rectangles too big
|
||||
if ((x1 + w) > target->w)
|
||||
w = target->w - x1;
|
||||
if ((y1 + h) > target->h)
|
||||
h = target->h - y1;
|
||||
|
||||
if ((w < 1) || (h < 1))
|
||||
return true;
|
||||
|
||||
uint8 *start = target->data + y1 * target->stride + x1;
|
||||
for (int32 i = 0; i < h; i++, start += target->stride)
|
||||
memset(start, color, w);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
99
engines/m4/graphics/gr_buff.h
Normal file
99
engines/m4/graphics/gr_buff.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_BUFF_H
|
||||
#define M4_GRAPHICS_GR_BUFF_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
#include "m4/mem/reloc.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
class GrBuff {
|
||||
protected:
|
||||
void alloc_pixmap();
|
||||
|
||||
Buffer dummy{};
|
||||
MemHandle pixmap = nullptr;
|
||||
public:
|
||||
int32 w, h, x_off, y_off, pitch, height;
|
||||
|
||||
public:
|
||||
GrBuff(int32 _w, int32 _h);
|
||||
GrBuff(int32 _w, int32 _h, int32 _x_off, int32 _y_off, int32 _pitch, int32 _height);
|
||||
virtual ~GrBuff();
|
||||
|
||||
/**
|
||||
* Get buffer pointer
|
||||
* @remarks Get_buffer will return the whole pixmap, not the
|
||||
* subrectangle specified via x_off, y_off, w, h, and pitch.
|
||||
* get_buffer will lock the pixmap, unlock it after use, SVP.
|
||||
* DO NOT FREE THE RETURNED BUFFER!
|
||||
*/
|
||||
Buffer *get_buffer();
|
||||
|
||||
uint8 *get_pixmap();
|
||||
|
||||
void lock();
|
||||
void release();
|
||||
void refresh_video(int32 scrnX, int32 scrnY, int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
};
|
||||
|
||||
int32 gr_buffer_free(Buffer *buf);
|
||||
byte *gr_buffer_pointer(Buffer *buf, int32 x, int32 y);
|
||||
const byte *gr_buffer_pointer(const Buffer *buf, int32 x, int32 y);
|
||||
int32 gr_buffer_init(Buffer *buf, const char *name, int32 w, int32 h);
|
||||
|
||||
/**
|
||||
* Copies a "rectangular" buffer area from "from" to "unto". Size
|
||||
* of copied rectangle is determined by "size_x, size_y". Upper left
|
||||
* corner in source buffer is indicated by "from_x, from_y", and
|
||||
* "unto_x, unto_y" determines upper left corner in destination
|
||||
* buffer (if upper left corner coordinates are the same in both
|
||||
* buffers, buf_rect_copy() can be used instead).
|
||||
* @returns Returns true if successful.
|
||||
*/
|
||||
bool gr_buffer_rect_copy_2(const Buffer *from, Buffer *to, int32 sx, int32 sy,
|
||||
int32 dx, int32 dy, int32 w, int32 h);
|
||||
|
||||
/**
|
||||
* Copies a "rectangular" buffer area from "from" to "unto". Size
|
||||
* of copied rectangle is determined by "size_x, size_y". Upper left
|
||||
* corner in BOTH buffers is indicated by "ul_x, ul_y". (To copy
|
||||
* using separate corner coordinates in each buffer, use
|
||||
* buf_rect_copy_2 ().
|
||||
* @returns Returns true if successful.
|
||||
*/
|
||||
bool gr_buffer_rect_copy(Buffer *from, Buffer *to, int32 x, int32 y, int32 w, int32 h);
|
||||
|
||||
/**
|
||||
* Fills a rectangular buffer area with the specified byte value.
|
||||
* Upper left corner is determined by "ul_x, ul_y", and sizes are
|
||||
* determined by "size_x, size_y."
|
||||
* @returns Returns true if successful; false if buffer invalid.
|
||||
*/
|
||||
int32 gr_buffer_rect_fill(Buffer *target, int32 x1, int32 y1, int32 w, int32 h);
|
||||
|
||||
void GrBuff_Show(void *s, void *r, void *b, int32 destX, int32 destY);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
62
engines/m4/graphics/gr_color.cpp
Normal file
62
engines/m4/graphics/gr_color.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m4/graphics/gr_color.h"
|
||||
#include "m4/core/errors.h"
|
||||
#include "m4/fileio/sys_file.h"
|
||||
#include "m4/mem/reloc.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
InvPal::InvPal(const char *filename) {
|
||||
handle = nullptr;
|
||||
if (!filename)
|
||||
return;
|
||||
|
||||
SysFile ipl5(filename);
|
||||
|
||||
if (!ipl5.exists())
|
||||
return;
|
||||
|
||||
handle = NewHandle(32768, "5 bit ict");
|
||||
|
||||
ipl5.read(handle, 32768);
|
||||
}
|
||||
|
||||
InvPal::~InvPal() {
|
||||
if (handle)
|
||||
DisposeHandle(handle);
|
||||
}
|
||||
|
||||
uint8 *InvPal::get_ptr() {
|
||||
if (!handle)
|
||||
return nullptr;
|
||||
|
||||
HLock(handle);
|
||||
return (uint8 *)*handle;
|
||||
}
|
||||
|
||||
void InvPal::release() {
|
||||
if (handle)
|
||||
HUnLock(handle);
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
44
engines/m4/graphics/gr_color.h
Normal file
44
engines/m4/graphics/gr_color.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_COLOR_H
|
||||
#define M4_GRAPHICS_GR_COLOR_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
#include "m4/mem/reloc.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
class InvPal {
|
||||
private:
|
||||
MemHandle handle;
|
||||
|
||||
public:
|
||||
InvPal(const char *filename);
|
||||
virtual ~InvPal();
|
||||
|
||||
uint8 *get_ptr();
|
||||
void release();
|
||||
};
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
61
engines/m4/graphics/gr_draw.cpp
Normal file
61
engines/m4/graphics/gr_draw.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m4/graphics/gr_draw.h"
|
||||
#include "m4/graphics/gr_line.h"
|
||||
#include "m4/graphics/gr_pal.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
void buffer_put_pixel(Buffer *buf, int32 x, int32 y, byte c) {
|
||||
*(buf->data + x + (y * buf->stride)) = (uint8)c;
|
||||
}
|
||||
|
||||
byte buffer_get_pixel(Buffer *buf, int32 x, int32 y) {
|
||||
return *(buf->data + x + (y * buf->stride));
|
||||
}
|
||||
|
||||
void buffer_draw_box(Buffer *buf, int32 x1, int32 y1, int32 x2, int32 y2, byte color) {
|
||||
gr_color_set(color);
|
||||
gr_hline(buf, x1, x2, y1);
|
||||
gr_hline(buf, x1, x2, y2);
|
||||
gr_vline(buf, x1, y1, y2);
|
||||
gr_vline(buf, x2, y1, y2);
|
||||
}
|
||||
|
||||
void buffer_draw_box_xor(Buffer *buf, int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
gr_hline_xor(buf, x1, x2, y1);
|
||||
gr_hline_xor(buf, x1, x2, y2);
|
||||
gr_vline_xor(buf, x1, y1 + 1, y2 - 1);
|
||||
gr_vline_xor(buf, x2, y1 + 1, y2 - 1);
|
||||
}
|
||||
|
||||
int32 buffer_fill(Buffer *target, byte value) {
|
||||
if (!target)
|
||||
return false;
|
||||
if (!target->data)
|
||||
return false;
|
||||
|
||||
memset(target->data, value, target->stride * target->h);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
57
engines/m4/graphics/gr_draw.h
Normal file
57
engines/m4/graphics/gr_draw.h
Normal file
@@ -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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_DRAW_H
|
||||
#define M4_GRAPHICS_GR_DRAW_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
/**
|
||||
* Given X, Y sets the value of the pixel at that position
|
||||
*/
|
||||
void buffer_put_pixel(Buffer *buf, int32 x, int32 y, byte c);
|
||||
|
||||
/**
|
||||
* Given X, Y returns value of pixel at that address on the screen
|
||||
*/
|
||||
byte buffer_get_pixel(Buffer *buf, int32 x, int32 y);
|
||||
|
||||
/**
|
||||
* Draws outside edge of retangle given home and size along both axis
|
||||
*/
|
||||
void buffer_draw_box(Buffer *buf, int32 x1, int32 y1, int32 x2, int32 y2, byte color);
|
||||
|
||||
/**
|
||||
* Draws a rectangle using xor
|
||||
*/
|
||||
void buffer_draw_box_xor(Buffer *buf, int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
|
||||
/**
|
||||
* Fills an entire buffer with a single byte value.
|
||||
* @returns Returns True if successful, FALSE if buffer invalid.
|
||||
*/
|
||||
int32 buffer_fill(Buffer *target, byte value);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
415
engines/m4/graphics/gr_font.cpp
Normal file
415
engines/m4/graphics/gr_font.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m4/graphics/gr_font.h"
|
||||
#include "m4/graphics/gr_buff.h"
|
||||
#include "m4/mem/mem.h"
|
||||
#include "m4/core/errors.h"
|
||||
#include "m4/core/imath.h"
|
||||
#include "m4/mem/memman.h"
|
||||
#include "m4/vars.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
#define font_width 2 /* offset to width array */
|
||||
#define font_data 130 /* offset to data array */
|
||||
#define STR_FONTSTRUCT "font struct"
|
||||
#define STR_FONTWIDTH "font widths"
|
||||
#define STR_FONTOFF "font offsets"
|
||||
#define STR_FONTDATA "font data"
|
||||
|
||||
static byte font_colors[4] = { 0, 15, 0, 8 };
|
||||
constexpr byte font_intr_w = 8;
|
||||
constexpr byte font_intr_h = 8;
|
||||
|
||||
static byte fontintr_width[128] = {
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // 00-0f width (128 entries)
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,4, // 10-1f
|
||||
2,3,4,5,4,6,6,3, 3,3,6,3,3,3,3,6, // 20-2f [ !"#]$%&' ()*+,-./
|
||||
6,6,6,6,6,6,6,6, 6,6,2,2,3,3,3,6, // 30-3f [01234567] [89:;]<=>?
|
||||
6,6,6,5,6,5,5,6, 6,3,5,5,6,7,6,6, // 40-4f [@ABCDEFG] [HIJKLMNO]
|
||||
6,6,6,6,6,6,6,6, 6,6,6,3,3,3,4,6, // 50-5f [PQRSTUVW] [XYZ[\]^_]
|
||||
5,5,5,5,5,5,5,5, 5,2,3,5,2,6,5,5, // 60-6f ['abcdefg] [hijklmno]
|
||||
5,5,3,5,3,5,5,6, 5,5,5,4,2,4,4,4, // 70-7f [pqrstuvw] []xyz{|}~^
|
||||
};
|
||||
|
||||
static short fontintr_offsets[128] = {
|
||||
784, 784, 784, 784, 784, 784, 784, 784, // 00-07
|
||||
784, 784, 784, 784, 784, 784, 784, 784, // 08-0f
|
||||
784, 784, 784, 784, 784, 784, 784, 784, // 10-17
|
||||
784, 784, 784, 784, 784, 784, 784, 784, // 18-1f
|
||||
0, 8, 16, 24, 40, 48, 64, 80, // 20-27 [ !"#$%&']
|
||||
88, 96, 104, 120, 128, 136, 144, 152, // 28-2f [()*+,-./]
|
||||
168, 1176, 192, 208, 224, 240, 256, 272, // 30-37 [01234567]
|
||||
288, 304, 320, 328, 88, 336, 96, 344, // 38-3f [89:;]<=>?
|
||||
360, 376, 392, 408, 424, 440, 456, 472, // 40-47 [@ABCDEFG]
|
||||
488, 504, 512, 528, 544, 560, 576, 592, // 48-4f [HIJKLMNO]
|
||||
608, 624, 640, 656, 672, 688, 704, 720, // 50-57 [PQRSTUVW]
|
||||
736, 752, 768, 1192, 1208, 1200, 784, 784, // 58-5f [XYZ[\]^_]
|
||||
784, 800, 816, 832, 848, 864, 880, 896, // 60-67 [`abcdefg]
|
||||
912, 928, 936, 944, 960, 968, 984, 1000, // 68-6f [hijklmno]
|
||||
1016, 1032, 1048, 1056, 1072, 1080, 1096, 1112, // 70-77 [pqrstuvw]
|
||||
1128, 1144, 1160, 784, 184, 1216, 784, 1224 // 78-7f []xyz{|}~^
|
||||
};
|
||||
|
||||
static byte fontintr_data[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0 " "
|
||||
0x14,0x14,0x14,0x14,0x14,0x00,0x14,0x00, // 8 "!"
|
||||
0x44,0x44,0x00,0x00,0x00,0x00,0x00,0x00, // 16 "
|
||||
0x00,0x00,0x11,0x00,0x55,0x40,0x11,0x00,0x11,0x00,0x55,0x40,0x11,0x00,0x00,0x00, // 24 "#"
|
||||
0x10,0x14,0x40,0x54,0x04,0x50,0x10,0x00, // 40 "$"
|
||||
0x00,0x00,0x10,0x00,0x44,0x40,0x11,0x00,0x01,0x10,0x04,0x44,0x00,0x10,0x00,0x00, // 48 "%"
|
||||
0x04,0x00,0x11,0x00,0x10,0x00,0x44,0x00,0x41,0x40,0x41,0x00,0x14,0x40,0x00,0x00, // 64 "&"
|
||||
0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00, // 80 "'"
|
||||
0x04,0x10,0x40,0x40,0x40,0x10,0x04,0x00, // 88 "("
|
||||
0x40,0x10,0x04,0x04,0x04,0x10,0x40,0x00, // 96 ")"
|
||||
0x00,0x00,0x04,0x00,0x44,0x40,0x15,0x00,0x44,0x40,0x04,0x00,0x00,0x00,0x00,0x00, // 104 "*"
|
||||
0x00,0x00,0x00,0x10,0x54,0x10,0x00,0x00, // 120 "+"
|
||||
0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x40, // 128 ","
|
||||
0x00,0x00,0x00,0x00,0x54,0x00,0x00,0x00, // 136 "-"
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, // 144 "."
|
||||
0x00,0x04,0x00,0x10,0x00,0x40,0x01,0x00,0x04,0x00,0x10,0x00,0x40,0x00,0x00,0x00, // 152 "/"
|
||||
0x00,0x00,0x15,0x40,0x50,0x10,0x54,0x10,0x51,0x10,0x50,0x50,0x15,0x40,0x00,0x00, // 168 "0"
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, // 184 "|"
|
||||
0x00,0x00,0x15,0x00,0x41,0x40,0x01,0x40,0x05,0x00,0x14,0x00,0x55,0x40,0x00,0x00, // 192 "2"
|
||||
0x00,0x00,0x15,0x40,0x00,0x50,0x05,0x40,0x00,0x50,0x00,0x50,0x55,0x40,0x00,0x00, // 208 "3"
|
||||
0x00,0x00,0x01,0x40,0x41,0x40,0x41,0x40,0x55,0x40,0x01,0x40,0x01,0x40,0x00,0x00, // 224 "4"
|
||||
0x00,0x00,0x55,0x50,0x50,0x00,0x55,0x40,0x00,0x50,0x00,0x50,0x55,0x40,0x00,0x00, // 240 "5"
|
||||
0x00,0x00,0x15,0x40,0x50,0x00,0x55,0x40,0x50,0x10,0x50,0x10,0x15,0x40,0x00,0x00, // 256 "6"
|
||||
0x00,0x00,0x55,0x50,0x00,0x50,0x01,0x40,0x05,0x00,0x05,0x00,0x05,0x00,0x00,0x00, // 272 "7"
|
||||
0x00,0x00,0x15,0x40,0x50,0x10,0x15,0x40,0x50,0x10,0x50,0x10,0x15,0x40,0x00,0x00, // 288 "8"
|
||||
0x00,0x00,0x15,0x40,0x40,0x50,0x41,0x50,0x14,0x50,0x00,0x50,0x15,0x40,0x00,0x00, // 304 "9"
|
||||
0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00, // 320 ":"
|
||||
0x00,0x00,0x40,0x00,0x00,0x40,0x40,0x00, // 328 ";"
|
||||
0x00,0x00,0x00,0x54,0x00,0x54,0x00,0x00, // 336 "="
|
||||
0x14,0x00,0x41,0x00,0x01,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00, // 344 "?" // 352
|
||||
0x15,0x00,0x40,0x40,0x41,0x00,0x44,0x40,0x41,0x00,0x40,0x00,0x15,0x00,0x00,0x00, // 360 "@"
|
||||
0x15,0x40,0x50,0x10,0x50,0x10,0x55,0x50,0x50,0x10,0x50,0x10,0x50,0x10,0x00,0x00, // 376 "A"
|
||||
0x55,0x40,0x50,0x10,0x50,0x10,0x55,0x40,0x50,0x10,0x50,0x10,0x55,0x40,0x00,0x00, // 392 "B"
|
||||
0x15,0x00,0x50,0x40,0x50,0x00,0x50,0x00,0x50,0x00,0x50,0x40,0x15,0x00,0x00,0x00, // 408 "C"
|
||||
0x55,0x40,0x14,0x40,0x14,0x10,0x14,0x10,0x14,0x10,0x14,0x10,0x55,0x40,0x00,0x00, // 424 "D"
|
||||
0x55,0x40,0x50,0x00,0x50,0x00,0x55,0x00,0x50,0x00,0x50,0x00,0x55,0x40,0x00,0x00, // 440 "E"
|
||||
0x55,0x40,0x50,0x00,0x50,0x00,0x55,0x00,0x50,0x00,0x50,0x00,0x50,0x00,0x00,0x00, // 456 "F"
|
||||
0x15,0x40,0x50,0x10,0x50,0x00,0x51,0x50,0x50,0x10,0x50,0x10,0x15,0x40,0x00,0x00, // 472 "G"
|
||||
0x50,0x10,0x50,0x10,0x50,0x10,0x55,0x50,0x50,0x10,0x50,0x10,0x50,0x10,0x00,0x00, // 488 "H"
|
||||
0x55,0x14,0x14,0x14,0x14,0x14,0x55,0x00, // 504 "I"
|
||||
0x05,0x50,0x01,0x40,0x01,0x40,0x01,0x40,0x01,0x40,0x41,0x40,0x15,0x00,0x00,0x00, // 512 "J"
|
||||
0x50,0x40,0x51,0x00,0x54,0x00,0x50,0x00,0x54,0x00,0x51,0x00,0x50,0x40,0x00,0x00, // 528 "K"
|
||||
0x50,0x00,0x50,0x00,0x50,0x00,0x50,0x00,0x50,0x00,0x50,0x00,0x55,0x50,0x00,0x00, // 544 "L"
|
||||
0x50,0x10,0x54,0x50,0x51,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x00,0x00, // 560 "M"
|
||||
0x50,0x10,0x50,0x10,0x54,0x10,0x51,0x10,0x50,0x50,0x50,0x10,0x50,0x10,0x00,0x00, // 576 "N"
|
||||
0x15,0x40,0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x15,0x40,0x00,0x00, // 592 "O"
|
||||
0x55,0x00,0x50,0x40,0x50,0x40,0x55,0x00,0x50,0x00,0x50,0x00,0x50,0x00,0x00,0x00, // 608 "P"
|
||||
0x15,0x00,0x50,0x40,0x50,0x40,0x50,0x40,0x50,0x40,0x51,0x00,0x14,0x40,0x00,0x00, // 624 "Q"
|
||||
0x55,0x40,0x50,0x10,0x50,0x10,0x55,0x40,0x50,0x10,0x50,0x10,0x50,0x10,0x00,0x00, // 640 "R"
|
||||
0x15,0x00,0x40,0x40,0x10,0x00,0x05,0x40,0x00,0x50,0x40,0x50,0x15,0x40,0x00,0x00, // 656 "S"
|
||||
0x55,0x50,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x00,0x00, // 672 "T"
|
||||
0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x15,0x40,0x00,0x00, // 688 "U"
|
||||
0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x10,0x40,0x04,0x00,0x00,0x00, // 704 "V"
|
||||
0x50,0x10,0x50,0x10,0x50,0x10,0x50,0x10,0x51,0x10,0x55,0x50,0x50,0x10,0x00,0x00, // 720 "W"
|
||||
0x40,0x40,0x40,0x40,0x11,0x00,0x04,0x00,0x11,0x00,0x40,0x40,0x40,0x40,0x00,0x00, // 736 "X"
|
||||
0x40,0x40,0x40,0x40,0x11,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x00,0x00, // 752 "Y"
|
||||
0x55,0x40,0x00,0x40,0x01,0x00,0x04,0x00,0x10,0x00,0x40,0x00,0x55,0x40,0x00,0x00, // 768 "Z"
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x40,0x00,0x00, // 784 a little weirdo thing
|
||||
0x00,0x00,0x00,0x00,0x15,0x00,0x01,0x40,0x11,0x40,0x41,0x40,0x14,0x40,0x00,0x00, // 800 "a"
|
||||
0x50,0x00,0x50,0x00,0x55,0x00,0x50,0x40,0x50,0x40,0x50,0x40,0x55,0x00,0x00,0x00, // 816 "b"
|
||||
0x00,0x00,0x00,0x00,0x15,0x00,0x50,0x40,0x50,0x00,0x50,0x40,0x15,0x00,0x00,0x00, // 832 "c"
|
||||
0x01,0x40,0x01,0x40,0x15,0x40,0x41,0x40,0x41,0x40,0x41,0x40,0x15,0x40,0x00,0x00, // 848 "d"
|
||||
0x00,0x00,0x00,0x00,0x15,0x00,0x50,0x40,0x55,0x40,0x50,0x00,0x15,0x00,0x00,0x00, // 864 "e"
|
||||
0x05,0x00,0x11,0x00,0x14,0x00,0x55,0x00,0x14,0x00,0x14,0x00,0x14,0x00,0x00,0x00, // 880 "f"
|
||||
0x00,0x00,0x00,0x00,0x14,0x00,0x41,0x40,0x41,0x40,0x15,0x40,0x41,0x40,0x15,0x00, // 896 "g"
|
||||
0x50,0x00,0x50,0x00,0x55,0x00,0x50,0x40,0x50,0x40,0x50,0x40,0x50,0x40,0x00,0x00, // 912 "h"
|
||||
0x50,0x00,0x50,0x50,0x50,0x50,0x50,0x00, // 928 "i"
|
||||
0x05,0x00,0x05,0x05,0x05,0x05,0x45,0x10, // 936 "j"
|
||||
0x50,0x00,0x50,0x00,0x50,0x40,0x51,0x00,0x54,0x00,0x51,0x00,0x50,0x40,0x00,0x00, // 944 "k"
|
||||
0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x00, // 960 "l"
|
||||
0x00,0x00,0x00,0x00,0x54,0x40,0x51,0x10,0x51,0x10,0x51,0x10,0x51,0x10,0x00,0x00, // 968 "m"
|
||||
0x00,0x00,0x00,0x00,0x55,0x00,0x50,0x40,0x50,0x40,0x50,0x40,0x50,0x40,0x00,0x00, // 984 "n"
|
||||
0x00,0x00,0x00,0x00,0x15,0x00,0x50,0x40,0x50,0x40,0x50,0x40,0x15,0x00,0x00,0x00, // 1000 "o"
|
||||
0x00,0x00,0x00,0x00,0x55,0x00,0x50,0x40,0x50,0x40,0x55,0x00,0x50,0x00,0x50,0x00, // 1016 "p"
|
||||
0x00,0x00,0x00,0x00,0x14,0x40,0x41,0x40,0x41,0x40,0x15,0x40,0x01,0x40,0x01,0x40, // 1032 "q"
|
||||
0x00,0x00,0x51,0x54,0x50,0x50,0x50,0x00, // 1048 "r"
|
||||
0x00,0x00,0x00,0x00,0x15,0x00,0x40,0x00,0x15,0x00,0x01,0x40,0x55,0x00,0x00,0x00, // 1056 "s"
|
||||
0x10,0x14,0x55,0x14,0x14,0x14,0x05,0x00, // 1072 "t"
|
||||
0x00,0x00,0x00,0x00,0x50,0x40,0x50,0x40,0x50,0x40,0x50,0x40,0x15,0x00,0x00,0x00, // 1080 "u"
|
||||
0x00,0x00,0x00,0x00,0x50,0x40,0x50,0x40,0x50,0x40,0x11,0x10,0x05,0x00,0x00,0x00, // 1096 "v"
|
||||
0x00,0x00,0x00,0x00,0x50,0x10,0x50,0x10,0x51,0x10,0x51,0x10,0x15,0x00,0x00,0x00, // 1112 "w"
|
||||
0x00,0x00,0x00,0x00,0x50,0x40,0x50,0x40,0x15,0x00,0x50,0x40,0x50,0x40,0x00,0x00, // 1128 "x"
|
||||
0x00,0x00,0x00,0x00,0x41,0x40,0x41,0x40,0x41,0x40,0x15,0x40,0x01,0x40,0x01,0x40, // 1144 "y
|
||||
0x00,0x00,0x00,0x00,0x55,0x00,0x01,0x00,0x14,0x00,0x40,0x00,0x55,0x00,0x00,0x00, // 1160 "z"
|
||||
0x00,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x15,0x40,0x00,0x00, // 1176 thick "1"
|
||||
0x55,0x50,0x50,0x50,0x50,0x50,0x55,0x00, // 1192 "["
|
||||
0x55,0x05,0x05,0x05,0x05,0x05,0x55,0x00, // 1200 "]"
|
||||
0x00,0x40,0x10,0x10,0x04,0x04,0x01,0x00, // 1208 "\"
|
||||
0x15,0x14,0x14,0x50,0x14,0x14,0x15,0x00, // 1216 "{"
|
||||
0x54,0x14,0x14,0x05,0x14,0x14,0x54,0x00 // 1224 "}"
|
||||
};
|
||||
|
||||
void font_set_colors(uint8 alt1, uint8 alt2, uint8 foreground) {
|
||||
if (_G(font) == _G(interfaceFont)) {
|
||||
font_colors[1] = foreground;
|
||||
} else {
|
||||
font_colors[1] = alt1;
|
||||
font_colors[2] = alt2;
|
||||
font_colors[3] = foreground;
|
||||
}
|
||||
}
|
||||
|
||||
void gr_font_set_color(uint8 foreground) {
|
||||
if (_G(font) == _G(interfaceFont))
|
||||
font_colors[1] = foreground;
|
||||
else
|
||||
font_colors[3] = foreground;
|
||||
}
|
||||
|
||||
Font *gr_font_create_system_font() {
|
||||
_G(interfaceFont) = (Font *)mem_alloc(sizeof(Font), "Font");
|
||||
if (!_G(interfaceFont))
|
||||
error("font struct");
|
||||
|
||||
_G(interfaceFont)->max_y_size = font_intr_h;
|
||||
_G(interfaceFont)->max_x_size = font_intr_w;
|
||||
_G(interfaceFont)->width = fontintr_width;
|
||||
_G(interfaceFont)->offset = fontintr_offsets;
|
||||
_G(interfaceFont)->pixData = fontintr_data;
|
||||
|
||||
return _G(interfaceFont);
|
||||
}
|
||||
|
||||
void gr_font_system_shutdown() {
|
||||
if (_G(interfaceFont))
|
||||
mem_free(_G(interfaceFont));
|
||||
}
|
||||
|
||||
void gr_font_dealloc(Font *killMe) {
|
||||
if (!killMe)
|
||||
return;
|
||||
if (killMe->width)
|
||||
mem_free(killMe->width);
|
||||
if (killMe->offset)
|
||||
mem_free(killMe->offset);
|
||||
if (killMe->pixData)
|
||||
mem_free(killMe->pixData);
|
||||
mem_free(killMe);
|
||||
}
|
||||
|
||||
void gr_font_set(Font *newFont) {
|
||||
if (newFont)
|
||||
_G(font) = newFont;
|
||||
}
|
||||
|
||||
Font *gr_font_get() {
|
||||
return _G(font);
|
||||
}
|
||||
|
||||
int32 gr_font_string_width(char *out_string, int32 auto_spacing) {
|
||||
if (_G(custom_ascii_converter)) { // if there is a function to convert the extended ASCII characters
|
||||
_G(custom_ascii_converter)(out_string); // call it with the string
|
||||
}
|
||||
|
||||
int32 width = 0; // Add some spacing in between the characters
|
||||
byte *widthArray = _G(font)->width;
|
||||
|
||||
while (*out_string) {
|
||||
width += widthArray[(byte)*out_string] + auto_spacing;
|
||||
out_string++;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
int32 gr_font_string_width(const Common::String &str, int32 auto_spacing) {
|
||||
char *tmp = new char[str.size() + 1];
|
||||
Common::copy(str.c_str(), str.c_str() + str.size() + 1, tmp);
|
||||
const int32 result = gr_font_string_width(tmp, auto_spacing);
|
||||
delete[] tmp;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int32 gr_font_get_height() {
|
||||
if (!_G(font))
|
||||
return -1;
|
||||
|
||||
return (int32)_G(font)->max_y_size;
|
||||
}
|
||||
|
||||
|
||||
int32 gr_font_write(Buffer *target, char *out_string, int32 x, int32 y, int32 w, int32 auto_spacing) {
|
||||
if (!target || !out_string)
|
||||
return x;
|
||||
|
||||
if (_G(custom_ascii_converter)) { // if there is a function to convert the extended ASCII characters
|
||||
_G(custom_ascii_converter)(out_string); // call it with the string
|
||||
}
|
||||
|
||||
int32 target_w;
|
||||
if (w)
|
||||
target_w = imath_min(target->w, x + w);
|
||||
else
|
||||
target_w = target->w;
|
||||
|
||||
x += 1;
|
||||
y += 1;
|
||||
int32 skipTop = 0;
|
||||
if (y < 0) {
|
||||
skipTop = -y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
int32 height = imath_max(0, (int32)_G(font)->max_y_size - skipTop);
|
||||
if (!height)
|
||||
return x;
|
||||
|
||||
const int32 bottom = y + height - 1;
|
||||
if (bottom > (target->h - 1)) {
|
||||
height -= imath_min((int32)height, (bottom - (target->h - 1)));
|
||||
}
|
||||
|
||||
if (height <= 0)
|
||||
return x;
|
||||
|
||||
byte *target_ptr = gr_buffer_pointer(target, x, y);
|
||||
byte *prev_target_ptr = target_ptr;
|
||||
|
||||
int32 cursX = x;
|
||||
Byte *widthArray = _G(font)->width;
|
||||
Byte *fontPixData = _G(font)->pixData;
|
||||
short *offsetArray = _G(font)->offset;
|
||||
|
||||
while (*out_string) {
|
||||
const byte c = (*out_string++) & 0x7f;
|
||||
const int32 wdth = widthArray[c];
|
||||
|
||||
// if width is zero, nothing to draw
|
||||
|
||||
if (wdth) {
|
||||
if ((cursX + wdth) >= target_w) // if character doesn't fit in buffer, abort
|
||||
return cursX;
|
||||
|
||||
const int32 offset = offsetArray[c];
|
||||
Byte *charData = &fontPixData[offset];
|
||||
|
||||
const int32 bytesInChar = (_G(font)->width[c] >> 2) + 1; // bytesPer[wdth]; // 2 bits per pixel
|
||||
if (skipTop)
|
||||
charData += bytesInChar * skipTop;
|
||||
|
||||
for (int32 i = 0; i < height; i++) {
|
||||
for (int32 j = 0; j < bytesInChar; j++) {
|
||||
const Byte workByte = *charData++;
|
||||
if (workByte & 0xc0)
|
||||
*target_ptr = font_colors[(workByte & 0xc0) >> 6];
|
||||
target_ptr++;
|
||||
if (workByte & 0x30)
|
||||
*target_ptr = font_colors[(workByte & 0x30) >> 4];
|
||||
target_ptr++;
|
||||
if (workByte & 0xc)
|
||||
*target_ptr = font_colors[(workByte & 0xc) >> 2];
|
||||
target_ptr++;
|
||||
if (workByte & 0x3)
|
||||
*target_ptr = font_colors[workByte & 0x3];
|
||||
target_ptr++;
|
||||
|
||||
} // end bytes per character line loop
|
||||
|
||||
target_ptr += target->stride - (bytesInChar << 2);
|
||||
|
||||
} // end for height loop
|
||||
|
||||
target_ptr = prev_target_ptr + wdth + auto_spacing; // one pixel space
|
||||
prev_target_ptr = target_ptr;
|
||||
|
||||
} // end if there was a drawable character
|
||||
|
||||
cursX += w;
|
||||
} // end while there is a character to draw loop
|
||||
|
||||
return cursX;
|
||||
}
|
||||
|
||||
int32 gr_font_write(Buffer *target, const char *out_string, int32 x, int32 y, int32 w, int32 auto_spacing) {
|
||||
char *tmp = mem_strdup(out_string);
|
||||
const int32 result = gr_font_write(target, tmp, x, y, w, auto_spacing);
|
||||
free(tmp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Font *gr_font_load(const char *fontName) {
|
||||
SysFile fontFile(fontName);
|
||||
if (!fontFile.exists())
|
||||
return nullptr;
|
||||
|
||||
uint32 tag = fontFile.readUint32LE();
|
||||
if (tag != 'FONT')
|
||||
error_show(FL, 'FNTL', "font: %s chkpnt: %d", (const char *)fontName, 0);
|
||||
|
||||
Font *newFont = (Font *)mem_alloc(sizeof(Font), STR_FONTSTRUCT);
|
||||
if (!newFont)
|
||||
error_show(FL, 'OOM!', "_G(font) struct");
|
||||
|
||||
newFont->max_y_size = fontFile.readByte();
|
||||
newFont->max_x_size = fontFile.readByte();
|
||||
newFont->dataSize = fontFile.readUint32LE();
|
||||
|
||||
// read 'WIDT' into tag
|
||||
tag = fontFile.readUint32LE();
|
||||
if (tag != 'WIDT')
|
||||
error_show(FL, 'FNTL', "font: %s chkpnt: %d", fontName, 1);
|
||||
|
||||
// width table
|
||||
newFont->width = (byte *)mem_alloc(256, STR_FONTWIDTH);
|
||||
if (!newFont->width)
|
||||
error_show(FL, 'OOM!', "_G(font) width table");
|
||||
|
||||
fontFile.read(newFont->width, 256);
|
||||
|
||||
// read 'OFFS' into tag
|
||||
tag = fontFile.readUint32LE();
|
||||
if (tag != 'OFFS')
|
||||
error_show(FL, 'FNTL', "font: %s chkpnt: %d", fontName, 2);
|
||||
|
||||
// offset table
|
||||
newFont->offset = (short *)mem_alloc(256 * sizeof(int16), STR_FONTOFF);
|
||||
if (!newFont->offset)
|
||||
error_show(FL, 'OOM!', "font offset table");
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
newFont->offset[i] = fontFile.readSint16LE();
|
||||
|
||||
// read 'PIXS' into tag
|
||||
tag = fontFile.readUint32LE();
|
||||
if (tag != 'PIXS')
|
||||
error_show(FL, 'FNTL', "font: %s chkpnt: %d", fontName, 3);
|
||||
|
||||
// pixData
|
||||
newFont->pixData = (byte *)mem_alloc(newFont->dataSize, STR_FONTDATA);
|
||||
if (!newFont->pixData)
|
||||
error_show(FL, 'OOM!', "font pix data");
|
||||
|
||||
fontFile.read(newFont->pixData, newFont->dataSize);
|
||||
|
||||
// we don't need to close the file, because the destructor will close fontFile automagically
|
||||
return newFont;
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
60
engines/m4/graphics/gr_font.h
Normal file
60
engines/m4/graphics/gr_font.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_FONT_H
|
||||
#define M4_GRAPHICS_GR_FONT_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "m4/m4_types.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
struct Font {
|
||||
byte max_y_size;
|
||||
byte max_x_size;
|
||||
uint32 dataSize;
|
||||
|
||||
byte *width;
|
||||
int16 *offset;
|
||||
byte *pixData;
|
||||
};
|
||||
|
||||
void gr_font_system_shutdown();
|
||||
void gr_font_dealloc(Font *killMe);
|
||||
Font *gr_font_create_system_font();
|
||||
void gr_font_set_color(uint8 foreground);
|
||||
Font *gr_font_get();
|
||||
void gr_font_set(Font *font);
|
||||
int32 gr_font_get_height();
|
||||
int32 gr_font_write(Buffer *target, char *out_string, int32 x, int32 y,
|
||||
int32 w, int32 auto_spacing = 1);
|
||||
int32 gr_font_write(Buffer *target, const char *out_string, int32 x, int32 y,
|
||||
int32 w, int32 auto_spacing);
|
||||
int32 gr_font_string_width(char *out_string, int32 auto_spacing = 1);
|
||||
int32 gr_font_string_width(const Common::String &str, int32 auto_spacing = 1);
|
||||
|
||||
Font *gr_font_load(const char *fontName);
|
||||
|
||||
void font_set_colors(uint8 alt1, uint8 alt2, uint8 foreground);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
138
engines/m4/graphics/gr_line.cpp
Normal file
138
engines/m4/graphics/gr_line.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m4/graphics/gr_line.h"
|
||||
#include "m4/vars.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
void gr_vline_xor(Buffer *buf, int32 x, int32 y1, int32 y2) {
|
||||
if (y1 > y2) {
|
||||
SWAP(y1, y2);
|
||||
}
|
||||
|
||||
if ((x > buf->w) || (y1 > buf->h))
|
||||
return;
|
||||
|
||||
if (y2 > buf->h)
|
||||
y2 = buf->h; // Don't draw past bottom
|
||||
|
||||
byte *start = buf->data + x;
|
||||
|
||||
for (int32 i = y1; i < y2; i++, start += buf->stride)
|
||||
*start ^= 0xff;
|
||||
}
|
||||
|
||||
void gr_hline_xor(Buffer *buf, int32 x1, int32 x2, int32 y) {
|
||||
if (x1 > x2) {
|
||||
SWAP(x1, x2);
|
||||
}
|
||||
|
||||
if ((y > buf->h) || (x1 > buf->w))
|
||||
return;
|
||||
|
||||
byte *start = gr_buffer_pointer(buf, x1, y);
|
||||
|
||||
for (int32 i = x1; i < x2; i++, start++)
|
||||
*start ^= 0xff;
|
||||
}
|
||||
|
||||
void gr_vline(Buffer *buf, int32 x, int32 y1, int32 y2) {
|
||||
if (y1 > y2) {
|
||||
SWAP(y1, y2);
|
||||
}
|
||||
|
||||
if ((x > buf->w) || (y1 > buf->h))
|
||||
return;
|
||||
|
||||
y2++;
|
||||
if (y2 > buf->h)
|
||||
y2 = buf->h; // don't draw past bottom
|
||||
|
||||
byte *start = gr_buffer_pointer(buf, x, y1);
|
||||
|
||||
for (int32 i = y1; i < y2; i++, start += buf->stride)
|
||||
*start = _G(color);
|
||||
}
|
||||
|
||||
void gr_hline(Buffer *buf, int32 x1, int32 x2, int32 y) {
|
||||
if (x1 > x2) {
|
||||
SWAP(x1, x2);
|
||||
}
|
||||
|
||||
if ((y > buf->h) || (x1 > buf->w))
|
||||
return;
|
||||
|
||||
byte *start = gr_buffer_pointer(buf, x1, y);
|
||||
|
||||
x2++;
|
||||
if (x2 > buf->w)
|
||||
x2 = buf->w;
|
||||
|
||||
for (int32 i = x1; i < x2; i++, start++)
|
||||
*start = _G(color);
|
||||
}
|
||||
|
||||
void gr_line(int32 x1, int32 y1, int32 x2, int32 y2, int32 color, Buffer *screen) {
|
||||
byte *myData = (byte *)screen->data;
|
||||
int32 y_unit, x_unit; // Variables for amount of change in x and y
|
||||
|
||||
int32 offset = y1 * screen->stride + x1; // Calculate offset into video RAM
|
||||
|
||||
int32 ydiff = y2 - y1; // Calculate difference between y coordinates
|
||||
if (ydiff < 0) { // If the line moves in the negative direction
|
||||
ydiff = -ydiff; // ...get absolute value of difference
|
||||
y_unit = -screen->stride; // ...and set negative unit in y dimension
|
||||
} else y_unit = screen->stride; // Else set positive unit in y dimension
|
||||
|
||||
int32 xdiff = x2 - x1; // Calculate difference between x coordinates
|
||||
if (xdiff < 0) { // If the line moves in the negative direction
|
||||
xdiff = -xdiff; // ...get absolute value of difference
|
||||
x_unit = -1; // ...and set negative unit in x dimension
|
||||
} else x_unit = 1; // Else set positive unit in y dimension
|
||||
|
||||
int32 error_term = 0; // Initialize error term
|
||||
if (xdiff > ydiff) { // If difference is bigger in x dimension
|
||||
const int32 length = xdiff + 1; // ...prepare to count off in x direction
|
||||
for (int32 i = 0; i < length; i++) { // Loop through points in x direction
|
||||
myData[offset] = (char)color; // Set the next pixel in the line to COLOR
|
||||
offset += x_unit; // Move offset to next pixel in x direction
|
||||
error_term += ydiff; // Check to see if move required in y direction
|
||||
if (error_term > xdiff) { // If so...
|
||||
error_term -= xdiff; // ...reset error term
|
||||
offset += y_unit; // ...and move offset to next pixel in y dir.
|
||||
}
|
||||
}
|
||||
} else { // If difference is bigger in y dimension
|
||||
const int32 length = ydiff + 1; // ...prepare to count off in y direction
|
||||
for (int32 i = 0; i < length; i++) { // Loop through points in y direction
|
||||
myData[offset] = (char)color; // Set the next pixel in the line to COLOR
|
||||
offset += y_unit; // Move offset to next pixel in y direction
|
||||
error_term += xdiff; // Check to see if move required in x direction
|
||||
if (error_term > 0) { // If so...
|
||||
error_term -= ydiff; // ...reset error term
|
||||
offset += x_unit; // ...and move offset to next pixel in x dir.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
46
engines/m4/graphics/gr_line.h
Normal file
46
engines/m4/graphics/gr_line.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_LINE_H
|
||||
#define M4_GRAPHICS_GR_LINE_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
/**
|
||||
* Given starting and ending points on the Y axis, and the constant
|
||||
* X value, draws a line in the set color in the specified buffer
|
||||
*/
|
||||
void gr_hline(Buffer *buf, int32 x1, int32 x2, int32 y);
|
||||
|
||||
/**
|
||||
* Given starting and ending points on the Y axis, and the constant
|
||||
* X value, draws a line in the given color on the live MCGA screen.
|
||||
*/
|
||||
void gr_vline(Buffer *buf, int32 x, int32 y1, int32 y2);
|
||||
void gr_hline_xor(Buffer *buf, int32 x1, int32 x2, int32 y);
|
||||
void gr_vline_xor(Buffer *buf, int32 x, int32 y1, int32 y2);
|
||||
void gr_line(int32 x1, int32 y1, int32 x2, int32 y2, int32 color, Buffer *screen);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
188
engines/m4/graphics/gr_pal.cpp
Normal file
188
engines/m4/graphics/gr_pal.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "m4/graphics/gr_pal.h"
|
||||
#include "m4/core/errors.h"
|
||||
#include "m4/vars.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
byte EGAcolors[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
uint8 gr_pal_get_ega_color(uint8 myColor) {
|
||||
return EGAcolors[myColor];
|
||||
}
|
||||
|
||||
|
||||
uint8 *gr_color_createInverseTable(RGB8 *pal, uint8 bitDepth, int begin_color, int end_color) {
|
||||
error("gr_color_createInverseTable is not implemented in ScummVM");
|
||||
}
|
||||
|
||||
void gr_color_create_ipl5(uint8 *inverseColorTable, char *fname, int room_num) {
|
||||
error("gr_color_create_ipl5 is not implemented in ScummVM");
|
||||
}
|
||||
|
||||
uint8 *gr_color_load_ipl5(const char *filename, uint8 *inverseColors) {
|
||||
error("gr_color_load_ipl5 is not implemented in ScummVM");
|
||||
}
|
||||
|
||||
void gr_color_set(int32 c) {
|
||||
_G(color) = c;
|
||||
}
|
||||
|
||||
byte gr_color_get_current() {
|
||||
return _G(color);
|
||||
}
|
||||
|
||||
void gr_pal_clear(RGB8 *palette) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
palette[i].r = 0;
|
||||
palette[i].g = 0;
|
||||
palette[i].b = 0;
|
||||
}
|
||||
|
||||
gr_pal_set(palette);
|
||||
}
|
||||
|
||||
void gr_pal_set(RGB8 *pal) {
|
||||
gr_pal_set_range(pal, 0, 256);
|
||||
}
|
||||
|
||||
void gr_pal_set_RGB8(RGB8 *entry, int r, int g, int b) {
|
||||
entry->r = (byte)r;
|
||||
entry->g = (byte)g;
|
||||
entry->b = (byte)b;
|
||||
}
|
||||
|
||||
void gr_pal_set_range(RGB8 *pal, int first_color, int num_colors) {
|
||||
g_system->getPaletteManager()->setPalette((const byte *)pal + first_color * 3,
|
||||
first_color, num_colors);
|
||||
}
|
||||
|
||||
void gr_pal_set_range(int first_color, int num_colors) {
|
||||
gr_pal_set_range(_G(master_palette), first_color, num_colors);
|
||||
}
|
||||
|
||||
void gr_pal_set_entry(int32 index, RGB8 *entry) {
|
||||
g_system->getPaletteManager()->setPalette((const byte *)entry, index, 1);
|
||||
}
|
||||
|
||||
void gr_pal_clear_range(RGB8 *palette, int first_color, int last_color) {
|
||||
for (int i = first_color; i <= last_color; i++) {
|
||||
palette[i].r = 0;
|
||||
palette[i].g = 0;
|
||||
palette[i].b = 0;
|
||||
}
|
||||
|
||||
gr_pal_set_range(palette, first_color, last_color - first_color);
|
||||
}
|
||||
|
||||
uint8 gr_pal_find_best_match(RGB8 *pal, uint8 r, uint8 g, uint8 b) {
|
||||
int index = 0;
|
||||
uint32 minDist = 0x7fffffff;
|
||||
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
const int Rdiff = r - pal[i].r;
|
||||
const int Gdiff = g - pal[i].g;
|
||||
const int Bdiff = b - pal[i].b;
|
||||
if (Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff < (int)minDist) {
|
||||
minDist = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint8)index;
|
||||
}
|
||||
|
||||
void gr_pal_interface(RGB8 *fixpal) {
|
||||
if (_GI().set_interface_palette(fixpal))
|
||||
return;
|
||||
|
||||
// Low intensity
|
||||
gr_pal_set_RGB8(&fixpal[0], 0, 0, 0); // r0 g0 b0 black
|
||||
gr_pal_set_RGB8(&fixpal[1], 0, 0, 168); // r0 g0 b2 blue
|
||||
gr_pal_set_RGB8(&fixpal[2], 0, 168, 0); // r0 g2 b0 green
|
||||
gr_pal_set_RGB8(&fixpal[3], 0, 168, 168); // r0 g2 b2 cyan
|
||||
|
||||
gr_pal_set_RGB8(&fixpal[4], 168, 0, 0); // r2 g0 b0 red
|
||||
gr_pal_set_RGB8(&fixpal[5], 168, 0, 168); // r2 g0 b2 violet
|
||||
gr_pal_set_RGB8(&fixpal[6], 168, 92, 0); // r2 g1 b0 brown
|
||||
gr_pal_set_RGB8(&fixpal[7], 168, 168, 168); // r2 g2 b2 light grey
|
||||
|
||||
// high intensity
|
||||
gr_pal_set_RGB8(&fixpal[8], 92, 92, 92); // r1 g1 b1 dark grey
|
||||
gr_pal_set_RGB8(&fixpal[9], 92, 92, 255); // r1 g1 b2 light blue
|
||||
gr_pal_set_RGB8(&fixpal[10], 92, 255, 92); // r1 g2 b1 light green
|
||||
gr_pal_set_RGB8(&fixpal[11], 92, 255, 255); // r1 g2 b2 light cyan
|
||||
|
||||
gr_pal_set_RGB8(&fixpal[12], 255, 92, 92); // r2 g1 b1 light red
|
||||
gr_pal_set_RGB8(&fixpal[13], 255, 92, 255); // r2 g1 b2 pink
|
||||
gr_pal_set_RGB8(&fixpal[14], 255, 255, 23); // r2 g2 b1 yellow
|
||||
gr_pal_set_RGB8(&fixpal[15], 255, 255, 255);// r1 g1 b1 white
|
||||
}
|
||||
|
||||
void gr_pal_reset_ega_colors(RGB8 *pal) {
|
||||
EGAcolors[0] = gr_pal_find_best_match(pal, 0, 0, 0); //__BLACK
|
||||
EGAcolors[1] = gr_pal_find_best_match(pal, 0, 0, 255); //__BLUE
|
||||
EGAcolors[2] = gr_pal_find_best_match(pal, 0, 255, 0); //__GREEN
|
||||
EGAcolors[3] = gr_pal_find_best_match(pal, 0, 255, 255); //__CYAN
|
||||
EGAcolors[4] = gr_pal_find_best_match(pal, 255, 0, 0); //__RED
|
||||
EGAcolors[5] = gr_pal_find_best_match(pal, 255, 0, 255); //__VIOLET
|
||||
EGAcolors[6] = gr_pal_find_best_match(pal, 168, 84, 84); //__BROWN
|
||||
EGAcolors[7] = gr_pal_find_best_match(pal, 168, 168, 168); //__LTGRAY
|
||||
EGAcolors[8] = gr_pal_find_best_match(pal, 84, 84, 84); //__DKGRAY
|
||||
EGAcolors[9] = gr_pal_find_best_match(pal, 0, 0, 127); //__LTBLUE
|
||||
EGAcolors[10] = gr_pal_find_best_match(pal, 0, 127, 0); //__LTGREEN
|
||||
EGAcolors[11] = gr_pal_find_best_match(pal, 0, 127, 127); //__LTCYAN
|
||||
EGAcolors[12] = gr_pal_find_best_match(pal, 84, 0, 0); //__LTRED
|
||||
EGAcolors[13] = gr_pal_find_best_match(pal, 84, 0, 0); //__PINK
|
||||
EGAcolors[14] = gr_pal_find_best_match(pal, 0, 84, 84); //__YELLOW
|
||||
EGAcolors[15] = gr_pal_find_best_match(pal, 255, 255, 255); //__WHITE
|
||||
}
|
||||
|
||||
void gr_backup_palette() {
|
||||
Common::copy(_G(master_palette), _G(master_palette) + 256, _G(backup_palette));
|
||||
}
|
||||
|
||||
void gr_restore_palette() {
|
||||
Common::copy(_G(backup_palette), _G(backup_palette) + 256, _G(master_palette));
|
||||
}
|
||||
|
||||
void pal_mirror_colours(int first_color, int last_color, RGB8 *pal) {
|
||||
if (first_color < 0 || last_color > 255 || first_color > last_color)
|
||||
error_show(FL, 'Burg', "pal_mirror_colours index error");
|
||||
|
||||
const int num_colors = last_color - first_color + 1;
|
||||
for (int index = 0; index < num_colors; ++index) {
|
||||
RGB8 *destP = pal + (last_color + num_colors - index);
|
||||
RGB8 *srcP = pal + (first_color + index);
|
||||
*destP = *srcP;
|
||||
}
|
||||
}
|
||||
|
||||
void pal_mirror_colours(int first_color, int last_color) {
|
||||
pal_mirror_colours(first_color, last_color, _G(master_palette));
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
74
engines/m4/graphics/gr_pal.h
Normal file
74
engines/m4/graphics/gr_pal.h
Normal file
@@ -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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_PAL_H
|
||||
#define M4_GRAPHICS_GR_PAL_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
constexpr int MIN_PAL_ENTRY = 1;
|
||||
constexpr int MAX_PAL_ENTRY = 255;
|
||||
|
||||
#define __BLACK (gr_pal_get_ega_color(0))
|
||||
#define __BLUE (gr_pal_get_ega_color(1))
|
||||
#define __GREEN (gr_pal_get_ega_color(2))
|
||||
#define __CYAN (gr_pal_get_ega_color(3))
|
||||
#define __RED (gr_pal_get_ega_color(4))
|
||||
#define __VIOLET (gr_pal_get_ega_color(5))
|
||||
#define __BROWN (gr_pal_get_ega_color(6))
|
||||
#define __LTGRAY (gr_pal_get_ega_color(7))
|
||||
#define __DKGRAY (gr_pal_get_ega_color(8))
|
||||
#define __LTBLUE (gr_pal_get_ega_color(9))
|
||||
#define __LTGREEN (gr_pal_get_ega_color(10))
|
||||
#define __LTCYAN (gr_pal_get_ega_color(11))
|
||||
#define __LTRED (gr_pal_get_ega_color(12))
|
||||
#define __PINK (gr_pal_get_ega_color(13))
|
||||
#define __YELLOW (gr_pal_get_ega_color(14))
|
||||
#define __WHITE (gr_pal_get_ega_color(15))
|
||||
|
||||
uint8 gr_pal_get_ega_color(uint8 myColor);
|
||||
|
||||
void gr_color_create_ipl5(uint8 *inverseColorTable, char *fname, int room_num);
|
||||
uint8 *gr_color_load_ipl5(const char *filename, uint8 *inverseColors);
|
||||
void gr_color_set(int32 c);
|
||||
byte gr_color_get_current();
|
||||
|
||||
void gr_pal_set_range(RGB8 *pal, int first_color, int num_colors);
|
||||
void gr_pal_set_range(int first_color, int num_colors);
|
||||
void gr_pal_set(RGB8 *pal);
|
||||
void gr_pal_set_RGB8(RGB8 *entry, int r, int g, int b);
|
||||
void gr_pal_set_entry(int32 index, RGB8 *entry);
|
||||
void gr_pal_clear(RGB8 *palette);
|
||||
void gr_pal_clear_range(RGB8 *palette, int first_color, int last_color);
|
||||
uint8 gr_pal_find_best_match(RGB8 *pal, uint8 r, uint8 g, uint8 b);
|
||||
void gr_pal_interface(RGB8 *fixpal);
|
||||
void gr_pal_reset_ega_colors(RGB8 *pal);
|
||||
void gr_backup_palette();
|
||||
void gr_restore_palette();
|
||||
|
||||
void pal_mirror_colours(int first_color, int last_color, RGB8 *pal);
|
||||
void pal_mirror_colours(int first_color, int last_color);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
346
engines/m4/graphics/gr_series.cpp
Normal file
346
engines/m4/graphics/gr_series.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m4/graphics/gr_series.h"
|
||||
#include "m4/core/errors.h"
|
||||
#include "m4/wscript/ws_load.h"
|
||||
#include "m4/wscript/ws_machine.h"
|
||||
#include "m4/wscript/wst_regs.h"
|
||||
#include "m4/vars.h"
|
||||
#include "m4/m4.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
void Series::play(const char *seriesName, frac16 layer, uint32 flags,
|
||||
int16 triggerNum, int32 frameRate, int32 loopCount, int32 s,
|
||||
int32 x, int32 y, int32 firstFrame, int32 lastFrame) {
|
||||
_series = M4::series_play(seriesName, layer, flags, triggerNum, frameRate,
|
||||
loopCount, s, x, y, firstFrame, lastFrame);
|
||||
|
||||
const Common::String shadow = Common::String::format("%ss", seriesName);
|
||||
_seriesS = M4::series_play(shadow.c_str(), layer + 1, flags, -1, frameRate,
|
||||
loopCount, s, x, y, firstFrame, lastFrame);
|
||||
}
|
||||
|
||||
void Series::show(const char *seriesName, frac16 layer, uint32 flags,
|
||||
int16 triggerNum, int32 duration, int32 index, int32 s, int32 x, int32 y) {
|
||||
_series = M4::series_show(seriesName, layer, flags, triggerNum, duration,
|
||||
index, s, x, y);
|
||||
|
||||
const Common::String shadow = Common::String::format("%ss", seriesName);
|
||||
_seriesS = M4::series_show(shadow.c_str(), layer + 1, flags, -1, duration,
|
||||
index, s, x, y);
|
||||
}
|
||||
|
||||
void Series::show(const char *series1, const char *series2, int layer) {
|
||||
_series = M4::series_show(series1, layer);
|
||||
_seriesS = M4::series_show(series2, layer + 1);
|
||||
}
|
||||
|
||||
void Series::show_index2(const char *series1, const char *series2, int layer, int index1, int index2) {
|
||||
_series = M4::series_show(series1, layer, 0, -1, -1, index1);
|
||||
_seriesS = M4::series_show(series2, layer + 1, 0, -1, -1, index1 + 1);
|
||||
}
|
||||
|
||||
void Series::series_play(const char *seriesName, frac16 layer, uint32 flags,
|
||||
int16 triggerNum, int32 frameRate, int32 loopCount, int32 s,
|
||||
int32 x, int32 y, int32 firstFrame, int32 lastFrame) {
|
||||
Series tmp;
|
||||
tmp.play(seriesName, layer, flags, triggerNum, frameRate,
|
||||
loopCount, s, x, y, firstFrame, lastFrame);
|
||||
}
|
||||
|
||||
void Series::series_show(const char *seriesName, frac16 layer, uint32 flags,
|
||||
int16 triggerNum, int32 duration, int32 index, int32 s, int32 x, int32 y) {
|
||||
Series tmp;
|
||||
tmp.show(seriesName, layer, flags, triggerNum, duration,
|
||||
index, s, x, y);
|
||||
}
|
||||
|
||||
|
||||
void Series::terminate() {
|
||||
if (_series)
|
||||
terminateMachineAndNull(_series);
|
||||
if (_seriesS)
|
||||
terminateMachineAndNull(_seriesS);
|
||||
}
|
||||
|
||||
|
||||
static void series_trigger_dispatch_callback(frac16 myMessage, machine * /*sender*/) {
|
||||
kernel_trigger_dispatchx(myMessage);
|
||||
}
|
||||
|
||||
int32 series_load(const char *seriesName, int32 assetIndex, RGB8 *myPal) {
|
||||
const int32 myAssetIndex = AddWSAssetCELS(seriesName, assetIndex, myPal);
|
||||
|
||||
if ((myAssetIndex < 0) || (myAssetIndex >= 256))
|
||||
error_show(FL, 'SPNF', seriesName);
|
||||
|
||||
return myAssetIndex;
|
||||
}
|
||||
|
||||
void series_unload(int32 assetIndex) {
|
||||
ClearWSAssets(_WS_ASSET_CELS, assetIndex, assetIndex);
|
||||
}
|
||||
|
||||
bool series_draw_sprite(int32 spriteHash, int32 index, Buffer *destBuff, int32 x, int32 y) {
|
||||
M4sprite srcSprite;
|
||||
M4Rect clipRect, updateRect;
|
||||
|
||||
if (!destBuff) {
|
||||
error_show(FL, 'BUF!');
|
||||
return false;
|
||||
}
|
||||
|
||||
M4sprite *srcSpritePtr = &srcSprite;
|
||||
if ((srcSpritePtr = GetWSAssetSprite(nullptr, (uint32)spriteHash, (uint32)index, srcSpritePtr, nullptr)) == nullptr)
|
||||
error_show(FL, 'SPNF', "hash: %d, index: %d", spriteHash, index);
|
||||
|
||||
HLock(srcSpritePtr->sourceHandle);
|
||||
//gr_pal_interface(&master_palette[0]);
|
||||
srcSpritePtr->data = (uint8 *)((intptr)*(srcSpritePtr->sourceHandle) + srcSpritePtr->sourceOffset);
|
||||
|
||||
RendGrBuff Destination;
|
||||
DrawRequestX dr;
|
||||
RendCell Frame;
|
||||
|
||||
Destination.Width = destBuff->stride;
|
||||
Destination.Height = destBuff->h;
|
||||
Destination.PixMap = (void *)destBuff->data;
|
||||
|
||||
dr.x = x;
|
||||
dr.y = y;
|
||||
dr.scale_x = 100;
|
||||
dr.scale_y = 100;
|
||||
dr.depth_map = destBuff->data;
|
||||
dr.Pal = nullptr;
|
||||
dr.ICT = nullptr;
|
||||
dr.depth = 0;
|
||||
|
||||
Frame.hot_x = srcSpritePtr->xOffset;
|
||||
Frame.hot_y = srcSpritePtr->yOffset;
|
||||
|
||||
Frame.Width = srcSpritePtr->w;
|
||||
Frame.Height = srcSpritePtr->h;
|
||||
Frame.Comp = (uint32)srcSpritePtr->encoding;
|
||||
Frame.data = srcSpritePtr->data;
|
||||
|
||||
clipRect.x1 = 0;
|
||||
clipRect.y1 = 0;
|
||||
clipRect.x2 = Destination.Width;
|
||||
clipRect.y2 = Destination.Height;
|
||||
|
||||
// and draw the sprite
|
||||
render_sprite_to_8BBM(&Destination, &dr, &Frame, &clipRect, &updateRect);
|
||||
|
||||
HUnLock(srcSpritePtr->sourceHandle);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool series_show_frame(int32 spriteHash, int32 index, Buffer *destBuff, int32 x, int32 y) {
|
||||
return series_draw_sprite(spriteHash, index, destBuff, x, y);
|
||||
}
|
||||
|
||||
machine *series_stream(const char *seriesName, int32 frameRate, int32 layer, int32 trigger) {
|
||||
SysFile *sysFile = new SysFile(seriesName);
|
||||
|
||||
// Store the frameRate in g_temp1
|
||||
// If it is < 0, the default frame rate for the ss will be used
|
||||
_G(globals)[GLB_TEMP_1] = frameRate << 16;
|
||||
|
||||
// Store the SysFile pointer
|
||||
_G(globals)[GLB_TEMP_4] = (intptr)sysFile;
|
||||
|
||||
// Set the callback trigger
|
||||
_G(globals)[GLB_TEMP_5] = kernel_trigger_create(trigger);
|
||||
|
||||
// Set the layer
|
||||
_G(globals)[GLB_TEMP_6] = layer << 16;
|
||||
|
||||
machine *m = kernel_spawn_machine(seriesName, HASH_STREAM_MACHINE, series_trigger_dispatch_callback);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool series_stream_break_on_frame(machine *m, int32 frameNum, int32 trigger) {
|
||||
// Parameter verification
|
||||
if (!m)
|
||||
return false;
|
||||
|
||||
_G(globals)[GLB_TEMP_2] = frameNum << 16;
|
||||
_G(globals)[GLB_TEMP_3] = kernel_trigger_create(trigger);
|
||||
|
||||
// Send the message to the machine to accept the new callback frame num and trigger
|
||||
sendWSMessage(0x10000, 0, m, 0, nullptr, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void series_set_frame_rate(machine *m, int32 newFrameRate) {
|
||||
if ((!m) || (!m->myAnim8) || !verifyMachineExists(m)) {
|
||||
if (g_engine->getGameType() == GType_Burger)
|
||||
error_show(FL, 'SSFR');
|
||||
return;
|
||||
}
|
||||
|
||||
m->myAnim8->myRegs[IDX_CELS_FRAME_RATE] = newFrameRate << 16;
|
||||
}
|
||||
|
||||
machine *series_show(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum,
|
||||
int32 duration, int32 index, int32 s, int32 x, int32 y) {
|
||||
int32 myAssetIndex;
|
||||
RGB8 *tempPalettePtr = nullptr;
|
||||
|
||||
term_message(seriesName);
|
||||
|
||||
if (flags & SERIES_LOAD_PALETTE)
|
||||
tempPalettePtr = &_G(master_palette)[0];
|
||||
|
||||
if ((myAssetIndex = AddWSAssetCELS(seriesName, -1, tempPalettePtr)) < 0)
|
||||
error_show(FL, 'SPNF', seriesName);
|
||||
|
||||
_G(globals)[GLB_TEMP_1] = (frac16)myAssetIndex << 24; // cels hash
|
||||
_G(globals)[GLB_TEMP_2] = layer << 16; // layer
|
||||
|
||||
_G(globals)[GLB_TEMP_3] = kernel_trigger_create(triggerNum); // trigger
|
||||
|
||||
_G(globals)[GLB_TEMP_4] = duration << 16; // frame duration (-1=forever, 0=default)
|
||||
_G(globals)[GLB_TEMP_5] = index << 16; // index of series to show
|
||||
|
||||
_G(globals)[GLB_TEMP_6] = (s << 16) / 100; // scale
|
||||
_G(globals)[GLB_TEMP_7] = x << 16; // x
|
||||
_G(globals)[GLB_TEMP_8] = y << 16; // y
|
||||
|
||||
_G(globals)[GLB_TEMP_14] = (flags & SERIES_STICK) ? 0x10000 : 0; // stick to screen after trigger?
|
||||
_G(globals)[GLB_TEMP_16] = (flags & SERIES_HORZ_FLIP) ? 0x10000 : 0;// horizontal flip
|
||||
|
||||
machine *m = kernel_spawn_machine(seriesName, HASH_SERIES_SHOW_MACHINE, series_trigger_dispatch_callback);
|
||||
|
||||
if (!m)
|
||||
error_show(FL, 'WSMF', seriesName);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
machine *series_place_sprite(const char *seriesName, int32 index, int32 x, int32 y, int32 s, int32 layer) {
|
||||
return series_show(seriesName, layer, 0x40, -1, -1, index, s, x, y);
|
||||
}
|
||||
|
||||
machine *series_show_sprite(const char *seriesName, int32 index, int32 layer) {
|
||||
return series_show(seriesName, layer, 0x40, -1, -1, index);
|
||||
}
|
||||
|
||||
machine *series_play(const char *seriesName, frac16 layer, uint32 flags, int16 triggerNum,
|
||||
int32 frameRate, int32 loopCount, int32 s, int32 x, int32 y,
|
||||
int32 firstFrame, int32 lastFrame) {
|
||||
int32 myAssetIndex;
|
||||
RGB8 *tempPalettePtr = nullptr;
|
||||
|
||||
term_message(seriesName);
|
||||
|
||||
if (flags & SERIES_LOAD_PALETTE)
|
||||
tempPalettePtr = &_G(master_palette)[0];
|
||||
|
||||
if ((myAssetIndex = AddWSAssetCELS(seriesName, -1, tempPalettePtr)) < 0)
|
||||
error_show(FL, 'SPNF', seriesName);
|
||||
|
||||
_G(globals)[GLB_TEMP_1] = (frac16)myAssetIndex << 24; // cels hash
|
||||
_G(globals)[GLB_TEMP_2] = layer << 16; // layer
|
||||
|
||||
_G(globals)[GLB_TEMP_3] = kernel_trigger_create(triggerNum); // trigger
|
||||
|
||||
_G(globals)[GLB_TEMP_4] = frameRate << 16; // framerate
|
||||
_G(globals)[GLB_TEMP_5] = loopCount << 16; // loop count
|
||||
|
||||
_G(globals)[GLB_TEMP_6] = (s << 16) / 100; // scale
|
||||
_G(globals)[GLB_TEMP_7] = x << 16; // x
|
||||
_G(globals)[GLB_TEMP_8] = y << 16; // y
|
||||
|
||||
_G(globals)[GLB_TEMP_9] = firstFrame << 16; // first frame
|
||||
_G(globals)[GLB_TEMP_10] = lastFrame << 16; // last frame
|
||||
|
||||
_G(globals)[GLB_TEMP_11] = (flags & SERIES_PINGPONG) ? 0x10000 : 0; // ping pong
|
||||
_G(globals)[GLB_TEMP_12] = (flags & SERIES_BACKWARD) ? 0x10000 : 0; // backwards
|
||||
_G(globals)[GLB_TEMP_13] = (flags & SERIES_RANDOM) ? 0x10000 : 0; // random
|
||||
_G(globals)[GLB_TEMP_14] = (flags & SERIES_STICK) ? 0x10000 : 0; // stick to screen
|
||||
_G(globals)[GLB_TEMP_15] = (flags & SERIES_LOOP_TRIGGER) ? 0x10000 : 0; // trigger back every loop?
|
||||
_G(globals)[GLB_TEMP_16] = (flags & SERIES_HORZ_FLIP) ? 0x10000 : 0; // horizontal flip
|
||||
|
||||
machine *m = kernel_spawn_machine(seriesName, HASH_SERIES_PLAY_MACHINE, series_trigger_dispatch_callback);
|
||||
|
||||
if (!m)
|
||||
error_show(FL, 'WSMF', seriesName);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
machine *series_ranged_play(const char *seriesName, int32 loopCount, uint32 flags,
|
||||
int32 firstFrame, int32 lastFrame, int32 s, uint32 layer,
|
||||
int32 frameRate, int32 trigger, bool stickWhenDone) {
|
||||
if (loopCount == 1)
|
||||
loopCount = 0;
|
||||
if (stickWhenDone)
|
||||
flags |= 0x10;
|
||||
|
||||
return series_play(seriesName, layer, flags, trigger, frameRate,
|
||||
loopCount, s, 0, 0, firstFrame, lastFrame);
|
||||
}
|
||||
|
||||
machine *series_ranged_play_xy(const char *seriesName, int loopCount, int flags,
|
||||
int firstFrame, int lastFrame, int x, int y, int s, int layer,
|
||||
int frameRate, int trigger, bool stick_when_done) {
|
||||
if (loopCount == 1)
|
||||
loopCount = 0;
|
||||
if (stick_when_done)
|
||||
flags |= 0x10;
|
||||
|
||||
return series_play(seriesName, layer, flags, trigger, frameRate,
|
||||
loopCount, s, x, y, firstFrame, lastFrame);
|
||||
}
|
||||
|
||||
machine *series_plain_play(const char *seriesName, int32 loopCount, uint32 flags,
|
||||
int32 s, int32 layer, int32 frameRate, int32 trigger, bool stickWhenDone) {
|
||||
if (stickWhenDone)
|
||||
flags |= 0x10;
|
||||
if (loopCount == 1)
|
||||
loopCount = 0;
|
||||
|
||||
return series_play(seriesName, layer, flags, trigger, frameRate, loopCount, s);
|
||||
}
|
||||
|
||||
machine *series_play_xy(const char *seriesName, int loopCount, int flags,
|
||||
int x, int y, int scale, int layer, int frameRate, int trigger) {
|
||||
if (loopCount == 1)
|
||||
loopCount = 0;
|
||||
|
||||
return series_play(seriesName, layer, flags, trigger, frameRate,
|
||||
loopCount, scale, x, y);
|
||||
}
|
||||
|
||||
machine *series_simple_play(const char *seriesName, frac16 layer, bool stickWhenDone) {
|
||||
int flags = 0;
|
||||
if (stickWhenDone)
|
||||
flags |= 0x10;
|
||||
|
||||
return series_play(seriesName, layer, flags);
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
126
engines/m4/graphics/gr_series.h
Normal file
126
engines/m4/graphics/gr_series.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_SERIES_H
|
||||
#define M4_GRAPHICS_GR_SERIES_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
#include "m4/wscript/ws_machine.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
constexpr uint32 SERIES_FORWARD = 0;
|
||||
constexpr uint32 SERIES_PINGPONG = 1;
|
||||
constexpr uint32 SERIES_BACKWARD = 2;
|
||||
constexpr uint32 SERIES_RANDOM = 4; // series is played in random order, trigger after number of frames in range played
|
||||
constexpr uint32 SERIES_NO_TOSS = 8; // series is not tossed at the end of playing
|
||||
constexpr uint32 SERIES_STICK = 16; // series sticks on last frame, then sends trigger
|
||||
constexpr uint32 SERIES_LOOP_TRIGGER = 32; // get trigger back every loop
|
||||
constexpr uint32 SERIES_LOAD_PALETTE = 64; // load master_palette with colours?
|
||||
constexpr uint32 SERIES_HORZ_FLIP = 128; // horizontal flip
|
||||
|
||||
// Old constants
|
||||
constexpr uint32 FORWARD = 0;
|
||||
constexpr uint32 PINGPONG = 1;
|
||||
constexpr uint32 BACKWARD = 2;
|
||||
constexpr uint32 STICK = 4;
|
||||
constexpr uint32 NO_TOSS = 8;
|
||||
|
||||
enum {
|
||||
HASH_SERIES_PLAY_MACHINE = 0,
|
||||
HASH_SERIES_SHOW_MACHINE = 1,
|
||||
// HASH_TIMER_MACHINE = 2, // defined in adv.h
|
||||
|
||||
HASH_STREAM_MACHINE = 6
|
||||
};
|
||||
|
||||
/**
|
||||
* Since series are normally started in pairs, this simplifies doing so
|
||||
*/
|
||||
struct Series {
|
||||
machine *_series = nullptr;
|
||||
machine *_seriesS = nullptr;
|
||||
|
||||
void play(const char *seriesName, frac16 layer, uint32 flags = 0,
|
||||
int16 triggerNum = -1, int32 frameRate = 6, int32 loopCount = 0, int32 s = 100,
|
||||
int32 x = 0, int32 y = 0, int32 firstFrame = 0, int32 lastFrame = -1);
|
||||
void show(const char *seriesName, frac16 layer, uint32 flags = 0,
|
||||
int16 triggerNum = -1, int32 duration = -1, int32 index = 0, int32 s = 100,
|
||||
int32 x = 0, int32 y = 0);
|
||||
void show(const char *series1, const char *series2, int layer);
|
||||
void show_index2(const char *series1, const char *series2, int layer, int index1, int index2);
|
||||
void terminate();
|
||||
|
||||
operator bool() const {
|
||||
return _series != nullptr;
|
||||
}
|
||||
|
||||
machine *&operator[](uint idx) {
|
||||
return (idx == 0) ? _series : _seriesS;
|
||||
}
|
||||
|
||||
frac16 *regs() const {
|
||||
return _series->myAnim8->myRegs;
|
||||
}
|
||||
|
||||
static void series_play(const char *seriesName, frac16 layer, uint32 flags = 0,
|
||||
int16 triggerNum = -1, int32 frameRate = 6, int32 loopCount = 0, int32 s = 100,
|
||||
int32 x = 0, int32 y = 0, int32 firstFrame = 0, int32 lastFrame = -1);
|
||||
static void series_show(const char *seriesName, frac16 layer, uint32 flags = 0,
|
||||
int16 triggerNum = -1, int32 duration = -1, int32 index = 0, int32 s = 100,
|
||||
int32 x = 0, int32 y = 0);
|
||||
};
|
||||
|
||||
int32 series_load(const char *seriesName, int32 assetIndex = -1, RGB8 *myPal = nullptr);
|
||||
void series_unload(int32 assetIndex);
|
||||
bool series_draw_sprite(int32 spriteHash, int32 index, Buffer *destBuff, int32 x, int32 y);
|
||||
|
||||
bool series_show_frame(int32 spriteHash, int32 index, Buffer *destBuff, int32 x, int32 y);
|
||||
machine *series_place_sprite(const char *seriesName, int32 index, int32 x, int32 y, int32 s, int32 layer);
|
||||
machine *series_show_sprite(const char *seriesName, int32 index, int32 layer);
|
||||
|
||||
machine *series_play(const char *seriesName, frac16 layer, uint32 flags = 0,
|
||||
int16 triggerNum = -1, int32 frameRate = 6, int32 loopCount = 0, int32 s = 100,
|
||||
int32 x = 0, int32 y = 0, int32 firstFrame = 0, int32 lastFrame = -1);
|
||||
machine *series_simple_play(const char *seriesName, frac16 layer, bool stickWhenDone);
|
||||
|
||||
machine *series_show(const char *seriesName, frac16 layer, uint32 flags = 0,
|
||||
int16 triggerNum = -1, int32 duration = -1, int32 index = 0, int32 s = 100,
|
||||
int32 x = 0, int32 y = 0);
|
||||
|
||||
machine *series_ranged_play(const char *seriesName, int32 loopCount, uint32 flags,
|
||||
int32 firstFrame, int32 lastFrame, int32 s, uint32 layer,
|
||||
int32 frameRate, int32 trigger = -1, bool stick_when_done = false);
|
||||
machine *series_ranged_play_xy(const char *seriesName, int loopCount, int flags,
|
||||
int firstFrame, int lastFrame, int x, int y, int s, int layer,
|
||||
int frameRate, int trigger = -1, bool stick_when_done = false);
|
||||
machine *series_plain_play(const char *seriesName, int32 loopCount, uint32 flags,
|
||||
int32 s, int32 layer, int32 frameRate, int32 trigger = -1, bool stickWhenDone = false);
|
||||
machine *series_play_xy(const char *seriesName, int loopCount, int flags,
|
||||
int x, int y, int scale, int layer, int frameRate, int trigger);
|
||||
|
||||
machine *series_stream(const char *seriesName, int32 frameRate, int32 layer, int32 trigger);
|
||||
bool series_stream_break_on_frame(machine *m, int32 frameNum, int32 trigger);
|
||||
void series_set_frame_rate(machine *m, int32 newFrameRate);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
262
engines/m4/graphics/gr_sprite.cpp
Normal file
262
engines/m4/graphics/gr_sprite.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/textconsole.h"
|
||||
#include "m4/graphics/gr_sprite.h"
|
||||
#include "m4/graphics/gr_surface.h"
|
||||
#include "m4/core/errors.h"
|
||||
#include "m4/core/imath.h"
|
||||
#include "m4/core/term.h"
|
||||
#include "m4/mem/memman.h"
|
||||
#include "m4/platform/draw.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
/**
|
||||
* ScaleX and ScaleY are supposed to be percents, where 100 means 100%
|
||||
* S and D are Raw encoded (unencoded!) buffers.
|
||||
*/
|
||||
static uint8 scale_sprite(Buffer *S, Buffer *D, uint32 ScaleX, uint32 ScaleY) {
|
||||
if (!D)
|
||||
error_show(FL, 'BUF!', "scale sprite NULL D");
|
||||
|
||||
if (!S)
|
||||
error_show(FL, 'BUF!', "scale sprite h:%d w:%d sx:%uld sy:%uld", D->h, D->w, ScaleX, ScaleY);
|
||||
|
||||
uint8 *pData = S->data;
|
||||
|
||||
/* calculate new x size */
|
||||
D->w = S->w * ScaleX / 100;
|
||||
if (S->w * ScaleX % 100 >= 50)
|
||||
++D->w;
|
||||
|
||||
/* calculate new y size */
|
||||
D->h = S->h * ScaleY / 100;
|
||||
if (S->h * ScaleY % 100 >= 50)
|
||||
++D->h;
|
||||
|
||||
D->stride = D->w;
|
||||
|
||||
/* allocate 'scaled' buffer */
|
||||
uint8 *pScaled = (uint8 *)mem_alloc(D->h * D->stride, "scaled buffer");
|
||||
if (!pScaled)
|
||||
error_show(FL, 'OOM!', "scaled buffer h:%uld w:%uld", D->h, D->stride);
|
||||
D->data = pScaled;
|
||||
|
||||
uint16 ErrY = 50;
|
||||
for (uint16 i = 0; i < S->h; ++i) {
|
||||
ErrY += ScaleY;
|
||||
while (ErrY >= 100) {
|
||||
uint16 ErrX = 50;
|
||||
for (uint16 j = 0; j < S->w; ++j) {
|
||||
ErrX += ScaleX;
|
||||
while (ErrX >= 100) {
|
||||
*pScaled++ = *pData;
|
||||
ErrX -= 100;
|
||||
}
|
||||
++pData;
|
||||
}
|
||||
ErrY -= 100;
|
||||
pData -= S->w;
|
||||
}
|
||||
pData += S->w;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define Scaled ((drawReq->scaleY != 100) || (drawReq->scaleX != 100 && drawReq->scaleX != -100))
|
||||
#define Rle (source.encoding == RLE8)
|
||||
#define Clipped ((drawReq->x < 0) || (drawReq->y < 0) || (drawReq->x + source.w > drawReq->Dest->w) || (drawReq->y + source.h > drawReq->Dest->h))
|
||||
#define Forward (drawReq->scaleX > 0)
|
||||
#define Depthed (drawReq->srcDepth)
|
||||
#define Shadow (source.encoding & 0x80)
|
||||
#define ClipD (leftOffset || rightOffset || bottomCut)
|
||||
|
||||
uint8 gr_sprite_draw(DrawRequest *drawReq) {
|
||||
Buffer source;
|
||||
uint8 *shadowBuff = nullptr, *scaledBuff = nullptr;
|
||||
Buffer afterScaled = { 0, 0, nullptr, 0, 0 };
|
||||
|
||||
if (!drawReq->Src) {
|
||||
term_message("nullptr source data in sprite_draw");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Negative scaleY means don't bother drawing this sprite
|
||||
if (drawReq->scaleY <= 0)
|
||||
return 0;
|
||||
|
||||
if (!drawReq->Src->w || !drawReq->Src->h)
|
||||
return 1;
|
||||
|
||||
// Copy DrawReq->Src to source buffer
|
||||
source = *drawReq->Src;
|
||||
assert(source.data);
|
||||
|
||||
// if it's RLE encoded, ensure the sprite will decode to match the expected size
|
||||
if (source.encoding & RLE8) {
|
||||
if (RLE8Decode_Size(source.data, source.stride) != (size_t)(source.stride * source.h))
|
||||
error_show(FL, 'RLE8', "RLE8 sprite suspected BAD!");
|
||||
}
|
||||
|
||||
// Check for RLE encoding in case of shadows
|
||||
// There is no RLE shadow draw routine, so we have to decode shadows ahead of time.
|
||||
if ((source.encoding & RLE8) && (source.encoding & SHADOW)) {
|
||||
if (!(shadowBuff = (uint8 *)mem_alloc(source.stride * source.h, "shadow buff")))
|
||||
error_show(FL, 'OOM!', "buffer w:%uld, h:%uld", source.w, source.h);
|
||||
|
||||
RLE8Decode(source.data, shadowBuff, source.stride);
|
||||
source.data = shadowBuff;
|
||||
source.encoding &= ~RLE8;
|
||||
}
|
||||
|
||||
// Check for scaling
|
||||
// We scale before we draw
|
||||
if (Scaled) {
|
||||
// Check if input is RLE8 encoded
|
||||
// If it's scaled we decode it first
|
||||
if (Rle) {
|
||||
if (!(scaledBuff = (uint8 *)mem_alloc(source.stride * source.h, "scaled buffer")))
|
||||
error_show(FL, 'OOM!', "no mem: buffer w:%d, h:%d", source.w, source.h);
|
||||
|
||||
RLE8Decode(source.data, scaledBuff, source.stride);
|
||||
source.data = scaledBuff;
|
||||
source.encoding &= ~RLE8;
|
||||
}
|
||||
|
||||
if (scale_sprite(&source, &afterScaled, imath_abs(drawReq->scaleX), imath_abs(drawReq->scaleY))) {
|
||||
if (shadowBuff)
|
||||
mem_free(shadowBuff);
|
||||
if (scaledBuff)
|
||||
mem_free(scaledBuff);
|
||||
|
||||
error_show(FL, 'SPSF', "gr_sprite_draw");
|
||||
}
|
||||
|
||||
// Preserve encoding
|
||||
afterScaled.encoding = source.encoding;
|
||||
|
||||
// Copy AfterScaled to source buffer
|
||||
source = afterScaled;
|
||||
}
|
||||
|
||||
const bool shadow = (drawReq->Src->encoding & SHADOW) != 0;
|
||||
assert(!shadow || drawReq->ICT);
|
||||
|
||||
M4Surface dst(*drawReq->Dest);
|
||||
dst.draw(source, drawReq->x, drawReq->y, drawReq->scaleX > 0,
|
||||
drawReq->srcDepth ? drawReq->depthCode : nullptr, drawReq->srcDepth,
|
||||
shadow ? drawReq->ICT : nullptr,
|
||||
drawReq->Pal);
|
||||
|
||||
if (shadowBuff)
|
||||
mem_free(shadowBuff);
|
||||
|
||||
if (scaledBuff)
|
||||
mem_free(scaledBuff);
|
||||
|
||||
if (afterScaled.data)
|
||||
mem_free(afterScaled.data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
//RLE8 COMPRESSION CODE...
|
||||
|
||||
#define ESC ((uint8)0)
|
||||
#define EOL ((uint8)0)
|
||||
#define EOB ((uint8)1)
|
||||
#define DELTA ((uint8)2)
|
||||
|
||||
#define OutBuffSize(x) ((x) + (((x) + 254) / 255 + 1) * 2 + 2)
|
||||
|
||||
static uint16 EncodeScan(uint8 *pi, uint8 *po, uint16 scanlen, uint8 EndByte) {
|
||||
uint8 *ps = pi + 1;
|
||||
uint16 outlen = 0, run;
|
||||
|
||||
while (scanlen) {
|
||||
uint16 limit = (scanlen < 255) ? scanlen : 255;
|
||||
|
||||
for (run = 1; run < limit && *pi == *ps; ++run, ++ps) {}
|
||||
|
||||
if (run > 1) {
|
||||
scanlen -= run;
|
||||
*po++ = run;
|
||||
*po++ = *pi;
|
||||
outlen += 2;
|
||||
pi = ps++;
|
||||
} else if (scanlen < 3) {
|
||||
for (; scanlen; --scanlen) {
|
||||
*po++ = 1;
|
||||
*po++ = *pi++;
|
||||
outlen += 2;
|
||||
}
|
||||
} else {
|
||||
--ps;
|
||||
do {
|
||||
++ps;
|
||||
while ((*ps != *(ps + 1) || *ps != *(ps + 2) || *ps != *(ps + 3)) && (ps - pi) < limit)
|
||||
++ps;
|
||||
} while ((run = ps - pi) < 3);
|
||||
|
||||
scanlen -= run;
|
||||
*po++ = ESC;
|
||||
*po++ = run;
|
||||
outlen += (run + 2);
|
||||
|
||||
for (limit = 0; limit < run; ++limit)
|
||||
*po++ = *pi++;
|
||||
++ps;
|
||||
}
|
||||
}
|
||||
|
||||
*po++ = ESC;
|
||||
*po = EndByte;
|
||||
outlen += 2;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
uint32 gr_sprite_RLE8_encode(Buffer *Source, Buffer *Dest) {
|
||||
int i;
|
||||
uint32 Offset = 0;
|
||||
|
||||
Dest->w = Source->w;
|
||||
Dest->h = Source->h;
|
||||
Dest->encoding = RLE8;
|
||||
Dest->stride = Source->stride;
|
||||
Dest->data = (uint8 *)mem_alloc(Source->h * OutBuffSize(Source->stride), "sprite data");
|
||||
|
||||
if (!Dest->data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < Source->h - 1; ++i)
|
||||
Offset += EncodeScan(Source->data + i * Source->stride, Dest->data + Offset, Source->w, EOL);
|
||||
|
||||
Offset += EncodeScan(Source->data + i * Source->stride, Dest->data + Offset, Source->w, EOB);
|
||||
|
||||
Dest->data = (uint8 *)mem_realloc(Dest->data, Offset, "rle8 sprite data");
|
||||
|
||||
return Offset;
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
54
engines/m4/graphics/gr_sprite.h
Normal file
54
engines/m4/graphics/gr_sprite.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_SPRITE_H
|
||||
#define M4_GRAPHICS_GR_SPRITE_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
enum {
|
||||
NO_COMPRESS = 0x00,
|
||||
RLE8 = 0x01,
|
||||
SHADOW = 0x80
|
||||
};
|
||||
|
||||
struct DrawRequest {
|
||||
Buffer *Src = nullptr; // sprite source buffer
|
||||
Buffer *Dest = nullptr; // destination buffer
|
||||
int32 x = 0; // x position relative to Destination(0, 0)
|
||||
int32 y = 0; // y position relative to Destination(0, 0)
|
||||
int32 scaleX = 0; // x scale factor (can be negative for reverse draw)
|
||||
int32 scaleY = 0; // y scale factor (can't be negative)
|
||||
uint8 *depthCode = nullptr; // depth code array for destination (doesn't care if srcDepth is 0)
|
||||
uint8 *Pal = nullptr; // palette for shadow draw (doesn't care if SHADOW bit is not set in Src.encoding)
|
||||
uint8 *ICT = nullptr; // Inverse Color Table (doesn't care if SHADOW bit is not set in Src.encoding)
|
||||
uint8 srcDepth = 0; // depth code for source (0 if no depth processing)
|
||||
};
|
||||
|
||||
|
||||
uint32 gr_sprite_RLE8_encode(Buffer *Source, Buffer *Dest);
|
||||
uint8 gr_sprite_draw(DrawRequest *DrawReq);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
194
engines/m4/graphics/gr_surface.cpp
Normal file
194
engines/m4/graphics/gr_surface.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "m4/graphics/gr_surface.h"
|
||||
#include "m4/graphics/gr_sprite.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
M4Surface::M4Surface(int sw, int sh) : Buffer() {
|
||||
this->w = sw;
|
||||
this->h = sh;
|
||||
this->stride = sw;
|
||||
this->encoding = NO_COMPRESS;
|
||||
this->data = new byte[sw * sh];
|
||||
Common::fill(this->data, this->data + sw * sh, 0);
|
||||
_disposeAfterUse = DisposeAfterUse::YES;
|
||||
}
|
||||
|
||||
M4Surface::M4Surface(const byte *src, int sw, int sh) {
|
||||
this->w = sw;
|
||||
this->h = sh;
|
||||
this->stride = sw;
|
||||
this->encoding = NO_COMPRESS;
|
||||
this->data = new byte[sw * sh];
|
||||
Common::fill(this->data, this->data + sw * sh, 0);
|
||||
_disposeAfterUse = DisposeAfterUse::YES;
|
||||
|
||||
rleDraw(src);
|
||||
}
|
||||
|
||||
M4Surface::~M4Surface() {
|
||||
if (_disposeAfterUse == DisposeAfterUse::YES)
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void M4Surface::rleDraw(const byte *src, int x, int y) {
|
||||
const byte *srcP = src;
|
||||
byte *destData = data + y * w + x;
|
||||
byte *destP = destData;
|
||||
int destWidth = w;
|
||||
byte count, val;
|
||||
int line = 0;
|
||||
|
||||
assert(x >= 0 && y >= 0 && x < w && y < h);
|
||||
|
||||
for (;;) {
|
||||
count = *srcP++;
|
||||
|
||||
if (count) {
|
||||
// Basic run length
|
||||
val = *srcP++;
|
||||
|
||||
// 0 pixels are transparent, and are skipped. Otherwise, draw pixels
|
||||
if (val != 0)
|
||||
Common::fill(destP, destP + count, val);
|
||||
destP += count;
|
||||
|
||||
} else {
|
||||
count = *srcP++;
|
||||
|
||||
if (count >= 3) {
|
||||
// Block of uncompressed pixels to copy
|
||||
for (; count > 0; --count, ++destP) {
|
||||
val = *srcP++;
|
||||
if (val != 0)
|
||||
*destP = val;
|
||||
}
|
||||
|
||||
} else if (!(count & 3)) {
|
||||
// End of line code
|
||||
++line;
|
||||
destP = destData + line * destWidth;
|
||||
|
||||
} else {
|
||||
// Stop drawing image. Seems weird that it doesn't handle the X/Y offset
|
||||
// form for count & 2, but the original explicitly doesn't implement it
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(destP <= (data + h * stride));
|
||||
}
|
||||
|
||||
void M4Surface::draw(const Buffer &src, int x, int y, bool forwards,
|
||||
const byte *depthCodes, int srcDepth, const byte *inverseColorTable,
|
||||
const byte *palette) {
|
||||
if ((src.encoding & 0x7f) == RLE8) {
|
||||
// The standard case of RLE sprite drawing onto screen can directly
|
||||
// use RLE decompression for performance
|
||||
if (forwards && !depthCodes && !inverseColorTable && x >= 0 && y >= 0 &&
|
||||
(x + src.w) <= this->w && (y + src.h) <= this->h) {
|
||||
rleDraw(src.data, x, y);
|
||||
|
||||
} else {
|
||||
// All other RLE drawing first decompresses the sprite, and then does
|
||||
// the various clipping, reverse, etc. on that
|
||||
M4Surface tmp(src.data, src.w, src.h);
|
||||
drawInner(tmp, depthCodes, x, y, forwards, srcDepth, palette, inverseColorTable);
|
||||
}
|
||||
} else {
|
||||
// Uncompressed images get passed to inner drawing
|
||||
drawInner(src, depthCodes, x, y, forwards, srcDepth, palette, inverseColorTable);
|
||||
}
|
||||
}
|
||||
|
||||
void M4Surface::drawInner(const Buffer &src, const byte *depthCodes, int x, int y,
|
||||
bool forwards, int srcDepth, const byte *palette, const byte *inverseColorTable) {
|
||||
assert((src.encoding & 0x7f) == NO_COMPRESS);
|
||||
|
||||
for (int srcY = 0; srcY < src.h; ++srcY, ++y) {
|
||||
if (y >= h)
|
||||
// Below bottom of screen
|
||||
break;
|
||||
else if (y < 0)
|
||||
// Above top of screen
|
||||
continue;
|
||||
|
||||
const byte *srcP = forwards ? src.getBasePtr(0, srcY) : src.getBasePtr(src.w - 1, srcY);
|
||||
byte *destP = getBasePtr(x, y);
|
||||
const byte *depthP = depthCodes ? depthCodes + y * w + x : nullptr;
|
||||
int deltaX = forwards ? 1 : -1;
|
||||
int destX = x;
|
||||
uint32 adjusted, total;
|
||||
|
||||
for (int srcX = 0; srcX < src.w; ++srcX, srcP += deltaX, ++destX) {
|
||||
if (destX >= w)
|
||||
// Beyond right of screen
|
||||
break;
|
||||
|
||||
byte v = *srcP;
|
||||
byte depth = depthP ? *depthP & 0xf : 0;
|
||||
if (destX >= 0 && v != 0 && (!depthP || depth == 0 || srcDepth < depth)) {
|
||||
if (inverseColorTable) {
|
||||
// Handling for shadows
|
||||
if (v != 128) {
|
||||
const byte *palP = palette + *destP * 3;
|
||||
uint rgb = (uint32)palP[0] | ((uint32)palP[1] << 8) |
|
||||
((uint32)palP[2] << 16);
|
||||
rgb >>= 2;
|
||||
|
||||
// Red component
|
||||
adjusted = (rgb & 0xff) * v;
|
||||
adjusted = MIN((uint)(adjusted >> 8), 31U);
|
||||
total = adjusted << 10;
|
||||
|
||||
// Green component
|
||||
rgb >>= 8;
|
||||
adjusted = (rgb & 0xff) * v;
|
||||
adjusted = MIN((uint)(adjusted >> 8), 31U);
|
||||
total |= (adjusted << 5);
|
||||
|
||||
// Blue component
|
||||
rgb >>= 8;
|
||||
adjusted = (rgb & 0xff) * v;
|
||||
adjusted = MIN((uint)(adjusted >> 8), 31U);
|
||||
total |= adjusted;
|
||||
|
||||
// Write out pixel from inverse table
|
||||
*destP = inverseColorTable[total];
|
||||
}
|
||||
} else {
|
||||
// Normal pixel
|
||||
*destP = v;
|
||||
}
|
||||
}
|
||||
|
||||
++destP;
|
||||
if (depthP)
|
||||
++depthP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
61
engines/m4/graphics/gr_surface.h
Normal file
61
engines/m4/graphics/gr_surface.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GR_SURFACE_H
|
||||
#define M4_GRAPHICS_GR_SURFACE_H
|
||||
|
||||
#include "common/types.h"
|
||||
#include "m4/m4_types.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
class M4Surface : public Buffer {
|
||||
private:
|
||||
DisposeAfterUse::Flag _disposeAfterUse = DisposeAfterUse::NO;
|
||||
|
||||
void drawInner(const Buffer &src, const byte *depthCodes, int x, int y,
|
||||
bool forwards, int srcDepth, const byte *palette, const byte *inverseColorTable);
|
||||
|
||||
public:
|
||||
M4Surface() : Buffer() {}
|
||||
M4Surface(const Buffer &src) : Buffer(src) {}
|
||||
M4Surface(int sw, int sh);
|
||||
M4Surface(const byte *src, int sw, int sh);
|
||||
|
||||
~M4Surface();
|
||||
|
||||
/**
|
||||
* Simple drawing at a given position given source RLE data.
|
||||
* In this simplified version, the sprite must be entirely on-screen
|
||||
*/
|
||||
void rleDraw(const byte *src, int x = 0, int y = 0);
|
||||
|
||||
/**
|
||||
* Main drawing
|
||||
*/
|
||||
void draw(const Buffer &src, int x, int y, bool forwards = true,
|
||||
const byte *depthCodes = nullptr, int srcDepth = -1,
|
||||
const byte *inverseColorTable = nullptr, const byte *palette = nullptr);
|
||||
};
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
88
engines/m4/graphics/graphics.h
Normal file
88
engines/m4/graphics/graphics.h
Normal file
@@ -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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_GRAPHICS_H
|
||||
#define M4_GRAPHICS_GRAPHICS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
constexpr int SCREEN_WIDTH = 640;
|
||||
constexpr int SCREEN_HEIGHT = 480;
|
||||
|
||||
#define FILL_INTERIOR 1 // a flag for use by DrawTile
|
||||
#define BORDER 0
|
||||
|
||||
#define COLOR_MAX_SHADOW_COLORS 3
|
||||
|
||||
#define FONT_SIZE 128
|
||||
#define FONT_MAX_WIDTH 255
|
||||
#define FONT_MAX_HEIGHT 200
|
||||
|
||||
//SS FILE DATA DEFINITIONS...
|
||||
#define HEAD_M4SS 0x4D345353 //'M4SS'
|
||||
#define HEAD_SS4M 0x5353344D //'SS4M'
|
||||
#define SS_FORMAT 101 //if it ever has to be printed, divide by 100
|
||||
|
||||
#define CELS__PAL 0x2050414C //' PAL'
|
||||
#define CELS_LAP_ 0x4C415020 //INTEL ' PAL'
|
||||
#define CELS___SS 0x20205353 //' SS'
|
||||
#define CELS_SS__ 0x53532020 //INTEL ' SS'
|
||||
|
||||
#define CELS_HEADER 0
|
||||
#define CELS_SRC_SIZE 1
|
||||
#define CELS_PACKING 2
|
||||
#define CELS_FRAME_RATE 3
|
||||
#define CELS_PIX_SPEED 4
|
||||
#define CELS_SS_MAX_W 5
|
||||
#define CELS_SS_MAX_H 6
|
||||
#define CELS_RSVD_3 7
|
||||
#define CELS_RSVD_4 8
|
||||
#define CELS_RSVD_5 9
|
||||
#define CELS_RSVD_6 10
|
||||
#define CELS_RSVD_7 11
|
||||
#define CELS_RSVD_8 12
|
||||
#define CELS_COUNT 13
|
||||
#define SS_HEAD_SIZE 14 //includes all the previous dwords
|
||||
#define CELS_OFFSETS 14
|
||||
|
||||
#define CELS_PACK 0
|
||||
#define CELS_STREAM 1
|
||||
#define CELS_X 2
|
||||
#define CELS_Y 3
|
||||
#define CELS_W 4
|
||||
#define CELS_H 5
|
||||
#define CELS_COMP 6
|
||||
#define INDV_RSVD_1 8
|
||||
#define INDV_RSVD_2 8
|
||||
#define INDV_RSVD_3 9
|
||||
#define INDV_RSVD_4 10
|
||||
#define INDV_RSVD_5 11
|
||||
#define INDV_RSVD_6 12
|
||||
#define INDV_RSVD_7 13
|
||||
#define INDV_RSVD_8 14
|
||||
#define SS_INDV_HEAD 15 //includes all the previous dwords
|
||||
#define CELS_DATA 15
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
862
engines/m4/graphics/krn_pal.cpp
Normal file
862
engines/m4/graphics/krn_pal.cpp
Normal file
@@ -0,0 +1,862 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
#include "m4/adv_r/adv_control.h"
|
||||
#include "m4/core/errors.h"
|
||||
#include "m4/core/imath.h"
|
||||
#include "m4/graphics/krn_pal.h"
|
||||
#include "m4/graphics/gr_pal.h"
|
||||
#include "m4/graphics/gr_series.h"
|
||||
#include "m4/gui/gui_sys.h"
|
||||
#include "m4/gui/gui_vmng.h"
|
||||
#include "m4/platform/keys.h"
|
||||
#include "m4/vars.h"
|
||||
#include "m4/m4.h"
|
||||
#include "m4/platform/timer.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
#define _GP(X) _G(krnPal)._##X
|
||||
|
||||
#define BACKGROUND_HEIGHT (int32)639
|
||||
|
||||
#define GREY_START (IS_RIDDLE ? 21 : 32)
|
||||
#define GREY_END (IS_RIDDLE ? 58 : 63)
|
||||
#define NUM_GREYS (1 + GREY_END - GREY_START)
|
||||
|
||||
#define FREE_START (GREY_END + 1)
|
||||
#define FREE_END 255
|
||||
#define NUM_FREE (255 - FREE_START + 1)
|
||||
|
||||
static HotkeyCB remember_esc_key;
|
||||
|
||||
void krn_pal_game_task() {
|
||||
g_engine->pal_game_task();
|
||||
}
|
||||
|
||||
static int32 screen_height(Buffer *grey_screen) {
|
||||
return imath_min(BACKGROUND_HEIGHT + _G(kernel).letter_box_y, grey_screen->h);
|
||||
}
|
||||
|
||||
static void grey_fade(RGB8 *pal, int32 to_from_flag, int32 from, int32 to, int32 steps, int32 delay) {
|
||||
RGB8 *working = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
|
||||
|
||||
// perform the fade
|
||||
for (int i = 1; i < steps; i++) {
|
||||
for (int j = from; j <= to; j++) {
|
||||
if (to_from_flag == TO_GREY) { // fade to grey from full color
|
||||
working[j].r = (Byte)((int)pal[j].r + ((((int)_GP(fadeToMe)[j].r - (int)pal[j].r) * i) / steps));
|
||||
working[j].g = (Byte)((int)pal[j].g + ((((int)_GP(fadeToMe)[j].g - (int)pal[j].g) * i) / steps));
|
||||
working[j].b = (Byte)((int)pal[j].b + ((((int)_GP(fadeToMe)[j].b - (int)pal[j].b) * i) / steps));
|
||||
} else if (to_from_flag == TO_COLOR) { // fade from grey to full color
|
||||
working[j].r = (Byte)((int)_GP(fadeToMe)[j].r + ((((int)pal[j].r - (int)_GP(fadeToMe)[j].r) * i) / steps));
|
||||
working[j].g = (Byte)((int)_GP(fadeToMe)[j].g + ((((int)pal[j].g - (int)_GP(fadeToMe)[j].g) * i) / steps));
|
||||
working[j].b = (Byte)((int)_GP(fadeToMe)[j].b + ((((int)pal[j].b - (int)_GP(fadeToMe)[j].b) * i) / steps));
|
||||
} else { //fade from grey to black
|
||||
working[j].r = (Byte)((int)_GP(fadeToMe)[j].r - ((((int)_GP(fadeToMe)[j].r) * i) / steps));
|
||||
working[j].g = (Byte)((int)_GP(fadeToMe)[j].g - ((((int)_GP(fadeToMe)[j].g) * i) / steps));
|
||||
working[j].b = (Byte)((int)_GP(fadeToMe)[j].b - ((((int)_GP(fadeToMe)[j].b) * i) / steps));
|
||||
}
|
||||
}
|
||||
|
||||
gr_pal_set_range(working, from, to - from + 1); ///set pal 21-255
|
||||
|
||||
// Time delay of "delay" milliseconds
|
||||
g_events->delay(delay);
|
||||
}
|
||||
|
||||
// Eliminate round off error
|
||||
if (to_from_flag == TO_GREY) {
|
||||
gr_pal_set_range(_GP(fadeToMe), from, to - from + 1); ///set pal 21-255
|
||||
} else if (to_from_flag == TO_COLOR) {
|
||||
gr_pal_set_range(pal, from, to - from + 1); ///set pal 21-255
|
||||
} else {
|
||||
for (int i = from; i <= to; i++) {
|
||||
pal[i].r = pal[i].g = pal[i].b = 0;
|
||||
}
|
||||
gr_pal_set_range(pal, from, to - from + 1); ///set pal 21-255
|
||||
}
|
||||
|
||||
mem_free(working);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// screen is the currently displayed screen
|
||||
// screenPicture is the data to restore the screen with
|
||||
// note: color 0 doesn't fade.
|
||||
|
||||
static void create_luminance_map(RGB8 *pal) {
|
||||
for (int i = GREY_START; i <= FREE_END; i++) {
|
||||
const Byte luminance = (Byte)((pal[i].r + pal[i].g + pal[i].b) / 3);
|
||||
_GP(fadeToMe)[i].g = luminance;
|
||||
// Orion Burger uses green shading, Riddle uses grey shading
|
||||
_GP(fadeToMe)[i].r = _GP(fadeToMe)[i].b = IS_RIDDLE ? luminance : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// finds the best matches for the in the greys in the grey ramp range using the free range greys
|
||||
// used to map greys out of the grey ramp area, and then again to map the grey ramp out of the grey ramp area!
|
||||
static void make_translation_table(RGB8 *pal) {
|
||||
for (int32 i = 0; i < NUM_GREYS; i++) {
|
||||
int32 bestMatch = FREE_START; // assume the first of the free indexes is best match to start with
|
||||
int32 minDist = 255; // assume that it's really far away to start with
|
||||
|
||||
if (!(i & 0x3ff)) {
|
||||
digi_read_another_chunk();
|
||||
midi_loop();
|
||||
}
|
||||
|
||||
// look for best match in the free indexes for the greys in GREY_START-GREY_END range (we need these available)
|
||||
const int32 matchGrey = pal[GREY_START + i].g; // Use green instead of red cause we're having a green screen
|
||||
|
||||
for (int32 j = FREE_START; j <= FREE_END; j++) {
|
||||
const int32 tryGrey = pal[j].g;
|
||||
if (imath_abs(tryGrey - matchGrey) < minDist) {
|
||||
minDist = imath_abs(tryGrey - matchGrey);
|
||||
bestMatch = j;
|
||||
}
|
||||
if (minDist == 0)
|
||||
break; // no need to continue searching if we found a perfect match
|
||||
}
|
||||
_GP(translation)[i] = (uint8)bestMatch;
|
||||
}
|
||||
}
|
||||
|
||||
void krn_fade_to_grey(RGB8 *pal, int32 steps, int32 delay) {
|
||||
if (_G(kernel).fading_to_grey) {
|
||||
return;
|
||||
}
|
||||
_G(kernel).fading_to_grey = true;
|
||||
|
||||
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
|
||||
|
||||
_GP(fadeToMe) = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
|
||||
_GP(trick) = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
|
||||
_GP(picPal) = (RGB8 *)mem_alloc(sizeof(RGB8) * 256, STR_FADEPAL);
|
||||
|
||||
memcpy(_GP(picPal), pal, sizeof(RGB8) * 256);
|
||||
create_luminance_map(pal);
|
||||
|
||||
grey_fade(pal, TO_GREY, GREY_START, GREY_END, steps, delay);
|
||||
|
||||
// Make translation table to translate colors using entries 59-255 into 21-58 range
|
||||
|
||||
for (int32 i = 0; i < (IS_RIDDLE ? 64 : 32); i++) {
|
||||
int32 bestMatch = IS_RIDDLE ? 63 : 65;
|
||||
int32 minDist = 255;
|
||||
|
||||
for (int32 j = FREE_START; j <= 255; j++) {
|
||||
if (imath_abs((_GP(fadeToMe)[j].r >> 2) - i) < minDist) {
|
||||
minDist = imath_abs((_GP(fadeToMe)[j].r >> 2) - i);
|
||||
bestMatch = j;
|
||||
}
|
||||
if (minDist == 0)
|
||||
// No need to continue searching if we found a perfect match
|
||||
break;
|
||||
}
|
||||
|
||||
_GP(translation)[i] = (uint8)bestMatch;
|
||||
}
|
||||
|
||||
// Palette now grey scale. Remap any pixels which are in the range 21-58 to the range 53-255
|
||||
// because we need to use those palette entries soon
|
||||
|
||||
uint8 *tempPtr = grey_screen->data;
|
||||
|
||||
// Note: this loop should be y0 to y1, x0 to x1, not a stride*h loop.
|
||||
for (int32 i = 0; i < (grey_screen->stride * grey_screen->h); i++) {
|
||||
if ((*tempPtr >= GREY_START) && (*tempPtr <= GREY_END)) {
|
||||
// Must move the pixel index to the best match in FREE_START-FREE_END range with _GP(translation) table
|
||||
*tempPtr = _GP(translation)[*tempPtr - GREY_START];
|
||||
}
|
||||
tempPtr++;
|
||||
|
||||
if (!(i & 0x3ff)) {
|
||||
_G(digi).task();
|
||||
_G(midi).task();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
|
||||
|
||||
// Make new trickPal with grey-scale ramp entries and load it into VGA registers
|
||||
memcpy(_GP(trick), _GP(fadeToMe), sizeof(RGB8) * 256); // trick pal is the greyed version plus the grey ramp overlayed on top
|
||||
const byte grey_step = 256 / NUM_GREYS;
|
||||
byte grey_ramp = 0;
|
||||
for (int32 i = GREY_START; i <= GREY_END; i++) {
|
||||
_GP(trick)[i].g = grey_ramp;
|
||||
_GP(trick)[i].r = _GP(trick)[i].b = IS_RIDDLE ? grey_ramp : 0;
|
||||
grey_ramp += grey_step;
|
||||
}
|
||||
|
||||
gr_pal_set_range(_GP(trick), GREY_START, NUM_GREYS);
|
||||
remap_buffer_with_luminance_map(grey_screen, 0, 0, grey_screen->w - 1, screen_height(grey_screen) - 1);
|
||||
|
||||
_G(gameDrawBuff)->release();
|
||||
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
|
||||
}
|
||||
|
||||
void krn_fade_from_grey(RGB8 *pal, int32 steps, int32 delay, int32 fadeType) {
|
||||
if (!_G(kernel).fading_to_grey) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the screen
|
||||
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
|
||||
|
||||
// load original faded greys into the free indexes (no pixels have these indexes yet)
|
||||
gr_pal_set_range(_GP(fadeToMe), FREE_START, NUM_FREE); // Load fadeToMe colors into VGA
|
||||
|
||||
make_translation_table(_GP(trick)); // This is used in fade_to_grey too!
|
||||
|
||||
// for every pixel in the screen, move any pixel in the GREY_START-GREY_END range out in to the free range
|
||||
uint8 *tempPtr = grey_screen->data;
|
||||
// note: this loop should be y0 to y1, x0 to x1, not a stride*h loop.
|
||||
for (int32 i = 0; i < (grey_screen->stride * grey_screen->h); ++i) {
|
||||
if (!(i & 0x3ff)) {
|
||||
_G(digi).task();
|
||||
_G(midi).task();
|
||||
}
|
||||
|
||||
// if the pixel is within the GREY range, move it to where the _GP(translation) table says
|
||||
if ((*tempPtr >= GREY_START) && (*tempPtr <= GREY_END)) {
|
||||
*tempPtr = _GP(translation)[*tempPtr - GREY_START];
|
||||
}
|
||||
tempPtr++;
|
||||
}
|
||||
|
||||
// Remapped indexes out of grey ramp
|
||||
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
|
||||
// Setting grey ramp indexes back to picture greys
|
||||
gr_pal_set_range(_GP(fadeToMe), GREY_START, NUM_GREYS); // get the rest of the original re-luminance colors
|
||||
|
||||
//recopy screenPicture to screen to restore original pixels
|
||||
krn_UnsetGreyVideoMode();
|
||||
RestoreScreens(0, 0, MAX_VIDEO_X, MAX_VIDEO_Y);
|
||||
|
||||
memcpy(pal, _GP(picPal), sizeof(RGB8) * 256);
|
||||
|
||||
ws_RefreshWoodscriptBuffer(_G(game_bgBuff)->get_buffer(), &(_G(currentSceneDef).depth_table[0]),
|
||||
_G(screenCodeBuff)->get_buffer(), (uint8 *)&_G(master_palette)[0], _G(inverse_pal)->get_ptr());
|
||||
_G(game_bgBuff)->release();
|
||||
_G(inverse_pal)->release();
|
||||
|
||||
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
|
||||
|
||||
grey_fade(pal, fadeType, GREY_START, FREE_END, steps, delay);
|
||||
|
||||
mem_free((char *)_GP(trick));
|
||||
mem_free((char *)_GP(fadeToMe));
|
||||
mem_free((char *)_GP(picPal));
|
||||
_G(kernel).fading_to_grey = false;
|
||||
_G(gameDrawBuff)->release();
|
||||
gr_pal_set(_G(master_palette));
|
||||
}
|
||||
|
||||
void kernel_examine_inventory_object(const char *picName, RGB8 *pal, int steps, int delay,
|
||||
int32 x, int32 y, int32 triggerNum, const char *digiName, int32 digiTrigger) {
|
||||
|
||||
remember_esc_key = GetSystemHotkey(KEY_ESCAPE);
|
||||
RemoveSystemHotkey(KEY_ESCAPE);
|
||||
|
||||
interface_hide();
|
||||
|
||||
_GP(exam_saved_hotspots) = _G(currentSceneDef).hotspots;
|
||||
_G(currentSceneDef).hotspots = nullptr;
|
||||
|
||||
_GP(myFadeTrigger) = kernel_trigger_create(triggerNum);
|
||||
|
||||
krn_fade_to_grey(pal, steps, delay);
|
||||
|
||||
_GP(seriesHash) = series_load(picName, -1, pal); // Preload sprite so we can unload it
|
||||
gr_pal_set_range(pal, FREE_START, NUM_FREE); // Set that series colors into VGA
|
||||
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
|
||||
|
||||
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
|
||||
krn_SetGreyVideoMode(
|
||||
// Grey rectangle
|
||||
0, 0, MAX_VIDEO_X, screen_height(grey_screen) + _G(kernel).letter_box_y,
|
||||
|
||||
// Color rectangle
|
||||
x, y, x + ws_get_sprite_width(_GP(seriesHash), 0) - 1, y + ws_get_sprite_height(_GP(seriesHash), 0) - 1);
|
||||
_G(gameDrawBuff)->release();
|
||||
|
||||
// Play the sprite series as a loop
|
||||
int32 status;
|
||||
ScreenContext *game_buff_ptr = vmng_screen_find(_G(gameDrawBuff), &status);
|
||||
_GP(seriesAnim8) = series_play_xy(picName, -1, FORWARD,
|
||||
x - game_buff_ptr->x1, y - game_buff_ptr->y1, 100, 0, 7, -1);
|
||||
|
||||
if (digiName) {
|
||||
digi_play(digiName, 1, 255, digiTrigger);
|
||||
}
|
||||
|
||||
player_set_commands_allowed(true);
|
||||
|
||||
cycleEngines(_G(game_bgBuff)->get_buffer(),
|
||||
&(_G(currentSceneDef).depth_table[0]),
|
||||
_G(screenCodeBuff)->get_buffer(),
|
||||
(uint8 *)&_G(master_palette)[0],
|
||||
_G(inverse_pal)->get_ptr(), true);
|
||||
|
||||
game_pause(true);
|
||||
|
||||
_G(inverse_pal)->release();
|
||||
_G(game_bgBuff)->release();
|
||||
|
||||
pauseEngines();
|
||||
}
|
||||
|
||||
void kernel_examine_inventory_object(const char *picName, int steps, int delay,
|
||||
int32 x, int32 y, int32 triggerNum, const char *digiName, int32 digiTrigger) {
|
||||
kernel_examine_inventory_object(picName, _G(master_palette), steps, delay,
|
||||
x, y, triggerNum, digiName, digiTrigger);
|
||||
}
|
||||
|
||||
void kernel_unexamine_inventory_object(RGB8 *pal, int steps, int delay) {
|
||||
if (!_GP(seriesAnim8) || _GP(seriesHash) < 0)
|
||||
return;
|
||||
|
||||
player_set_commands_allowed(false);
|
||||
game_pause(false);
|
||||
unpauseEngines();
|
||||
|
||||
terminateMachine(_GP(seriesAnim8));
|
||||
series_unload(_GP(seriesHash));
|
||||
_GP(seriesAnim8) = nullptr;
|
||||
_GP(seriesHash) = 0;
|
||||
|
||||
Buffer *grey_screen = _G(gameDrawBuff)->get_buffer();
|
||||
krn_SetGreyVideoMode(0, 0, MAX_VIDEO_X, screen_height(grey_screen) + _G(kernel).letter_box_y, -1, -1, -1, -1);
|
||||
_G(gameDrawBuff)->release();
|
||||
|
||||
krn_pal_game_task();
|
||||
|
||||
krn_fade_from_grey(pal, steps, delay, TO_COLOR);
|
||||
|
||||
krn_pal_game_task();
|
||||
|
||||
// Set in kernel_examine_inventory_object (above)
|
||||
kernel_trigger_dispatchx(_GP(myFadeTrigger));
|
||||
|
||||
RestoreScreens(0, 0, MAX_VIDEO_X, MAX_VIDEO_Y);
|
||||
|
||||
_G(currentSceneDef).hotspots = _GP(exam_saved_hotspots);
|
||||
|
||||
interface_show();
|
||||
AddSystemHotkey(KEY_ESCAPE, remember_esc_key);
|
||||
}
|
||||
|
||||
|
||||
// This is an inplace remap
|
||||
// fadeToMe must already have been set up to correspond to the image on the screen
|
||||
void remap_buffer_with_luminance_map(Buffer *src, int32 x1, int32 y1, int32 x2, int32 y2) {
|
||||
if ((!src) || (!src->data)) return;
|
||||
|
||||
// WORKAROUND: Fix original bounding that could result in buffer overruns on final y2 line
|
||||
if (x1 < 0) x1 = 0;
|
||||
if (y1 < 0) y1 = 0;
|
||||
if (x2 >= src->w) x2 = src->w - 1;
|
||||
if (y2 >= src->h) y2 = src->h - 1;
|
||||
if (x2 <= x1 || y2 <= y1)
|
||||
return;
|
||||
|
||||
x2 -= x1;
|
||||
y2 -= y1;
|
||||
|
||||
for (int32 y = 0; y <= y2; y++) {
|
||||
uint8 *ptr = &src->data[(y + y1) * src->stride + x1];
|
||||
for (int32 x = 0; x <= x2; x++) {
|
||||
// Remap the greyed out pixel to the closest grey in GREY_START to GREY_END range
|
||||
// shift right 3, takes a 255 value and makes it out of 32 (the number of greys in reduced grey ramp)
|
||||
ptr[x] = (uint8)(GREY_START + (_GP(fadeToMe)[ptr[x]].g >> 3)); // Use green instead of red cause we're having a green screen
|
||||
}
|
||||
|
||||
if (!(y & 0xff)) {
|
||||
_G(digi).task();
|
||||
_G(midi).task();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void krn_SetGreyVideoMode(int32 grey_x1, int32 grey_y1, int32 grey_x2, int32 grey_y2, int32 color_x1, int32 color_y1, int32 color_x2, int32 color_y2) {
|
||||
_GP(greyAreaX1) = grey_x1;
|
||||
_GP(greyAreaY1) = grey_y1;
|
||||
_GP(greyAreaX2) = grey_x2;
|
||||
_GP(greyAreaY2) = grey_y2;
|
||||
|
||||
_GP(colorAreaX1) = color_x1;
|
||||
_GP(colorAreaY1) = color_y1;
|
||||
_GP(colorAreaX2) = color_x2;
|
||||
_GP(colorAreaY2) = color_y2;
|
||||
|
||||
_GP(greyVideoMode) = true;
|
||||
}
|
||||
|
||||
void krn_UnsetGreyVideoMode() {
|
||||
_GP(greyAreaX1) = -1;
|
||||
_GP(greyAreaY1) = -1;
|
||||
_GP(greyAreaX2) = -1;
|
||||
_GP(greyAreaY2) = -1;
|
||||
|
||||
_GP(colorAreaX1) = -1;
|
||||
_GP(colorAreaY1) = -1;
|
||||
_GP(colorAreaX2) = -1;
|
||||
_GP(colorAreaY2) = -1;
|
||||
|
||||
_GP(greyVideoMode) = false;
|
||||
}
|
||||
|
||||
bool krn_GetGreyMode() {
|
||||
return _GP(greyVideoMode);
|
||||
}
|
||||
|
||||
void krn_UpdateGreyArea(Buffer *greyOutThisBuffer, int32 scrnX, int32 scrnY, int32 greyX1, int32 greyY1, int32 greyX2, int32 greyY2) {
|
||||
if ((!_GP(greyVideoMode)) || (!greyOutThisBuffer) || (!greyOutThisBuffer->data)) {
|
||||
return;
|
||||
}
|
||||
int32 x1 = imath_max(greyX1 + scrnX, _GP(greyAreaX1));
|
||||
int32 y1 = imath_max(greyY1 + scrnY, _GP(greyAreaY1));
|
||||
const int32 x2 = imath_min(greyX2 + scrnX, _GP(greyAreaX2));
|
||||
int32 y2 = imath_min(greyY2 + scrnY, _GP(greyAreaY2));
|
||||
if ((x1 > x2) || (y1 > y2)) return;
|
||||
bool finished = false;
|
||||
if (!finished) {
|
||||
if (y1 < _GP(colorAreaY1)) {
|
||||
remap_buffer_with_luminance_map(greyOutThisBuffer,
|
||||
x1 - scrnX, y1 - scrnY, x2 - scrnX, imath_min(y2, _GP(colorAreaY1) - 1) - scrnY);
|
||||
y1 = imath_min(y2, _GP(colorAreaY1));
|
||||
if (y1 >= y2)
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
if (!finished) {
|
||||
if (y2 > _GP(colorAreaY2)) {
|
||||
remap_buffer_with_luminance_map(greyOutThisBuffer,
|
||||
x1 - scrnX, imath_max(y1, _GP(colorAreaY2) + 1) - scrnY, x2 - scrnX, y2 - scrnY);
|
||||
y2 = imath_max(y1, _GP(colorAreaY2));
|
||||
if (y1 >= y2)
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
if (!finished) {
|
||||
if (x1 < _GP(colorAreaX1)) {
|
||||
remap_buffer_with_luminance_map(greyOutThisBuffer,
|
||||
x1 - scrnX, y1 - scrnY, imath_min(x2, _GP(colorAreaX1) - 1) - scrnX, y2 - scrnY);
|
||||
x1 = imath_min(x2, _GP(colorAreaX1));
|
||||
if (x1 >= x2)
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
if (!finished) {
|
||||
if (x2 > _GP(colorAreaX2)) {
|
||||
remap_buffer_with_luminance_map(greyOutThisBuffer,
|
||||
imath_max(x1, _GP(colorAreaX2) + 1) - scrnX, y1 - scrnY, x2 - scrnX, y2 - scrnY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void krn_ChangeBufferLuminance(Buffer *target, int32 percent) {
|
||||
uint8 luminancePal[256];
|
||||
|
||||
// Parameter verification
|
||||
if ((!target) || (!target->data)) {
|
||||
return;
|
||||
}
|
||||
if ((percent < 0) || (percent == 100)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (percent == 0) {
|
||||
gr_color_set(__BLACK);
|
||||
gr_buffer_rect_fill(target, 0, 0, target->w, target->h);
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the frac16 form of the percent
|
||||
const frac16 fracPercent = (percent * 255) / 100;
|
||||
|
||||
// Get the palette and the inverse palette
|
||||
RGB8 *pal = &_G(master_palette)[0];
|
||||
uint8 *inverse_palette = _G(inverse_pal)->get_ptr();
|
||||
if ((!pal) || (!inverse_palette)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the luminance Pal table
|
||||
for (int32 i = 0; i < 256; i++) {
|
||||
const int32 r = ((((pal[i].r * fracPercent) >> 10) >> 1)) & 0x1f;
|
||||
const int32 g = ((((pal[i].g * fracPercent) >> 10) >> 1)) & 0x1f;
|
||||
const int32 b = ((((pal[i].b * fracPercent) >> 10) >> 1)) & 0x1f;
|
||||
luminancePal[i] = inverse_palette[(r << 10) + (g << 5) + b];
|
||||
}
|
||||
|
||||
// Note: this loop should be y0 to y1, x0 to x1, not a stride*h loop.
|
||||
// Loop through every pixel replacing it with the index into the luminance table
|
||||
uint8 *tempPtr = target->data;
|
||||
for (int32 y = 0; y < target->h; y++) {
|
||||
for (int32 x = 0; x < target->stride; x++) {
|
||||
*tempPtr = luminancePal[*tempPtr];
|
||||
tempPtr++;
|
||||
//pixel = *tempPtr;
|
||||
}
|
||||
}
|
||||
|
||||
_G(inverse_pal)->release();
|
||||
}
|
||||
|
||||
|
||||
static void pal_fade_callback(frac16 myMessage) {
|
||||
_G(pal_fade_in_progress) = false;
|
||||
kernel_trigger_dispatchx((int32)myMessage);
|
||||
}
|
||||
|
||||
void pal_fade_init(RGB8 *origPalette, int32 firstPalEntry, int32 lastPalEntry,
|
||||
int32 targetPercent, int32 numTicks, int32 triggerNum) {
|
||||
if ((!origPalette) || (firstPalEntry < 0) || (lastPalEntry > 255) || (firstPalEntry > lastPalEntry))
|
||||
return;
|
||||
if ((targetPercent < 0) || (targetPercent > 100))
|
||||
return;
|
||||
|
||||
_GP(myFadeReq) = true;
|
||||
_GP(myFadeFinished) = false;
|
||||
_GP(myFadeStartTime) = timer_read_60();
|
||||
_GP(myFadeEndDelayTime) = timer_read_60();
|
||||
_GP(myFadeStartIndex) = firstPalEntry;
|
||||
_GP(myFadeEndIndex) = lastPalEntry;
|
||||
_GP(myFadeEndTime) = _GP(myFadeStartTime) + numTicks;
|
||||
_GP(myFadeTrigger) = kernel_trigger_create(triggerNum);
|
||||
_GP(myFadeStartPercentFrac) = _GP(myFadeCurrPercentFrac);
|
||||
_GP(myFadePercentFrac) = DivSF16(targetPercent << 16, 100 << 16);
|
||||
|
||||
// Disable_end_user_hot_keys();
|
||||
_G(pal_fade_in_progress) = true;
|
||||
}
|
||||
|
||||
void pal_fade_init(int32 firstPalEntry, int32 lastPalEntry, int32 targetPercent, int32 numTicks, int32 triggerNum) {
|
||||
pal_fade_init(_G(master_palette), firstPalEntry, lastPalEntry, targetPercent, numTicks, triggerNum);
|
||||
}
|
||||
|
||||
void disable_player_commands_and_fade_init(int trigger) {
|
||||
player_set_commands_allowed(false);
|
||||
pal_fade_init(_G(master_palette), _G(kernel).first_fade, 255, 0, 30, trigger);
|
||||
}
|
||||
|
||||
static void pal_fade_update(RGB8 *origPalette) {
|
||||
const int32 currTime = timer_read_60();
|
||||
|
||||
if (currTime >= _GP(myFadeEndDelayTime)) { // If the delay has expired, fade more
|
||||
frac16 tempFrac2;
|
||||
if (currTime >= _GP(myFadeEndTime)) {
|
||||
tempFrac2 = _GP(myFadePercentFrac);
|
||||
_GP(myFadeStartPercentFrac) = _GP(myFadePercentFrac);
|
||||
_GP(myFadeFinished) = true;
|
||||
} else if (currTime <= _GP(myFadeStartTime)) {
|
||||
return;
|
||||
} else {
|
||||
const frac16 tempFrac = DivSF16((currTime - _GP(myFadeStartTime)) << 16, (_GP(myFadeEndTime) - _GP(myFadeStartTime)) << 16);
|
||||
tempFrac2 = MulSF16(tempFrac, _GP(myFadePercentFrac) - _GP(myFadeStartPercentFrac)) + _GP(myFadeStartPercentFrac);
|
||||
}
|
||||
|
||||
_GP(myFadeCurrPercentFrac) = tempFrac2;
|
||||
|
||||
for (int32 i = _GP(myFadeStartIndex); i <= _GP(myFadeEndIndex); i++) {
|
||||
_GP(myFXPalette)[i].r = (Byte)(MulSF16(origPalette[i].r << 16, tempFrac2) >> 16);
|
||||
_GP(myFXPalette)[i].g = (Byte)(MulSF16(origPalette[i].g << 16, tempFrac2) >> 16);
|
||||
_GP(myFXPalette)[i].b = (Byte)(MulSF16(origPalette[i].b << 16, tempFrac2) >> 16);
|
||||
}
|
||||
|
||||
// Recalculate the end delay time again
|
||||
_GP(myFadeEndDelayTime) = currTime + _GP(myFadeDelayTicks); // Recalculate the end delay time again
|
||||
|
||||
// Must refresh the DAC
|
||||
_GP(myFadeDACrefresh) = true;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_DAC() {
|
||||
RGB8 color;
|
||||
|
||||
color.r = color.b = color.g = 0;
|
||||
for (int i = 0; i < 256; i++)
|
||||
gr_pal_set_entry(i, &color);
|
||||
}
|
||||
|
||||
void pal_fade_set_start(RGB8 *origPalette, int32 percent) {
|
||||
pal_fade_init(origPalette, _G(kernel).first_fade, 255, percent, 0, (uint)-1);
|
||||
pal_fade_update(origPalette);
|
||||
pal_fx_update();
|
||||
}
|
||||
|
||||
void pal_fade_set_start(int32 percent) {
|
||||
pal_fade_set_start(_G(master_palette), percent);
|
||||
}
|
||||
|
||||
static void pal_cycle_callback(frac16 myMessage) {
|
||||
kernel_trigger_dispatchx((uint32)myMessage);
|
||||
}
|
||||
|
||||
void pal_cycle_init(int32 firstPalEntry, int32 lastPalEntry,
|
||||
int32 delayTicks, int32 totalTicks, int32 triggerNum) {
|
||||
// Validation
|
||||
if ((firstPalEntry < 0) || (lastPalEntry > 255) || (firstPalEntry > lastPalEntry))
|
||||
return;
|
||||
if (delayTicks <= 0)
|
||||
return;
|
||||
|
||||
_GP(myCycleReq) = true;
|
||||
_GP(myCycleFinished) = false;
|
||||
_GP(myCycleDelayTicks) = delayTicks;
|
||||
_GP(myCycleStartTime) = timer_read_60();
|
||||
_GP(myCycleEndDelayTime) = timer_read_60();
|
||||
_GP(myCycleStartIndex) = firstPalEntry;
|
||||
_GP(myCycleEndIndex) = lastPalEntry;
|
||||
_GP(myCycleTrigger) = kernel_trigger_create(triggerNum); // Returned when myCycleEndTime is reached
|
||||
|
||||
if (totalTicks > 0) { // If totalTicks > 0, calculate end time
|
||||
_GP(myCycleEndTime) = _GP(myCycleStartTime) + totalTicks;
|
||||
_GP(myCycleNeverStopCycling) = false;
|
||||
|
||||
} else if (totalTicks < 0) { // If totalTicks < 0, never stop the cycling
|
||||
_GP(myCycleNeverStopCycling) = true;
|
||||
|
||||
} else { // If totalTicks is 0, stop cycling now
|
||||
_GP(myCycleReq) = false;
|
||||
_GP(myCycleFinished) = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool pal_cycle_active() {
|
||||
return _GP(myCycleReq);
|
||||
}
|
||||
|
||||
void pal_cycle_stop() {
|
||||
_GP(myCycleReq) = false;
|
||||
}
|
||||
|
||||
void pal_cycle_resume() {
|
||||
_GP(myCycleReq) = true;
|
||||
}
|
||||
|
||||
static void pal_cycle_update() {
|
||||
const int32 currTime = timer_read_60(); // Get current time
|
||||
|
||||
if (_GP(myCycleNeverStopCycling) == false) { // If there is an end time to get to...
|
||||
|
||||
if (currTime >= _GP(myCycleEndTime)) { // See if we have reached it
|
||||
_GP(myCycleFinished) = true; // Mark cycling as finished
|
||||
return; // Return
|
||||
}
|
||||
} else {
|
||||
// See if we should color cycle right now
|
||||
if (currTime >= _GP(myCycleEndDelayTime)) { // If the delay has expired, color cycle
|
||||
RGB8 firstColor;
|
||||
int32 i;
|
||||
// Cycle the master palette
|
||||
firstColor.r = _G(master_palette)[_GP(myCycleStartIndex)].r; // Remember first color
|
||||
firstColor.g = _G(master_palette)[_GP(myCycleStartIndex)].g;
|
||||
firstColor.b = _G(master_palette)[_GP(myCycleStartIndex)].b;
|
||||
for (i = _GP(myCycleStartIndex); i < _GP(myCycleEndIndex); ++i) { // Shift colors down one in palette
|
||||
_G(master_palette)[i].r = _G(master_palette)[i + 1].r;
|
||||
_G(master_palette)[i].g = _G(master_palette)[i + 1].g;
|
||||
_G(master_palette)[i].b = _G(master_palette)[i + 1].b;
|
||||
}
|
||||
_G(master_palette)[_GP(myCycleEndIndex)].r = firstColor.r; // Set last color to the first color
|
||||
_G(master_palette)[_GP(myCycleEndIndex)].g = firstColor.g;
|
||||
_G(master_palette)[_GP(myCycleEndIndex)].b = firstColor.b;
|
||||
|
||||
// Then cycle the FX palette
|
||||
firstColor.r = _GP(myFXPalette)[_GP(myCycleStartIndex)].r; // Remember first color
|
||||
firstColor.g = _GP(myFXPalette)[_GP(myCycleStartIndex)].g;
|
||||
firstColor.b = _GP(myFXPalette)[_GP(myCycleStartIndex)].b;
|
||||
for (i = _GP(myCycleStartIndex); i < _GP(myCycleEndIndex); ++i) { // Shift colors down one in palette
|
||||
_GP(myFXPalette)[i].r = _GP(myFXPalette)[i + 1].r;
|
||||
_GP(myFXPalette)[i].g = _GP(myFXPalette)[i + 1].g;
|
||||
_GP(myFXPalette)[i].b = _GP(myFXPalette)[i + 1].b;
|
||||
}
|
||||
_GP(myFXPalette)[_GP(myCycleEndIndex)].r = firstColor.r; // Set last color to the first color
|
||||
_GP(myFXPalette)[_GP(myCycleEndIndex)].g = firstColor.g;
|
||||
_GP(myFXPalette)[_GP(myCycleEndIndex)].b = firstColor.b;
|
||||
|
||||
|
||||
// Recalculate the end delay time again
|
||||
_GP(myCycleEndDelayTime) = currTime + _GP(myCycleDelayTicks); // Recalculate the end delay time again
|
||||
|
||||
// must refresh the DAC
|
||||
_GP(myCycleDACrefresh) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pal_fx_update() {
|
||||
int32 startA = 0, endA = 0, startB = 0, endB = 0, startDAC = 0, endDAC = 0;
|
||||
|
||||
if (!_GP(myCycleReq) && !_GP(myFadeReq))
|
||||
// Crap out quickly if no effects required
|
||||
return;
|
||||
|
||||
// Perform any effect required and track index ranges
|
||||
if (_GP(myCycleReq)) {
|
||||
pal_cycle_update(); // Do the cycling (cycles master_palette and _GP(myFXPalette))
|
||||
if (_GP(myCycleDACrefresh)) { // If it needs the DAC to be refreshed,
|
||||
startA = _GP(myCycleStartIndex); // remember the range
|
||||
endA = _GP(myCycleEndIndex);
|
||||
_GP(myCycleDACrefresh) = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_GP(myFadeReq)) {
|
||||
pal_fade_update(&_G(master_palette)[0]); // Do the fading (sets myFXPalette to faded master_palette)
|
||||
if (_GP(myFadeDACrefresh)) { // If it needs the DAC to be refreshed,
|
||||
startB = _GP(myFadeStartIndex); // remember the range
|
||||
endB = _GP(myFadeEndIndex);
|
||||
_GP(myFadeDACrefresh) = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check ranges to perform minimum calls of gr_pal_set_range().
|
||||
// This was originally done to minimize snow on monitor due to repeated OUT instructions
|
||||
if (endA < startB || endB < startA) {
|
||||
// if A and B ranges don't overlap
|
||||
if (!(startA == 0 && endA == 0)) // if this is not the degenerate case (just the transparent color)
|
||||
gr_pal_set_range(&_GP(myFXPalette)[0], startA, endA - startA + 1); // set A range of the DAC
|
||||
|
||||
if (!(startB == 0 && endB == 0)) // if this is not the degenerate case (just the transparent color)
|
||||
gr_pal_set_range(&_GP(myFXPalette)[0], startB, endB - startB + 1); // set B range of the DAC
|
||||
|
||||
} else {
|
||||
// They overlap, so find the extent of the overlap
|
||||
(startA < startB) ? (startDAC = startA) : (startDAC = startB); // which start is less
|
||||
(endA > endB) ? (endDAC = endA) : (endDAC = endB); // which end is more
|
||||
|
||||
if (!(startDAC == 0 && endDAC == 0)) // if this is not the degenerate case (just the transparent color)
|
||||
gr_pal_set_range(&_GP(myFXPalette)[0], startDAC, endDAC - startDAC + 1); // set the whole range of the DAC
|
||||
}
|
||||
|
||||
// Turn off flags and call callbacks if effects are finished
|
||||
if (_GP(myFadeReq) && _GP(myFadeFinished)) {
|
||||
_GP(myFadeReq) = false;
|
||||
pal_fade_callback(_GP(myFadeTrigger));
|
||||
}
|
||||
|
||||
if (_GP(myCycleReq) && _GP(myCycleFinished)) {
|
||||
_GP(myCycleReq) = false;
|
||||
pal_cycle_callback(_GP(myCycleTrigger));
|
||||
}
|
||||
}
|
||||
|
||||
void DAC_tint_range(const RGB8 *tintColor, int32 percent, int32 firstPalEntry, int32 lastPalEntry, bool transparent) {
|
||||
int32 i;
|
||||
int32 r, g, b, dr, dg, db;
|
||||
RGB8 color, targetColor;
|
||||
|
||||
if ((firstPalEntry < 0) || (lastPalEntry > 255) || (firstPalEntry > lastPalEntry)) {
|
||||
// This should generate an error
|
||||
term_message("*** palette index error");
|
||||
return;
|
||||
}
|
||||
|
||||
term_message("Color tint DAC to: %d %d %d, %d percent, range (%d - %d)",
|
||||
tintColor->r, tintColor->g, tintColor->b, percent, firstPalEntry, lastPalEntry);
|
||||
percent = DivSF16(percent << 16, 100 << 16); // convert percent to frac16 format
|
||||
|
||||
targetColor.r = tintColor->r;
|
||||
targetColor.g = tintColor->g;
|
||||
targetColor.b = tintColor->b;
|
||||
|
||||
term_message("Doing palette.....");
|
||||
|
||||
if (!transparent) {
|
||||
for (i = firstPalEntry; i <= lastPalEntry; ++i) {
|
||||
|
||||
// Calculate deltas for RGB's and put them in frac16 format
|
||||
dr = (targetColor.r - _G(master_palette)[i].r) << 16;
|
||||
dg = (targetColor.g - _G(master_palette)[i].g) << 16;
|
||||
db = (targetColor.b - _G(master_palette)[i].b) << 16;
|
||||
|
||||
// New = orig + (delta * percent)
|
||||
r = _G(master_palette)[i].r + (MulSF16(percent, dr) >> 16);
|
||||
g = _G(master_palette)[i].g + (MulSF16(percent, dg) >> 16);
|
||||
b = _G(master_palette)[i].b + (MulSF16(percent, db) >> 16);
|
||||
|
||||
// Check for under/overflow
|
||||
r = CLIP(r, int32(0), int32(255));
|
||||
g = CLIP(g, int32(0), int32(255));
|
||||
b = CLIP(b, int32(0), int32(255));
|
||||
|
||||
color.r = (byte)r;
|
||||
color.g = (byte)g;
|
||||
color.b = (byte)b;
|
||||
|
||||
gr_pal_set_entry(i, &color); // Set the new color to the DAC
|
||||
}
|
||||
|
||||
} else {
|
||||
// This is for filtering colors. For example, a completely red filter
|
||||
// (255, 0, 0) will block out the blue and green parts of the palette.
|
||||
// 50% of the same filter will block out only 50% of the blue and
|
||||
// green, but leaving all of the rest blue.
|
||||
for (i = firstPalEntry; i <= lastPalEntry; ++i) {
|
||||
// Converting rgb to a frac16 ( << 16) dividing by 256 ( >> 8)
|
||||
// (the range of the palette values)
|
||||
const int32 percent_r = (targetColor.r) << 8;
|
||||
const int32 percent_g = (targetColor.g) << 8;
|
||||
const int32 percent_b = (targetColor.b) << 8;
|
||||
|
||||
// This is the difference between the color and the full effect
|
||||
// of the filter at 100%, as a frac16.
|
||||
dr = (_G(master_palette)[i].r << 16) - (MulSF16(percent_r, _G(master_palette)[i].r << 16));
|
||||
dg = (_G(master_palette)[i].g << 16) - (MulSF16(percent_g, _G(master_palette)[i].g << 16));
|
||||
db = (_G(master_palette)[i].b << 16) - (MulSF16(percent_b, _G(master_palette)[i].b << 16));
|
||||
|
||||
// Scaling the effect to the right percentage. This is a frac16.
|
||||
dr = MulSF16(dr, percent);
|
||||
dg = MulSF16(dg, percent);
|
||||
db = MulSF16(db, percent);
|
||||
|
||||
// Subtract the result to palette.
|
||||
r = (_G(master_palette)[i].r - (dr >> 16));
|
||||
g = (_G(master_palette)[i].g - (dg >> 16));
|
||||
b = (_G(master_palette)[i].b - (db >> 16));
|
||||
|
||||
// Check for under/overflow
|
||||
r = CLIP(r, int32(0), int32(255));
|
||||
g = CLIP(g, int32(0), int32(255));
|
||||
b = CLIP(b, int32(0), int32(255));
|
||||
|
||||
color.r = (byte)r;
|
||||
color.g = (byte)g;
|
||||
color.b = (byte)b;
|
||||
|
||||
gr_pal_set_entry(i, &color); // Set new colors to DAC.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DAC_restore() {
|
||||
term_message("DAC restored");
|
||||
gr_pal_set_range(&_G(master_palette)[0], 0, 256);
|
||||
}
|
||||
|
||||
} // namespace M4
|
||||
142
engines/m4/graphics/krn_pal.h
Normal file
142
engines/m4/graphics/krn_pal.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_KRN_PAL_H
|
||||
#define M4_GRAPHICS_KRN_PAL_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
#include "m4/adv_r/adv_hotspot.h"
|
||||
#include "m4/wscript/ws_machine.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
#define TO_GREY (int32)0
|
||||
#define TO_COLOR (int32)1
|
||||
#define TO_BLACK (int32)2
|
||||
|
||||
struct KernelPal_Globals {
|
||||
RGB8 _myFXPalette[256];
|
||||
|
||||
bool _myCycleReq = false;
|
||||
bool _myCycleFinished = true;
|
||||
bool _myCycleDACrefresh = false;
|
||||
int32 _myCycleDelayTicks = 6; // 10 times a second
|
||||
int32 _myCycleStartTime = 0;
|
||||
int32 _myCycleEndTime = 0;
|
||||
int32 _myCycleEndDelayTime = 0;
|
||||
int32 _myCycleStartIndex = 0;
|
||||
int32 _myCycleEndIndex = 0;
|
||||
int32 _myCycleTrigger = 0;
|
||||
int32 _myCycleNeverStopCycling = false;
|
||||
|
||||
bool _myFadeReq = false;
|
||||
bool _myFadeFinished = true;
|
||||
bool _myFadeDACrefresh = false;
|
||||
int32 _myFadeDelayTicks = 3; // 20 times a second
|
||||
int32 _myFadeStartTime = 0;
|
||||
int32 _myFadeEndTime = 0;
|
||||
int32 _myFadeEndDelayTime = 0;
|
||||
int32 _myFadeStartIndex = 0;
|
||||
int32 _myFadeEndIndex = 0;
|
||||
int32 _myFadeTrigger = 0;
|
||||
frac16 _myFadeStartPercentFrac = 0x10000;
|
||||
frac16 _myFadeCurrPercentFrac = 0x10000;
|
||||
frac16 _myFadePercentFrac = 0;
|
||||
|
||||
HotSpotRec *_exam_saved_hotspots = nullptr;
|
||||
|
||||
RGB8 *_fadeToMe = nullptr;
|
||||
RGB8 *_trick = nullptr;
|
||||
RGB8 *_picPal = nullptr;
|
||||
int32 _seriesHash = 0;
|
||||
machine *_seriesAnim8 = nullptr;
|
||||
uint8 _translation[64];
|
||||
|
||||
int32 _colorAreaX1 = -1;
|
||||
int32 _colorAreaY1 = -1;
|
||||
int32 _colorAreaX2 = -1;
|
||||
int32 _colorAreaY2 = -1;
|
||||
|
||||
int32 _greyAreaX1 = -1;
|
||||
int32 _greyAreaY1 = -1;
|
||||
int32 _greyAreaX2 = -1;
|
||||
int32 _greyAreaY2 = -1;
|
||||
|
||||
bool _greyVideoMode = false;
|
||||
};
|
||||
|
||||
void pal_fade_set_start(RGB8 *origPalette, int32 percent);
|
||||
void pal_fade_set_start(int32 percent);
|
||||
void pal_fade_init(RGB8 *origPalette, int32 firstPalEntry, int32 lastPalEntry, int32 targetPercent, int32 numTicks, int32 triggerNum);
|
||||
void pal_fade_init(int32 firstPalEntry, int32 lastPalEntry, int32 targetPercent, int32 numTicks, int32 triggerNum);
|
||||
|
||||
void disable_player_commands_and_fade_init(int trigger);
|
||||
void pal_cycle_init(int32 firstPalEntry, int32 lastPalEntry, int32 delayTicks,
|
||||
int32 totalTicks = -1, int32 triggerNum = -1);
|
||||
|
||||
/**
|
||||
* Returns true if color cycling is on
|
||||
*/
|
||||
bool pal_cycle_active();
|
||||
|
||||
/**
|
||||
* Stops color cycling
|
||||
*/
|
||||
void pal_cycle_stop();
|
||||
|
||||
/**
|
||||
* Starts color cycling
|
||||
*/
|
||||
void pal_cycle_resume();
|
||||
|
||||
/**
|
||||
* Handles fading and cycling
|
||||
*/
|
||||
void pal_fx_update();
|
||||
|
||||
/**
|
||||
* This is used to effect the screen colours (not the master palette) temporarily
|
||||
* until something else updates the DAC e.g. refresh_DAC()
|
||||
*/
|
||||
void DAC_tint_range(const RGB8 *tintColor, int32 percent, int32 firstPalEntry, int32 lastPalEntry, bool transparent);
|
||||
|
||||
void kernel_examine_inventory_object(const char *picName, RGB8 *pal,
|
||||
int steps, int delay, int32 x, int32 y, int32 trigger,
|
||||
const char *digiName, int32 digiTrigger);
|
||||
void kernel_examine_inventory_object(const char *picName, int steps, int delay,
|
||||
int32 x, int32 y, int32 triggerNum, const char *digiName = nullptr, int32 digiTrigger = -1);
|
||||
void kernel_unexamine_inventory_object(RGB8 *pal, int steps, int delay);
|
||||
|
||||
void remap_buffer_with_luminance_map(Buffer *src, int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
void krn_SetGreyVideoMode(int32 grey_x1, int32 grey_y1, int32 grey_x2, int32 grey_y2, int32 color_x1, int32 color_y1, int32 color_x2, int32 color_y2);
|
||||
void krn_UnsetGreyVideoMode(void);
|
||||
bool krn_GetGreyMode(void);
|
||||
void krn_UpdateGreyArea(Buffer *greyOutThisBuffer, int32 scrnX, int32 scrnY,
|
||||
int32 greyX1, int32 greyY1, int32 greyX2, int32 greyY2);
|
||||
void krn_ChangeBufferLuminance(Buffer *target, int32 percent);
|
||||
|
||||
void krn_pal_game_task();
|
||||
void krn_fade_from_grey(RGB8 *pal, int32 steps, int32 delay, int32 fadeType);
|
||||
void krn_fade_to_grey(RGB8 *pal, int32 steps, int32 delay);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
1028
engines/m4/graphics/rend.cpp
Normal file
1028
engines/m4/graphics/rend.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
engines/m4/graphics/rend.h
Normal file
87
engines/m4/graphics/rend.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef M4_GRAPHICS_REND_H
|
||||
#define M4_GRAPHICS_REND_H
|
||||
|
||||
#include "m4/m4_types.h"
|
||||
#include "m4/gui/gui.h"
|
||||
|
||||
namespace M4 {
|
||||
|
||||
struct RGBcolor {
|
||||
uint8 b, g, r;
|
||||
};
|
||||
|
||||
struct RendGrBuff {
|
||||
uint32 Width = 0;
|
||||
uint32 Height = 0;
|
||||
void *PixMap = nullptr;
|
||||
byte encoding = 0;
|
||||
uint32 Pitch = 0;
|
||||
};
|
||||
|
||||
struct DrawRequestX {
|
||||
int32 x; // X position relative to GrBuff(0, 0)
|
||||
int32 y; // Y position relative to GrBuff(0, 0)
|
||||
int32 scale_x; // X scale factor (can be negative for reverse draw)
|
||||
int32 scale_y; // Y scale factor (can't be negative)
|
||||
uint8 *depth_map; // Depth code array for destination (doesn't care if srcDepth is 0)
|
||||
RGBcolor *Pal; // Palette for shadow draw (doesn't care if SHADOW bit is not set in Src.encoding)
|
||||
uint8 *ICT; // Inverse Color Table (doesn't care if SHADOW bit is not set in Src.encoding)
|
||||
uint8 depth; // Depth code for source (0 if no depth processing)
|
||||
};
|
||||
|
||||
struct RendCell {
|
||||
uint32 Pack;
|
||||
uint32 Stream;
|
||||
long hot_x;
|
||||
long hot_y;
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
uint32 Comp;
|
||||
uint32 Reserved[8];
|
||||
uint8 *data;
|
||||
};
|
||||
|
||||
enum {
|
||||
kEndOfLine = 0,
|
||||
kEndOfSprite = 1,
|
||||
kJumpXY = 2
|
||||
};
|
||||
|
||||
typedef uint32 RenderResult;
|
||||
|
||||
typedef RenderResult(*RenderFunc)();
|
||||
|
||||
struct Rend_Globals {
|
||||
uint8 *_sourceAddress, *_destinationAddress, *_depthAddress, _spriteDepth, *_InverseColorTable;
|
||||
int32 _X_scale, _LeftPorch, _RightPorch, _StartingPixelPos, _X_error;
|
||||
int _Increment;
|
||||
RGBcolor *_Palette;
|
||||
};
|
||||
|
||||
void GetUpdateRectangle(int32 x, int32 y, int32 hot_x, int32 hot_y, int32 scale_x, int32 scale_y, int32 Width, int32 Height, M4Rect *UpdateRect);
|
||||
void render_sprite_to_8BBM(RendGrBuff *Destination, DrawRequestX *dr, RendCell *Frame, M4Rect *ClipRectangle, M4Rect *UpdateRect);
|
||||
|
||||
} // namespace M4
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user