2 * 2ooM: The Master of Orion II Reverse Engineering Project
3 * Rendering routines for Cairo surfaces.
4 * Copyright © 2014 Nick Bowler
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <cairo/cairo.h>
31 static const cairo_user_data_key_t last_frame_key;
34 * Scale 6-bit colour values (0-63) to 8-bit (0-255) as evenly as possible.
36 static inline guint32 scale6to8(unsigned x)
44 * Output a single row of pixel data in cairo ARGB32 format.
46 static void write_argb(unsigned char *argb, unsigned char *index,
47 unsigned n, unsigned x, unsigned y, unsigned stride,
48 const struct lbx_colour *palette)
50 argb += (unsigned long) y * stride;
53 for (unsigned i = 0; i < n; i++) {
54 const struct lbx_colour *c;
55 guint32 px = 0xffff00ff;
60 | (scale6to8(c->red) << 16)
61 | (scale6to8(c->green) << 8)
65 memcpy(argb + 4ul*i, &px, 4);
70 * Update a cairo RGBA32 surface according to the drawing commands in the
73 static int render_argb(cairo_surface_t *dst, struct lbx_image *img,
74 unsigned frame, const struct lbx_colour *palette)
76 unsigned char *row, *sdata;
77 unsigned x, y, stride;
81 g_return_val_if_fail(cairo_surface_get_type(dst) == CAIRO_SURFACE_TYPE_IMAGE, -1);
82 g_return_val_if_fail(cairo_image_surface_get_format(dst) == CAIRO_FORMAT_ARGB32, -1);
83 g_return_val_if_fail(cairo_image_surface_get_width(dst) == img->width, -1);
84 g_return_val_if_fail(cairo_image_surface_get_height(dst) == img->height, -1);
86 sdata = cairo_image_surface_get_data(dst);
87 stride = cairo_image_surface_get_stride(dst);
89 row = malloc(img->width);
93 rc = lbx_img_seek(img, frame);
99 cairo_surface_flush(dst);
100 while ((rc = lbx_img_read_row_header(img, &x, &y)) != 0) {
106 rc = lbx_img_read_row_data(img, row);
112 write_argb(sdata, row, rc, x, y, stride, palette);
114 cairo_surface_mark_dirty(dst);
120 static int get_last_frame(cairo_surface_t *s)
122 int *data = cairo_surface_get_user_data(s, &last_frame_key);
124 return data ? *data : -1;
127 static void set_last_frame(cairo_surface_t *s, int frame)
129 int *data = cairo_surface_get_user_data(s, &last_frame_key);
134 data = malloc(sizeof *data);
138 rc = cairo_surface_set_user_data(s, &last_frame_key,
140 if (rc != CAIRO_STATUS_SUCCESS) {
150 * Render the specified frame onto a cairo surface. If this is the first
151 * time rendering a frame onto this surface, it is not assumed to contain
152 * any particular data. Otherwise, unless there was an intervening call to
153 * lbxgui_render_restart, the surface is assumed to contain valid frame data
154 * from the most recent call to this function.
156 int lbxgui_render_argb(cairo_surface_t *dst, struct lbx_image *img,
157 unsigned frame, const struct lbx_colour *palette)
159 int last_frame = get_last_frame(dst), ref_frame = 0;
161 g_return_val_if_fail(frame < img->frames, -1);
162 g_return_val_if_fail(dst, -1);
165 ref_frame = (frame / img->chunk) * img->chunk;
167 if (last_frame < ref_frame || last_frame > frame) {
168 cairo_t *cr = cairo_create(dst);
169 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
176 for (unsigned i = MAX(last_frame+1, ref_frame); i <= frame; i++) {
177 int rc = render_argb(dst, img, i, palette);
179 set_last_frame(dst, -1);
183 set_last_frame(dst, i);
190 * "Forget" the last rendered frame on the specified surface so that the next
191 * image will be redrawn from scratch.
193 void lbxgui_render_restart(cairo_surface_t *dst)
195 g_return_if_fail(dst);
197 set_last_frame(dst, -1);
201 * Copies the active elements in the src palette over the corresponding
202 * elements in the dst palette.
204 void lbxgui_stack_palette(struct lbx_colour *dst, const struct lbx_colour *src)
206 for (unsigned i = 0; i < 256; i++) {