+/*
+ * upkg: a tool for manipulating Unreal Tournament packages.
+ * Very simple PCX writer for saving extracted textures.
+ *
+ * Copyright © 2012 Nick Bowler
+ *
+ * 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 <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <engine/palette.h>
+#include <pack.h>
+
+#include "pcx.h"
+
+int pcx_init_header(struct pcx_head *head)
+{
+ unsigned short stride;
+
+ if (head->width == 0 || head->width > 0xffff)
+ return -1;
+ if (head->height == 0 || head->height > 0xffff)
+ return -1;
+
+ stride = head->width + (head->width & 1);
+ if (stride == 0 || stride > 0xffff)
+ return -1;
+
+ memset(head->encoded, 0, sizeof head->encoded);
+
+ head->encoded[0] = 10; /* PCX Magic */
+ head->encoded[1] = 5; /* Version 3. */
+ head->encoded[2] = 1; /* Run-length encoding. */
+ head->encoded[3] = 8; /* Bits per pixel. */
+
+ pack_16_le(head->encoded+8, head->width-1);
+ pack_16_le(head->encoded+10, head->height-1);
+
+ head->encoded[65] = 1; /* One plane (indexed colour). */
+ pack_16_le(head->encoded+66, stride);
+
+ head->encoded[68] = 1; /* Colour palette. */
+
+ return 0;
+}
+
+int pcx_write_scanline(const struct pcx_head *head, const unsigned char *src,
+ FILE *f)
+{
+ size_t len = head->width, offset = 0;
+ unsigned char buf[head->width*2ul];
+
+ for (size_t i = 0; i < len;) {
+ unsigned run = 0;
+
+ while (i+run < len && src[i] == src[i+run] && run <= 0x3f)
+ run++;
+
+ if (run > 1 || src[i] > 0xbf)
+ buf[offset++] = 0xc0 | run;
+ buf[offset++] = src[i];
+ i += run;
+ }
+
+ if (fwrite(buf, offset, 1, f) != 1)
+ return -1;
+ return 0;
+}
+
+int pcx_write_palette(EnginePalette *palette, FILE *f)
+{
+ unsigned char buf[769] = {12};
+
+ for (unsigned i = 0; i < palette->entries; i++) {
+ buf[3*i+1] = palette->rgba[i][0];
+ buf[3*i+2] = palette->rgba[i][1];
+ buf[3*i+3] = palette->rgba[i][2];
+ }
+
+ if (fwrite(buf, sizeof buf, 1, f) != 1)
+ return -1;
+ return 0;
+}