Files
nunuhara_xsystem4/qnt.c
T
Nunuhara Cabbage 4eb5a256fd Refactor graphics code
Sprites are now rendered directly, rather than being blitted to a master
surface which is then copied to a texture. Every sprite now carries an
SDL_Texture in addition to an SDL_Surface (we need both, since
SDL_Texture doesn't give read-access to the pixel data).

All of the image-manipulation code is now in sdl_draw.c, and the
DrawGraph_* functions are now wrappers. Some games (Daibanchou at least)
use an API other than SACT2/DrawGraph, so these operations should be
generic to avoid duplication.
2019-11-29 23:16:40 -08:00

294 lines
7.9 KiB
C

/*
* qnt.c extract QNT cg
*
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
* 1998- <masaki-c@is.aist-nara.ac.jp>
* 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* @version 1.0 01/07/30 initial version
* @version 1.1 01/08/10 fix alpha map extraction
* @version 1.2 01/11/26 zlibの展開バッファが画像サイズよりも大きなものを
* 要求するときの workaround
* @version 1.2 01/11/28 format version 1 に対応
* *(top + 4) is 0 -> version 0
* *(top + 4) is 1 -> version 1
* @version 1.3 03/02/22 縦横奇数サイズ時にpixel/alphaともおかしかったのをfix
* zlib展開バッファを縦横それぞれ1byteづつ多くとる
* ようにした
*/
#include <stdlib.h>
#include <zlib.h>
#include <SDL.h>
#include "little_endian.h"
#include "cg.h"
#include "qnt.h"
#include "system4.h"
#include "sdl_private.h"
#include "sdl_core.h"
/*
zlib の展開バッファで、幅×高さ×3に、さらにどれくらい余裕をとるか
(リクルスで 1164バイトというのがあった)
*/
#define ZLIBBUF_MARGIN 5*1024
/*
* Get information from header
*
* b: raw data
*
* return: acquired qnt information object
*/
static void extract_header(uint8_t *b, struct qnt_header *qnt)
{
int rsv0;
rsv0 = LittleEndian_getDW(b, 4);
if (rsv0 == 0) {
qnt->hdr_size = 48;
qnt->x0 = LittleEndian_getDW(b, 8);
qnt->y0 = LittleEndian_getDW(b, 12);
qnt->width = LittleEndian_getDW(b, 16);
qnt->height = LittleEndian_getDW(b, 20);
qnt->bpp = LittleEndian_getDW(b, 24);
qnt->rsv = LittleEndian_getDW(b, 28);
qnt->pixel_size = LittleEndian_getDW(b, 32);
qnt->alpha_size = LittleEndian_getDW(b, 36);
} else {
qnt->hdr_size = LittleEndian_getDW(b, 8);
qnt->x0 = LittleEndian_getDW(b, 12);
qnt->y0 = LittleEndian_getDW(b, 16);
qnt->width = LittleEndian_getDW(b, 20);
qnt->height = LittleEndian_getDW(b, 24);
qnt->bpp = LittleEndian_getDW(b, 28);
qnt->rsv = LittleEndian_getDW(b, 32);
qnt->pixel_size = LittleEndian_getDW(b, 36);
qnt->alpha_size = LittleEndian_getDW(b, 40);
}
if (qnt->bpp != 24)
ERROR("Unsupported bits-per-pixel: %d", qnt->bpp);
}
/*
* Do extract qnt pixel image
*
* qnt: qnt header information
* pic: pixel to be stored
* b : raw data (pointer to pixel)
*/
static void extract_pixel(struct qnt_header *qnt, uint8_t *pic, uint8_t *b)
{
int i, j, x, y, w, h;
unsigned long ucbuf = (qnt->width+1) * (qnt->height+1) * 3 + ZLIBBUF_MARGIN;
uint8_t *raw = malloc(sizeof(uint8_t) * ucbuf);
if (Z_OK != uncompress(raw, &ucbuf, b, qnt->pixel_size)) {
WARNING("uncompress failed\n");
free(raw);
return;
}
w = qnt->width;
h = qnt->height;
j = 0;
for (i = 2; i >= 0; i--) {
for (y = 0; y < (h -1); y+=2) {
for (x = 0; x < (w -1); x+=2) {
pic[( y *w+x) *3 +i] = raw[j];
pic[((y+1)*w+x) *3 +i] = raw[j+1];
pic[( y *w+x+1)*3 +i] = raw[j+2];
pic[((y+1)*w+x+1)*3 +i] = raw[j+3];
j+=4;
}
if (x != w) {
pic[( y *w+x)*3 +i] = raw[j];
pic[((y+1)*w+x)*3 +i] = raw[j+1];
j+=4;
}
}
if (y != h) {
for (x = 0; x < (w -1); x+=2) {
pic[(y*w+x )*3+i] = raw[j];
pic[(y*w+x+1)*3+i] = raw[j+2];
j+=4;
}
if (x != w) {
pic[( y *w+x)*3 +i] = raw[j];
j+=4;
}
}
}
if (w > 1) {
for (x = 1; x < w; x++) {
pic[x*3 ] = pic[(x-1)*3 ] - pic[x*3 ];
pic[x*3+1] = pic[(x-1)*3+1] - pic[x*3+1];
pic[x*3+2] = pic[(x-1)*3+2] - pic[x*3+2];
}
}
if (h > 1) {
for (y = 1; y < h; y++) {
pic[(y*w)*3 ] = pic[((y-1)*w)*3 ] - pic[(y*w)*3 ];
pic[(y*w)*3+1] = pic[((y-1)*w)*3+1] - pic[(y*w)*3+1];
pic[(y*w)*3+2] = pic[((y-1)*w)*3+2] - pic[(y*w)*3+2];
for (x = 1; x < w; x++) {
int px, py;
py = pic[((y-1)*w+x )*3];
px = pic[( y *w+x-1)*3];
pic[(y*w+x)*3] = ((py+px)>>1) - pic[(y*w+x)*3];
py = pic[((y-1)*w+x )*3+1];
px = pic[( y *w+x-1)*3+1];
pic[(y*w+x)*3+1] = ((py+px)>>1) - pic[(y*w+x)*3+1];
py = pic[((y-1)*w+x )*3+2];
px = pic[( y *w+x-1)*3+2];
pic[(y*w+x)*3+2] = ((py+px)>>1) - pic[(y*w+x)*3+2];
}
}
}
free(raw);
}
/*
* Do extract qnt alpha image
*
* qnt: qnt header information
* pic: pixel to be stored
* b : raw data (pointer to alpha pixel)
*/
static void extract_alpha(struct qnt_header *qnt, uint8_t *pic, uint8_t *b)
{
int i, x, y, w, h;
unsigned long ucbuf = (qnt->width+1) * (qnt->height+1) + ZLIBBUF_MARGIN;
uint8_t *raw = malloc(sizeof(uint8_t) * ucbuf);
if (Z_OK != uncompress(raw, &ucbuf, b, qnt->alpha_size)) {
WARNING("uncompress failed\n");
free(raw);
return;
}
w = qnt->width;
h = qnt->height;
i = 1;
if (w > 1) {
pic[0] = raw[0];
for (x = 1; x < w; x++) {
pic[x] = pic[x-1] - raw[i];
i++;
}
if (w%2) i++;
}
if (h > 1) {
for (y = 1; y < h; y++) {
pic[y*w] = pic[(y-1) *w] - raw[i]; i++;
for (x = 1; x < w; x++) {
int pax, pay;
pax = pic[ y * w + x -1];
pay = pic[(y-1)* w + x ];
pic[y*w+x] = ((pax+pay) >> 1) - raw[i];
i++;
}
if (w%2) i++;
}
}
free(raw);
}
/*
* Check data is qnt format cg or not
*
* data: raw data (pointer to data top)
*
* return: true if data is qnt
*/
bool qnt_checkfmt(uint8_t *data)
{
if (data[0] != 'Q' || data[1] != 'N' || data[2] != 'T') return false;
return true;
}
bool qnt_get_metrics(uint8_t *data, struct cg_metrics *dst)
{
struct qnt_header qnt;
extract_header(data, &qnt);
dst->w = qnt.width;
dst->h = qnt.height;
dst->bpp = qnt.bpp;
dst->has_pixel = qnt.pixel_size > 0;
dst->has_alpha = qnt.alpha_size > 0;
dst->pixel_pitch = qnt.width * (qnt.bpp / 8);
dst->alpha_pitch = 1;
return true;
}
/*
* Extract qnt header and pixel
*
* data: raw data (pointer to data top)
*
* return: extracted image data and information
*/
void qnt_extract(uint8_t *data, struct cg *cg)
{
struct qnt_header qnt;
extract_header(data, &qnt);
uint8_t *pixels = malloc(sizeof(uint8_t) * ((qnt.width+10) * (qnt.height+10) * 3));
extract_pixel(&qnt, pixels, data + qnt.hdr_size);
cg->type = ALCG_QNT;
cg->has_alpha = qnt.alpha_size > 0;
if (!qnt.alpha_size) {
// convert RGB -> ARGB
SDL_Surface *tmp = SDL_CreateRGBSurfaceWithFormatFrom(pixels, qnt.width, qnt.height, 24,
qnt.width * 3, SDL_PIXELFORMAT_RGB24);
cg->s = SDL_ConvertSurface(tmp, sdl.format, 0);
cg->t = sdl_surface_to_texture(cg->s);
cg->pixel_alloc = false;
SDL_FreeSurface(tmp);
free(pixels);
return;
}
// combine color/alpha data
uint8_t *alpha = malloc(sizeof(uint8_t) * ((qnt.width+10) * (qnt.height+10)));
uint8_t *tmp = malloc((qnt.width+10) * (qnt.height+10) * 4);
extract_alpha(&qnt, alpha, data + qnt.hdr_size + qnt.pixel_size);
for (int src_i = 0, dst_i = 0, p = 0; p < qnt.width * qnt.height; p++) {
tmp[dst_i++] = alpha[p];
tmp[dst_i++] = pixels[src_i++];
tmp[dst_i++] = pixels[src_i++];
tmp[dst_i++] = pixels[src_i++];
}
free(alpha);
free(pixels);
pixels = tmp;
cg->s = SDL_CreateRGBSurfaceWithFormatFrom(pixels, qnt.width, qnt.height, 32,
qnt.width * 4, SDL_PIXELFORMAT_ARGB32);
cg->t = sdl_surface_to_texture(cg->s);
cg->pixel_alloc = true;
}