/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $URL$ * $Id$ * */ /* * This code is based on Broken Sword 2.5 engine * * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer * * Licensed under GNU GPL v2 * */ #include #include #include #include #include #include #include #include "sword25/gfx/image/vectorimage.h" #include "graphics/colormasks.h" namespace Sword25 { void art_rgb_fill_run1(art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n) { int i; if (r == g && g == b && r == 255) { memset(buf, g, n + n + n + n); } else { uint32 *alt = (uint32 *)buf; uint32 color = Graphics::ARGBToColor >(0xff, r, g, b); for (i = 0; i < n; i++) *alt++ = color; } } void art_rgb_run_alpha1(art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n) { int i; int v; for (i = 0; i < n; i++) { v = *buf; *buf++ = v + (((b - v) * alpha + 0x80) >> 8); v = *buf; *buf++ = v + (((g - v) * alpha + 0x80) >> 8); v = *buf; *buf++ = v + (((r - v) * alpha + 0x80) >> 8); v = *buf; *buf++ = v + (((alpha - v) * alpha + 0x80) >> 8); } } typedef struct _ArtRgbSVPAlphaData ArtRgbSVPAlphaData; struct _ArtRgbSVPAlphaData { int alphatab[256]; art_u8 r, g, b, alpha; art_u8 *buf; int rowstride; int x0, x1; }; static void art_rgb_svp_alpha_callback1(void *callback_data, int y, int start, ArtSVPRenderAAStep *steps, int n_steps) { ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data; art_u8 *linebuf; int run_x0, run_x1; art_u32 running_sum = start; int x0, x1; int k; art_u8 r, g, b; int *alphatab; int alpha; linebuf = data->buf; x0 = data->x0; x1 = data->x1; r = data->r; g = data->g; b = data->b; alphatab = data->alphatab; if (n_steps > 0) { run_x1 = steps[0].x; if (run_x1 > x0) { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], run_x1 - x0); } for (k = 0; k < n_steps - 1; k++) { running_sum += steps[k].delta; run_x0 = run_x1; run_x1 = steps[k + 1].x; if (run_x1 > run_x0) { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgb_run_alpha1(linebuf + (run_x0 - x0) * 4, r, g, b, alphatab[alpha], run_x1 - run_x0); } } running_sum += steps[k].delta; if (x1 > run_x1) { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgb_run_alpha1(linebuf + (run_x1 - x0) * 4, r, g, b, alphatab[alpha], x1 - run_x1); } } else { alpha = (running_sum >> 16) & 0xff; if (alpha) art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], x1 - x0); } data->buf += data->rowstride; } static void art_rgb_svp_alpha_opaque_callback1(void *callback_data, int y, int start, ArtSVPRenderAAStep *steps, int n_steps) { ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data; art_u8 *linebuf; int run_x0, run_x1; art_u32 running_sum = start; int x0, x1; int k; art_u8 r, g, b; int *alphatab; int alpha; linebuf = data->buf; x0 = data->x0; x1 = data->x1; r = data->r; g = data->g; b = data->b; alphatab = data->alphatab; if (n_steps > 0) { run_x1 = steps[0].x; if (run_x1 > x0) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgb_fill_run1(linebuf, r, g, b, run_x1 - x0); else art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], run_x1 - x0); } } for (k = 0; k < n_steps - 1; k++) { running_sum += steps[k].delta; run_x0 = run_x1; run_x1 = steps[k + 1].x; if (run_x1 > run_x0) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgb_fill_run1(linebuf + (run_x0 - x0) * 4, r, g, b, run_x1 - run_x0); else art_rgb_run_alpha1(linebuf + (run_x0 - x0) * 4, r, g, b, alphatab[alpha], run_x1 - run_x0); } } } running_sum += steps[k].delta; if (x1 > run_x1) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgb_fill_run1(linebuf + (run_x1 - x0) * 4, r, g, b, x1 - run_x1); else art_rgb_run_alpha1(linebuf + (run_x1 - x0) * 4, r, g, b, alphatab[alpha], x1 - run_x1); } } } else { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) art_rgb_fill_run1(linebuf, r, g, b, x1 - x0); else art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], x1 - x0); } } data->buf += data->rowstride; } void art_rgb_svp_alpha1(const ArtSVP *svp, int x0, int y0, int x1, int y1, uint32 color, art_u8 *buf, int rowstride, ArtAlphaGamma *alphagamma) { ArtRgbSVPAlphaData data; byte r, g, b, alpha; int i; int a, da; Graphics::colorToARGB >(color, alpha, r, g, b); data.r = r; data.g = g; data.b = b; data.alpha = alpha; a = 0x8000; da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */ for (i = 0; i < 256; i++) { data.alphatab[i] = a >> 16; a += da; } data.buf = buf; data.rowstride = rowstride; data.x0 = x0; data.x1 = x1; if (alpha == 255) art_svp_render_aa(svp, x0, y0, x1, y1, art_rgb_svp_alpha_opaque_callback1, &data); else art_svp_render_aa(svp, x0, y0, x1, y1, art_rgb_svp_alpha_callback1, &data); } void drawBez(ArtBpath *bez, art_u8 *buffer, int width, int height, double scaleX, double scaleY, double penWidth, unsigned int color) { ArtVpath *vec = NULL; ArtSVP *svp = NULL; #if 0 const char *codes[] = {"ART_MOVETO", "ART_MOVETO_OPEN", "ART_CURVETO", "ART_LINETO", "ART_END"}; for (int i = 0;; i++) { printf(" bez[%d].code = %s;\n", i, codes[bez[i].code]); if (bez[i].code == ART_END) break; if (bez[i].code == ART_CURVETO) { printf(" bez[%d].x1 = %f; bez[%d].y1 = %f;\n", i, bez[i].x1, i, bez[i].y1); printf(" bez[%d].x2 = %f; bez[%d].y2 = %f;\n", i, bez[i].x2, i, bez[i].y2); } printf(" bez[%d].x3 = %f; bez[%d].y3 = %f;\n", i, bez[i].x3, i, bez[i].y3); } printf(" drawBez(bez, buffer, 1.0, 1.0, %f, 0x%08x);\n", penWidth, color); #endif vec = art_bez_path_to_vec(bez, 0.5); if (scaleX != 1.0 || scaleY != 1.0) { ArtVpath *vec1; int size; for (size = 0; vec[size].code != ART_END; size++); vec1 = art_new(ArtVpath, size + 1); int k; for (k = 0; k < size; k++) { vec1[k].code = vec[k].code; vec1[k].x = vec[k].x * scaleX; vec1[k].y = vec[k].y * scaleY; } vec1[k].code = ART_END; art_free(vec); vec = vec1; } if (penWidth != -1) { svp = art_svp_vpath_stroke(vec, ART_PATH_STROKE_JOIN_ROUND, ART_PATH_STROKE_CAP_ROUND, penWidth, 1.0, 0.5); } else { svp = art_svp_from_vpath(vec); } art_rgb_svp_alpha1(svp, 0, 0, width, height, color, buffer, width * 4, NULL); art_free(svp); art_free(vec); } void VectorImage::render(int width, int height) { double scaleX = (width == - 1) ? 1 : static_cast(width) / static_cast(getWidth()); double scaleY = (height == - 1) ? 1 : static_cast(height) / static_cast(getHeight()); debug(0, "VectorImage::render(%d, %d) %s", width, height, _fname.c_str()); if (_pixelData) free(_pixelData); _pixelData = (byte *)malloc(width * height * 4); memset(_pixelData, 0, width * height * 4); for (uint e = 0; e < _elements.size(); e++) { //// Draw shapes for (uint s = 0; s < _elements[e].getFillStyleCount(); s++) { int fill0len = 0; int fill1len = 0; // Count vector sizes in order to minimize memory // fragmentation for (uint p = 0; p < _elements[e].getPathCount(); p++) { if (_elements[e].getPathInfo(p).getFillStyle1() == s + 1) fill1len += _elements[e].getPathInfo(p).getVecLen(); if (_elements[e].getPathInfo(p).getFillStyle0() == s + 1) fill0len += _elements[e].getPathInfo(p).getVecLen(); } // Now lump together vectors ArtBpath *fill1 = art_new(ArtBpath, fill1len + 1); ArtBpath *fill0 = art_new(ArtBpath, fill0len + 1); ArtBpath *fill1pos = fill1; ArtBpath *fill0pos = fill0; for (uint p = 0; p < _elements[e].getPathCount(); p++) { // Normal order if (_elements[e].getPathInfo(p).getFillStyle1() == s + 1) { for (int i = 0; i < _elements[e].getPathInfo(p).getVecLen(); i++) *fill1pos++ = _elements[e].getPathInfo(p).getVec()[i]; } // Reverse order if (_elements[e].getPathInfo(p).getFillStyle0() == s + 1) { for (int i = _elements[e].getPathInfo(p).getVecLen() - 1; i >= 0; i--) *fill0pos++ = _elements[e].getPathInfo(p).getVec()[i]; } } // Close vectors (*fill1pos).code = ART_END; (*fill0pos).code = ART_END; #if 0 if (fill1len) drawBez(fill1, _pixelData, width, height, scaleX, scaleY, -1, _elements[e].getFillStyleColor(s)); if (fill0len) drawBez(fill0, _pixelData, width, height, scaleX, scaleY, -1, _elements[e].getFillStyleColor(s)); #endif art_free(fill0); art_free(fill1); } //// Draw strokes for (uint s = 0; s < _elements[e].getLineStyleCount(); s++) { double penWidth = _elements[e].getLineStyleWidth(s); penWidth *= sqrt(fabs(scaleX * scaleY)); for (uint p = 0; p < _elements[e].getPathCount(); p++) { if (_elements[e].getPathInfo(p).getLineStyle() == s + 1) { drawBez(_elements[e].getPathInfo(p).getVec(), _pixelData, width, height, scaleX, scaleY, penWidth, _elements[e].getLineStyleColor(s)); } } } } } } // End of namespace Sword25