mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 11:28:56 +00:00
319 lines
7.3 KiB
C++
319 lines
7.3 KiB
C++
/*
|
|
* Descent 3
|
|
* Copyright (C) 2024 Parallax Software
|
|
*
|
|
* 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/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/Main/bitmap/pcx.cpp $
|
|
* $Revision: 8 $
|
|
* $Date: 3/30/99 12:36a $
|
|
* $Author: Jeff $
|
|
*
|
|
* Code to read PCX files
|
|
*
|
|
* $Log: /DescentIII/Main/bitmap/pcx.cpp $
|
|
*
|
|
* 8 3/30/99 12:36a Jeff
|
|
* added support for 24bit pcx's
|
|
*
|
|
* 7 2/16/99 5:50p Jason
|
|
* made pcx stuff only work with 8 bit files
|
|
*
|
|
* 6 10/20/98 1:41a Jeff
|
|
* fixed a mem_malloc/free bug
|
|
*
|
|
* 5 10/08/98 4:23p Kevin
|
|
* Changed code to comply with memory library usage. Always use mem_malloc
|
|
* , mem_free and mem_strdup
|
|
*
|
|
* 4 4/23/98 6:38p Jason
|
|
* made bitmaps use 1555 format
|
|
*
|
|
* 3 12/22/97 7:34p Samir
|
|
* Removed instances of gr.h include. Replaced with grdefs.h
|
|
*
|
|
* 2 10/15/97 5:20p Jason
|
|
* did a HUGE overhaul of the bitmap system
|
|
*
|
|
* 4 3/03/97 6:20p Matt
|
|
* Changed cfile functions to use D3 naming convention
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "bitmap.h"
|
|
#include "cfile.h"
|
|
#include "grdefs.h"
|
|
#include "log.h"
|
|
#include "mem.h"
|
|
#include "pserror.h"
|
|
|
|
// load an 8bit pcx image
|
|
static int bm_pcx_8bit_alloc_file(CFILE *infile);
|
|
// load a 24bit pcx image
|
|
static int bm_pcx_24bit_alloc_file(CFILE *infile);
|
|
|
|
// Loads a pcx file and converts it to 16 bit. Returns bitmap handle or -1 on error
|
|
int bm_pcx_alloc_file(CFILE *infile) {
|
|
uint8_t temp[128];
|
|
|
|
cf_ReadBytes(temp, 128, infile);
|
|
cfseek(infile, 0, SEEK_SET);
|
|
|
|
switch (temp[65]) {
|
|
case 1:
|
|
// one plane, sounds like an 8bit pcx
|
|
return bm_pcx_8bit_alloc_file(infile);
|
|
break;
|
|
case 3:
|
|
// three planes, sounds like a 24bit pcx
|
|
return bm_pcx_24bit_alloc_file(infile);
|
|
break;
|
|
}
|
|
|
|
return -1; // Must be 8 bit only
|
|
}
|
|
|
|
// load an 8bit pcx image
|
|
int bm_pcx_8bit_alloc_file(CFILE *infile) {
|
|
int xmin, ymin, xmax, ymax;
|
|
int width, height;
|
|
int total, run = 0;
|
|
int i, t;
|
|
int src_bm;
|
|
uint8_t pred[256], pgreen[256], pblue[256];
|
|
uint8_t buf;
|
|
uint8_t temp[128];
|
|
|
|
cf_ReadBytes(temp, 4, infile);
|
|
|
|
if (temp[3] != 8)
|
|
return -1; // nope...bail
|
|
|
|
xmin = cf_ReadShort(infile);
|
|
ymin = cf_ReadShort(infile);
|
|
xmax = cf_ReadShort(infile);
|
|
ymax = cf_ReadShort(infile);
|
|
|
|
cf_ReadBytes(temp, 116, infile);
|
|
|
|
if (temp[65 - 12] != 1)
|
|
return -1; // Must be 8 bit only
|
|
|
|
width = 1 + xmax - xmin;
|
|
height = 1 + ymax - ymin;
|
|
total = width * height;
|
|
|
|
uint8_t *rawdata = (uint8_t *)mem_malloc(width * height);
|
|
if (!rawdata)
|
|
return -1; // no memory!
|
|
|
|
run = 0;
|
|
while (run < total) {
|
|
buf = cf_ReadByte(infile);
|
|
if (buf >= 192) {
|
|
uint8_t tb;
|
|
tb = cf_ReadByte(infile);
|
|
for (i = 0; i < (buf - 192); i++, run++)
|
|
rawdata[run] = tb;
|
|
} else {
|
|
rawdata[run] = buf;
|
|
run++;
|
|
}
|
|
}
|
|
|
|
cf_ReadByte(infile); // ignore pad
|
|
|
|
// Read palette
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
pred[i] = cf_ReadByte(infile);
|
|
pgreen[i] = cf_ReadByte(infile);
|
|
pblue[i] = cf_ReadByte(infile);
|
|
|
|
pred[i] >>= 3;
|
|
pgreen[i] >>= 3;
|
|
pblue[i] >>= 3;
|
|
}
|
|
|
|
src_bm = bm_AllocBitmap(width, height, 0);
|
|
if (src_bm < 0)
|
|
return -1; // probably out of memory
|
|
|
|
uint16_t *data = bm_data(src_bm, 0);
|
|
|
|
for (i = 0; i < height; i++) {
|
|
for (t = 0; t < width; t++) {
|
|
uint16_t pixel;
|
|
uint8_t c = rawdata[i * width + t];
|
|
|
|
int r = pred[c];
|
|
int g = pgreen[c];
|
|
int b = pblue[c];
|
|
|
|
pixel = OPAQUE_FLAG | (r << 10) | (g << 5) | b;
|
|
if (c == 0)
|
|
pixel = NEW_TRANSPARENT_COLOR;
|
|
|
|
data[i * width + t] = pixel;
|
|
}
|
|
}
|
|
mem_free(rawdata);
|
|
|
|
return src_bm; // success!
|
|
}
|
|
|
|
// load a 24bit pcx image
|
|
int bm_pcx_24bit_alloc_file(CFILE *infile) {
|
|
int xmin, ymin, xmax, ymax;
|
|
int width, height;
|
|
int total, run = 0;
|
|
int i, t;
|
|
int src_bm;
|
|
uint8_t buf;
|
|
uint8_t temp[128];
|
|
|
|
cf_ReadBytes(temp, 4, infile);
|
|
|
|
if (temp[1] < 5) {
|
|
// need at least version 5.0f
|
|
LOG_ERROR << "PCXLoad: PCX Not version 5.0 or greater";
|
|
return -1;
|
|
}
|
|
|
|
if (temp[3] != 8) {
|
|
// need 8 bits per pixel
|
|
LOG_ERROR << "PCXLoad: PCX Not 8 bpp";
|
|
return -1; // nope...bail
|
|
}
|
|
|
|
xmin = cf_ReadShort(infile);
|
|
ymin = cf_ReadShort(infile);
|
|
xmax = cf_ReadShort(infile);
|
|
ymax = cf_ReadShort(infile);
|
|
|
|
cf_ReadBytes(temp, 116, infile);
|
|
|
|
#define PCXHEADER_OFFSET 12
|
|
|
|
if (temp[65 - PCXHEADER_OFFSET] != 3) {
|
|
// Must have 3 planes
|
|
LOG_ERROR << "PCXLoad: PCX Not 3 Planes for 24bit encoding";
|
|
return -1;
|
|
}
|
|
|
|
width = 1 + xmax - xmin;
|
|
height = 1 + ymax - ymin;
|
|
|
|
// Determine BytesPerLine
|
|
cfseek(infile, 66, SEEK_SET);
|
|
int BytesPerLine = cf_ReadShort(infile);
|
|
cfseek(infile, 128, SEEK_SET);
|
|
|
|
// scanline length
|
|
total = 3 * BytesPerLine;
|
|
|
|
uint8_t *rawdata = (uint8_t *)mem_malloc(total * height);
|
|
if (!rawdata) {
|
|
LOG_ERROR << "PCXLoad: Out of memory";
|
|
return -1; // no memory!
|
|
}
|
|
|
|
// Load in the data
|
|
// the data is divided into scanlines
|
|
// the first scanline is line 0's red
|
|
// the second scanline is line 0's green
|
|
// the third scanline is line 0's blue
|
|
// the fourth scanline is line 1's red
|
|
// etc.
|
|
int data_index = 0;
|
|
for (int line = 0; line < height; line++) {
|
|
// Read red scanline
|
|
run = 0;
|
|
while (run < BytesPerLine) {
|
|
buf = cf_ReadByte(infile);
|
|
if (buf >= 192) {
|
|
uint8_t tb;
|
|
tb = cf_ReadByte(infile);
|
|
for (i = 0; i < (buf - 192); i++, run++, data_index++)
|
|
rawdata[data_index] = tb;
|
|
} else {
|
|
rawdata[data_index] = buf;
|
|
run++;
|
|
data_index++;
|
|
}
|
|
}
|
|
|
|
// Read green scanline
|
|
run = 0;
|
|
while (run < BytesPerLine) {
|
|
buf = cf_ReadByte(infile);
|
|
if (buf >= 192) {
|
|
uint8_t tb;
|
|
tb = cf_ReadByte(infile);
|
|
for (i = 0; i < (buf - 192); i++, run++, data_index++)
|
|
rawdata[data_index] = tb;
|
|
} else {
|
|
rawdata[data_index] = buf;
|
|
run++;
|
|
data_index++;
|
|
}
|
|
}
|
|
|
|
// Read blue scanline
|
|
run = 0;
|
|
while (run < BytesPerLine) {
|
|
buf = cf_ReadByte(infile);
|
|
if (buf >= 192) {
|
|
uint8_t tb;
|
|
tb = cf_ReadByte(infile);
|
|
for (i = 0; i < (buf - 192); i++, run++, data_index++)
|
|
rawdata[data_index] = tb;
|
|
} else {
|
|
rawdata[data_index] = buf;
|
|
run++;
|
|
data_index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
src_bm = bm_AllocBitmap(width, height, 0);
|
|
if (src_bm < 0)
|
|
return -1; // probably out of memory
|
|
|
|
uint16_t *data = bm_data(src_bm, 0);
|
|
|
|
for (i = 0; i < height; i++) {
|
|
for (t = 0; t < width; t++) {
|
|
int r, g, b;
|
|
uint16_t pixel;
|
|
|
|
r = rawdata[(i * total) + (0 * BytesPerLine) + t];
|
|
g = rawdata[(i * total) + (1 * BytesPerLine) + t];
|
|
b = rawdata[(i * total) + (2 * BytesPerLine) + t];
|
|
|
|
pixel = OPAQUE_FLAG | GR_RGB16(r, g, b);
|
|
|
|
data[i * width + t] = pixel;
|
|
}
|
|
}
|
|
mem_free(rawdata);
|
|
|
|
return src_bm; // success!
|
|
}
|