mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-08 14:58:14 +03:00
Import CG reading code from xsystem35
Plus a bit of SACT2 implementation, and fix a bug where global arrays were not initialized properly.
This commit is contained in:
@@ -183,12 +183,15 @@ static int _ald_get(struct ald_archive *ar, int no, int *disk_out, int *dataptr_
|
||||
bool ald_data_exists(struct ald_archive *ar, int no)
|
||||
{
|
||||
int disk, dataptr;
|
||||
return !!_ald_get(ar, no, &disk, &dataptr);
|
||||
return ar && !!_ald_get(ar, no, &disk, &dataptr);
|
||||
}
|
||||
|
||||
/* Get a piece of data from an ALD archive. */
|
||||
struct archive_data *ald_get(struct ald_archive *ar, int no)
|
||||
{
|
||||
if (!ar)
|
||||
return NULL;
|
||||
|
||||
uint8_t *data;
|
||||
struct archive_data *dfile;
|
||||
int disk, dataptr, ptr, size;
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* bmp.c extract 8/24 bit BMP cg
|
||||
*
|
||||
* Copyright (C) 1999 TAJIRI,Yasuhiro <tajiri@wizard.elec.waseda.ac.jp>
|
||||
* rewrited 2000 CHIKAMA Masaki <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
|
||||
*
|
||||
* 0.00 99/01/04 初版
|
||||
* 0.01 99/01/20 パレットを読み込む際のrgbの並びを直した
|
||||
* @version 1.1 00/09/17 rewrite for changing interface
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "little_endian.h"
|
||||
#include "graphics.h"
|
||||
#include "cg.h"
|
||||
#include "bmp.h"
|
||||
|
||||
/*
|
||||
* static methods
|
||||
*/
|
||||
static struct bmp_header *extract_header(uint8_t *b);
|
||||
static void getpal(Pallet256 *pal, uint8_t *b);
|
||||
static void extract_8bit(struct bmp_header *bmp, uint8_t *pic, uint8_t *b);
|
||||
static void extract_24bit(struct bmp_header *bmp, uint16_t *pic, uint8_t *b);
|
||||
|
||||
/*
|
||||
* Get information from cg header
|
||||
* b: raw data (pointer to header)
|
||||
* return: acquired bmp information object
|
||||
*/
|
||||
static struct bmp_header *extract_header(uint8_t *b) {
|
||||
struct bmp_header *bmp = malloc(sizeof(struct bmp_header));
|
||||
|
||||
bmp->bmpSize = LittleEndian_getDW(b, 2);
|
||||
/*data[4]-data[7]reserv*/
|
||||
bmp->bmpDp = LittleEndian_getDW(b, 10);
|
||||
bmp->bmpXW = LittleEndian_getDW(b, 18);
|
||||
bmp->bmpYW = LittleEndian_getDW(b, 22);
|
||||
bmp->bmpBpp = LittleEndian_getW(b, 28);
|
||||
bmp->bmpCp = LittleEndian_getDW(b, 30);
|
||||
bmp->bmpImgSize = LittleEndian_getDW(b, 34);
|
||||
bmp->bmpPp = (bmp->bmpBpp==24 ? 0 :
|
||||
14 + LittleEndian_getDW(b, 14));
|
||||
bmp->bmpTp = LittleEndian_getDW(b, 14) == 12 ? BMP_OS2 : BMP_WIN;
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get pallet from raw data
|
||||
* pal: pallet to be stored
|
||||
* b : raw data (pointer to pallet)
|
||||
*/
|
||||
static void getpal(Pallet256 *pal, uint8_t *b) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
pal->blue[i] = *b++;
|
||||
pal->red[i] = *b++;
|
||||
pal->green[i] = *b++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do extract 8bit bmp image
|
||||
* bmps: bmp header information
|
||||
* pic: pixel to be stored
|
||||
* b : raw data (pointer to pixel)
|
||||
*/
|
||||
static void extract_8bit(struct bmp_header *bmp, uint8_t *pic, uint8_t *b) {
|
||||
int i, j;
|
||||
int pos;
|
||||
int LineNeed = (bmp->bmpXW * bmp->bmpBpp) / 8;
|
||||
|
||||
if (LineNeed % 4)
|
||||
LineNeed = (((LineNeed / 4) + 1) * 4); /* Duint16_t整列化 */
|
||||
|
||||
pos = LineNeed * (bmp->bmpYW); /* 最上行の位置 */
|
||||
for (i = 0; i < bmp->bmpYW; i++) {
|
||||
const uint8_t* p;
|
||||
pos -= LineNeed;
|
||||
p = b + pos;
|
||||
for (j = 0; j < bmp->bmpXW; j++)
|
||||
*pic++ = *p++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do extract 24bit bmp image
|
||||
* pms: pms header information
|
||||
* pic: pixel to be stored (16 bit converted)
|
||||
* b : raw data (pointer to pixel)
|
||||
*/
|
||||
static void extract_24bit(struct bmp_header *bmp, uint16_t *pic, uint8_t *b) {
|
||||
int i, j;
|
||||
int pos;
|
||||
int LineNeed = (bmp->bmpXW * bmp->bmpBpp) / 8;
|
||||
|
||||
if (LineNeed % 4)
|
||||
LineNeed = (((LineNeed / 4) + 1) * 4); /* Duint16_t整列化 */
|
||||
|
||||
pos = LineNeed * (bmp->bmpYW); /* 最上行の位置 */
|
||||
for (i = 0; i < bmp->bmpYW; i++) {
|
||||
const uint8_t* p;
|
||||
pos -= LineNeed;
|
||||
p = b + pos;
|
||||
|
||||
for (j = 0; j < bmp->bmpXW; j++) {
|
||||
uint16_t r,g,b;
|
||||
b = (*p++);
|
||||
g = (*p++);
|
||||
r = (*p++);
|
||||
r >>= 3;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
*pic = (r << 11 | g << 5 | b);
|
||||
/* 本当はPIX24なんだろうけど、その後表示する関数ないし、
|
||||
とりあえず。
|
||||
*pic = PIX16(r,g,b);
|
||||
*/
|
||||
pic++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check data is 8bit bmp format cg or not
|
||||
* data: raw data (pointer to data top)
|
||||
* return: true if data is bmp
|
||||
*/
|
||||
bool bmp256_checkfmt(uint8_t *data) {
|
||||
int w, h, bpp;
|
||||
if (data[0] != 'B' || data[1] != 'M') return false;
|
||||
|
||||
w = LittleEndian_getDW(data, 18);
|
||||
h = LittleEndian_getDW(data, 22);
|
||||
bpp = LittleEndian_getW(data, 28);
|
||||
|
||||
if (bpp != 8) return false;
|
||||
if (w < 0 || h < 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract 8bit bmp, header, pallet and pixel
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted image data and information
|
||||
*/
|
||||
struct cg *bmp256_extract(uint8_t *data) {
|
||||
struct bmp_header *bmp = extract_header(data);
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
|
||||
cg->pal = malloc(sizeof(Pallet256));
|
||||
getpal(cg->pal, data + bmp->bmpPp);
|
||||
|
||||
/* +10: margin for broken cg */
|
||||
cg->pic = malloc(sizeof(uint8_t) * ((bmp->bmpXW + 10) * (bmp->bmpYW + 10)));
|
||||
extract_8bit(bmp, cg->pic, data + bmp->bmpDp);
|
||||
|
||||
cg->type = ALCG_BMP8;
|
||||
cg->x = 0;
|
||||
cg->y = 0;
|
||||
cg->width = bmp->bmpXW;
|
||||
cg->height = bmp->bmpYW;
|
||||
cg->alpha = NULL;
|
||||
|
||||
free(bmp);
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check data is 24bit bmp format cg or not
|
||||
* data: raw data (pointer to data top)
|
||||
* return: true if data is pms
|
||||
*/
|
||||
bool bmp16m_checkfmt(uint8_t *data) {
|
||||
int w, h, bpp;
|
||||
|
||||
if (data[0] != 'B' || data[1] != 'M') return false;
|
||||
|
||||
w = LittleEndian_getDW(data, 18);
|
||||
h = LittleEndian_getDW(data, 22);
|
||||
bpp = LittleEndian_getW(data, 28);
|
||||
|
||||
if (bpp != 24) return false;
|
||||
if (w < 0 || h < 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract 24bit bmp, header, pallet and pixel
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted image data and information
|
||||
*/
|
||||
struct cg *bmp16m_extract(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct bmp_header *bmp = extract_header(data);
|
||||
|
||||
/* +10: margin for broken cg */
|
||||
cg->pic = (uint8_t *)malloc(sizeof(uint16_t) * (bmp->bmpXW + 10) * (bmp->bmpYW + 10));
|
||||
extract_24bit(bmp, (uint16_t *)cg->pic, data + bmp->bmpDp);
|
||||
|
||||
cg->type = ALCG_BMP24;
|
||||
cg->x = 0;
|
||||
cg->y = 0;
|
||||
cg->width = bmp->bmpXW;
|
||||
cg->height = bmp->bmpYW;
|
||||
cg->alpha = NULL;
|
||||
cg->pal = NULL;
|
||||
|
||||
free(bmp);
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract bmp pallet only
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted pallet data
|
||||
*/
|
||||
struct cg *bmp_getpal(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct bmp_header *bmp = extract_header(data);
|
||||
|
||||
cg->pal = malloc(sizeof(Pallet256));
|
||||
getpal(cg->pal, data + bmp->bmpPp);
|
||||
|
||||
cg->type = ALCG_BMP8;
|
||||
cg->pic = NULL;
|
||||
cg->alpha = NULL;
|
||||
|
||||
free(bmp);
|
||||
|
||||
return cg;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* bmp.h extract 8/24 bit BMP cg
|
||||
*
|
||||
* Copyright (C) 1999 TAJIRI,Yasuhiro <tajiri@wizard.elec.waseda.ac.jp>
|
||||
* rewrited 2000 Masaki Chikam <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.1 00/09/17 rewrite for changeing interface
|
||||
*
|
||||
*/
|
||||
/* $Id: bmp.h,v 1.1 2000/09/20 10:33:14 chikama Exp $ */
|
||||
|
||||
#ifndef SYSTEM4_BMP_H
|
||||
#define SYSTEM4_BMP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "cg.h"
|
||||
|
||||
enum bmp_type {
|
||||
BMP_OS2 = 1,
|
||||
BMP_WIN = 2
|
||||
};
|
||||
|
||||
struct bmp_header {
|
||||
int bmpSize; // header + data size?
|
||||
int bmpXW; // image width
|
||||
int bmpYW; // image height
|
||||
int bmpBpp; // image depth
|
||||
int bmpCp; // pointer to comment ?
|
||||
int bmpImgSize; // image size
|
||||
int bmpDp; // pointer to data
|
||||
int bmpPp; // pointer to pixel
|
||||
enum bmp_type bmpTp; // bmp type
|
||||
};
|
||||
|
||||
bool bmp256_checkfmt(uint8_t *data);
|
||||
struct cg *bmp256_extract(uint8_t *data);
|
||||
bool bmp16m_checkfmt(uint8_t *data);
|
||||
struct cg *bmp16m_extract(uint8_t *data);
|
||||
struct cg *bmp_getpal(uint8_t *data);
|
||||
|
||||
#endif /* SYSTEM_BMP_H */
|
||||
@@ -14,11 +14,161 @@
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "system4.h"
|
||||
#include "cg.h"
|
||||
#include "ald.h"
|
||||
#include "cg.h"
|
||||
#include "bmp.h"
|
||||
#include "pms.h"
|
||||
#include "qnt.h"
|
||||
#include "vsp.h"
|
||||
#include "graphics.h"
|
||||
|
||||
bool cg_exists(int no)
|
||||
{
|
||||
return ald[ALDFILE_CG] && ald_data_exists(ald[ALDFILE_CG], no);
|
||||
}
|
||||
|
||||
/*
|
||||
* Identify cg format
|
||||
* data: pointer to compressed data
|
||||
* return: cg type
|
||||
*/
|
||||
static enum cg_type check_cgformat(uint8_t *data)
|
||||
{
|
||||
if (qnt_checkfmt(data)) {
|
||||
return ALCG_QNT;
|
||||
} else if (pms256_checkfmt(data)) {
|
||||
return ALCG_PMS8;
|
||||
} else if (pms64k_checkfmt(data)) {
|
||||
return ALCG_PMS16;
|
||||
} else if (bmp16m_checkfmt(data)) {
|
||||
return ALCG_BMP24;
|
||||
} else if (bmp256_checkfmt(data)) {
|
||||
return ALCG_BMP8;
|
||||
} else if (vsp_checkfmt(data)) {
|
||||
return ALCG_VSP;
|
||||
}
|
||||
WARNING("Unknown CG type");
|
||||
return ALCG_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify pixel accoding to pallet bank (vsp only)
|
||||
* pic : pixel to be modifyied.
|
||||
* bank : pallet bank (use only MSB 4bit)
|
||||
* width : image width
|
||||
* height: image height
|
||||
*/
|
||||
//static void set_vspbank(uint8_t *pic, int bank, int width, int height) {
|
||||
// int pixels = width * height;
|
||||
//
|
||||
// while (pixels--) {
|
||||
// *pic = (*pic & 0x0f) | (uint8_t)bank; pic++;
|
||||
// }
|
||||
//}
|
||||
|
||||
/*
|
||||
* Free CG data
|
||||
* cg: object to free
|
||||
*/
|
||||
void cg_free(struct cg *cg)
|
||||
{
|
||||
if (cg->pic) free(cg->pic);
|
||||
if (cg->pal) free(cg->pal);
|
||||
if (cg->alpha) free(cg->alpha);
|
||||
free(cg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load cg data from file or cache
|
||||
* no: file no ( >= 0)
|
||||
* return: cg object(extracted)
|
||||
*/
|
||||
struct cg *cg_load(int no)
|
||||
{
|
||||
struct archive_data *dfile;
|
||||
struct cg *cg = NULL;
|
||||
int type, possibly_unused size = 0;
|
||||
|
||||
// search in cache
|
||||
//if ((cg = (struct cg *)cache_foreach(cacheid, no)))
|
||||
// return cg;
|
||||
|
||||
// read from file
|
||||
//if (NULL == (dfile = ald_getdata(DRIFILE_CG, no))) return NULL;
|
||||
if (!(dfile = ald_get(ald[ALDFILE_CG], no)))
|
||||
return NULL;
|
||||
|
||||
// update load cg counter
|
||||
// if (cg_loadCountVar != NULL) {
|
||||
// (*(cg_loadCountVar + no + 1))++;
|
||||
// }
|
||||
|
||||
// check loaded cg format
|
||||
type = check_cgformat(dfile->data);
|
||||
|
||||
// extract cg
|
||||
// size is only pixel data size
|
||||
switch(type) {
|
||||
case ALCG_VSP:
|
||||
sys_message("extracting VSP");
|
||||
cg = vsp_extract(dfile->data);
|
||||
size = cg->width * cg->height;
|
||||
break;
|
||||
case ALCG_PMS8:
|
||||
sys_message("extracting PMS8");
|
||||
cg = pms256_extract(dfile->data);
|
||||
size = cg->width * cg->height;
|
||||
break;
|
||||
case ALCG_PMS16:
|
||||
sys_message("extracting PMS16");
|
||||
cg = pms64k_extract(dfile->data);
|
||||
size = (cg->width * cg->height) * sizeof(uint16_t);
|
||||
break;
|
||||
case ALCG_BMP8:
|
||||
sys_message("extracting BMP8");
|
||||
cg = bmp256_extract(dfile->data);
|
||||
size = cg->width * cg->height;
|
||||
break;
|
||||
case ALCG_BMP24:
|
||||
sys_message("extracting BMP24");
|
||||
cg = bmp16m_extract(dfile->data);
|
||||
size = (cg->width * cg->height) * sizeof(uint16_t);
|
||||
break;
|
||||
case ALCG_QNT:
|
||||
sys_message("extracting QNT");
|
||||
cg = qnt_extract(dfile->data);
|
||||
size = (cg->width * cg->height) * 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// insert to cache
|
||||
//if (cg)
|
||||
// cache_insert(cacheid, no, cg, size, NULL);
|
||||
|
||||
// load pallet if not extracted
|
||||
// XXXX うむ、こいつらどこで解放するんだ
|
||||
switch(type) {
|
||||
case ALCG_VSP:
|
||||
cg = vsp_getpal(dfile->data);
|
||||
break;
|
||||
case ALCG_PMS8:
|
||||
cg = pms_getpal(dfile->data);
|
||||
break;
|
||||
case ALCG_BMP8:
|
||||
cg = bmp_getpal(dfile->data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// ok to free
|
||||
ald_free_data(dfile);
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
/* 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
|
||||
@@ -18,7 +20,51 @@
|
||||
#define SYSTEM4_CG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "graphics.h"
|
||||
|
||||
/*
|
||||
* Available CG formats
|
||||
*/
|
||||
enum cg_type {
|
||||
ALCG_UNKNOWN = 1,
|
||||
ALCG_VSP = 2,
|
||||
ALCG_PMS8 = 3,
|
||||
ALCG_PMS16 = 4,
|
||||
ALCG_BMP8 = 5,
|
||||
ALCG_BMP24 = 6,
|
||||
ALCG_QNT = 7,
|
||||
ALCG_AJP = 8
|
||||
};
|
||||
|
||||
/*
|
||||
* Information for displaying CG data
|
||||
*/
|
||||
struct cg {
|
||||
enum cg_type type; // cg format type
|
||||
int x; // default display location x
|
||||
int y; // default display location y
|
||||
int z; // draw order
|
||||
int width; // image width
|
||||
int height; // image height
|
||||
|
||||
uint8_t *pic; // extracted pixel data
|
||||
uint8_t *alpha; // extracted alpha data if exists
|
||||
Pallet256 *pal; // extracted pallet data if exists
|
||||
|
||||
int vsp_bank; // pallet bank for vsp
|
||||
int pms_bank; // pallet bank for pms
|
||||
|
||||
int spritecolor; // sprite color for vsp and pms8
|
||||
int alphalevel; // alpha level of image
|
||||
|
||||
int data_offset; // pic offset for clipping
|
||||
|
||||
int r, g, b, a;
|
||||
bool show;
|
||||
};
|
||||
|
||||
bool cg_exists(int no);
|
||||
struct cg *cg_load(int no);
|
||||
|
||||
#endif /* SYSTEM4_CG_H */
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/* 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, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_GRAPHICS_H
|
||||
#define SYSTEM4_GRAPHICS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <SDL.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t red[256];
|
||||
uint8_t green[256];
|
||||
uint8_t blue[256];
|
||||
} Pallet256;
|
||||
|
||||
typedef struct {
|
||||
uint8_t r,g,b;
|
||||
uint32_t pixel;
|
||||
} Pallet;
|
||||
|
||||
typedef SDL_Point Point;
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
} Dimension;
|
||||
|
||||
typedef SDL_Rect Rectangle;
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int depth;
|
||||
} DispInfo;
|
||||
|
||||
#endif /* SYSTEM4_GRAPHICS_H */
|
||||
+5
-5
@@ -18,7 +18,7 @@
|
||||
#include "hll.h"
|
||||
#include "../utfsjis.h"
|
||||
|
||||
hll_warn_unimplemented(OutputLog, Create)
|
||||
hll_warn_unimplemented(OutputLog, Create, 0)
|
||||
|
||||
hll_defun(Output, args) {
|
||||
struct string *s = heap[args[1].i].s;
|
||||
@@ -28,10 +28,10 @@ hll_defun(Output, args) {
|
||||
hll_return(0);
|
||||
}
|
||||
|
||||
hll_warn_unimplemented(OutputLog, Clear)
|
||||
hll_warn_unimplemented(OutputLog, Save)
|
||||
hll_warn_unimplemented(OutputLog, EnableAutoSave)
|
||||
hll_warn_unimplemented(OutputLog, DisableAutoSave)
|
||||
hll_warn_unimplemented(OutputLog, Clear, 0)
|
||||
hll_warn_unimplemented(OutputLog, Save, 0)
|
||||
hll_warn_unimplemented(OutputLog, EnableAutoSave, 0)
|
||||
hll_warn_unimplemented(OutputLog, DisableAutoSave, 0)
|
||||
|
||||
hll_deflib(OutputLog) {
|
||||
hll_export(Create),
|
||||
|
||||
+183
-19
@@ -19,10 +19,52 @@
|
||||
#include "hll.h"
|
||||
#include "../system4.h"
|
||||
#include "../cg.h"
|
||||
#include "../queue.h"
|
||||
#include "../sdl_core.h"
|
||||
|
||||
struct SACT2_sprite {
|
||||
TAILQ_ENTRY(SACT2_sprite) entry;
|
||||
struct cg *cg;
|
||||
Point pos;
|
||||
int z;
|
||||
int width, height;
|
||||
int r, g, b, a;
|
||||
bool show;
|
||||
bool used;
|
||||
};
|
||||
|
||||
static struct SACT2_sprite *sprites = NULL;
|
||||
static int nr_sprites = 0;
|
||||
|
||||
TAILQ_HEAD(listhead, SACT2_sprite) visible_sprites =
|
||||
TAILQ_HEAD_INITIALIZER(visible_sprites);
|
||||
|
||||
static void sprite_set_show(struct SACT2_sprite *sp, bool show)
|
||||
{
|
||||
if (!sp->show == !show)
|
||||
return;
|
||||
|
||||
sp->show = show;
|
||||
|
||||
if (show) {
|
||||
struct SACT2_sprite *p;
|
||||
TAILQ_FOREACH(p, &visible_sprites, entry) {
|
||||
if (p->z > sp->z) {
|
||||
TAILQ_INSERT_BEFORE(p, sp, entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
TAILQ_INSERT_TAIL(&visible_sprites, sp, entry);
|
||||
} else {
|
||||
TAILQ_REMOVE(&visible_sprites, sp, entry);
|
||||
}
|
||||
}
|
||||
|
||||
// int Init(imain_system pIMainSystem, int nCGCacheSize)
|
||||
hll_defun(Init, args)
|
||||
{
|
||||
|
||||
sdl_initialize();
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
@@ -65,22 +107,77 @@ hll_unimplemented(SACT2, QuakeScreen)
|
||||
hll_unimplemented(SACT2, QUAKE_SET_CROSS)
|
||||
// void QUAKE_SET_ROTATION(int nAmp, int nCycle)
|
||||
hll_unimplemented(SACT2, QUAKE_SET_ROTATION)
|
||||
|
||||
// int SP_GetUnuseNum(int nMin)
|
||||
hll_unimplemented(SACT2, SP_GetUnuseNum)
|
||||
hll_defun(SP_GetUnuseNum, args)
|
||||
{
|
||||
int nMin = args[0].i;
|
||||
|
||||
for (int i = nMin; i < nr_sprites; i++) {
|
||||
if (!sprites[i].used)
|
||||
hll_return(i);
|
||||
}
|
||||
|
||||
int n = max(nMin, nr_sprites);
|
||||
nr_sprites = n + 256;
|
||||
sprites = xrealloc(sprites, sizeof(struct SACT2_sprite) * nr_sprites);
|
||||
hll_return(n);
|
||||
}
|
||||
|
||||
// int SP_Count(void)
|
||||
hll_unimplemented(SACT2, SP_Count)
|
||||
// int SP_Enum(ref array@int anSP)
|
||||
hll_unimplemented(SACT2, SP_Enum)
|
||||
// int SP_GetMaxZ(void)
|
||||
hll_unimplemented(SACT2, SP_GetMaxZ)
|
||||
|
||||
// int SP_SetCG(int nSP, int nCG)
|
||||
hll_unimplemented(SACT2, SP_SetCG)
|
||||
hll_defun(SP_SetCG, args)
|
||||
{
|
||||
int sp = args[0].i;
|
||||
int cg = args[1].i;
|
||||
|
||||
WARNING("SACT2.SP_SetCG(%d, %d)", sp, cg);
|
||||
sprites[sp].cg = cg_load(cg);
|
||||
hll_return(!!sprites[sp].cg);
|
||||
}
|
||||
|
||||
// int SP_SetCGFromFile(int nSP, string pIStringFileName)
|
||||
hll_unimplemented(SACT2, SP_SetCGFromFile)
|
||||
// int SP_SaveCG(int nSP, string pIStringFileName)
|
||||
hll_unimplemented(SACT2, SP_SaveCG)
|
||||
|
||||
// int SP_Create(int nSP, int nWidth, int nHeight, int nR, int nG, int nB, int nBlendRate)
|
||||
hll_unimplemented(SACT2, SP_Create)
|
||||
hll_defun(SP_Create, args)
|
||||
{
|
||||
int sp = args[0].i;
|
||||
int width = args[1].i;
|
||||
int height = args[2].i;
|
||||
int r = args[3].i;
|
||||
int g = args[4].i;
|
||||
int b = args[5].i;
|
||||
int a = args[6].i;
|
||||
|
||||
sprites[sp] = (struct SACT2_sprite) {
|
||||
.pos = (Point) {
|
||||
.x = 0,
|
||||
.y = 0
|
||||
},
|
||||
.z = 0,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.r = r,
|
||||
.g = g,
|
||||
.b = b,
|
||||
.a = a,
|
||||
.cg = NULL,
|
||||
.show = false,
|
||||
.used = true
|
||||
};
|
||||
sprite_set_show(&sprites[sp], true);
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
// int SP_CreatePixelOnly(int nSP, int nWidth, int nHeight)
|
||||
hll_unimplemented(SACT2, SP_CreatePixelOnly)
|
||||
// int SP_CreateCustom(int nSP)
|
||||
@@ -88,47 +185,114 @@ hll_unimplemented(SACT2, SP_CreateCustom)
|
||||
// int SP_Delete(int nSP)
|
||||
hll_unimplemented(SACT2, SP_Delete)
|
||||
// int SP_SetPos(int nSP, int nX, int nY)
|
||||
hll_unimplemented(SACT2, SP_SetPos)
|
||||
hll_defun(SP_SetPos, args)
|
||||
{
|
||||
int sp = args[0].i;
|
||||
sprites[sp].pos.x = args[1].i;
|
||||
sprites[sp].pos.y = args[2].i;
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
// int SP_SetX(int nSP, int nX)
|
||||
hll_unimplemented(SACT2, SP_SetX)
|
||||
hll_defun(SP_SetX, args)
|
||||
{
|
||||
sprites[args[0].i].pos.x = args[1].i;
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
// int SP_SetY(int nSP, int nY)
|
||||
hll_unimplemented(SACT2, SP_SetY)
|
||||
hll_defun(SP_SetY, args)
|
||||
{
|
||||
sprites[args[0].i].pos.y = args[1].i;
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
// int SP_SetZ(int nSP, int nZ)
|
||||
hll_unimplemented(SACT2, SP_SetZ)
|
||||
hll_defun(SP_SetZ, args)
|
||||
{
|
||||
sprites[args[0].i].z = args[1].i;
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
// int SP_SetBlendRate(int nSP, int nBlendRate)
|
||||
hll_unimplemented(SACT2, SP_SetBlendRate)
|
||||
hll_defun(SP_SetBlendRate, args)
|
||||
{
|
||||
sprites[args[0].i].a = args[1].i;
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
// int SP_SetShow(int nSP, int nfShow)
|
||||
hll_unimplemented(SACT2, SP_SetShow)
|
||||
hll_defun(SP_SetShow, args)
|
||||
{
|
||||
sprite_set_show(&sprites[args[0].i], args[1].i);
|
||||
hll_return(1);
|
||||
}
|
||||
|
||||
// int SP_SetDrawMethod(int nSP, int nMethod)
|
||||
hll_unimplemented(SACT2, SP_SetDrawMethod)
|
||||
// int SP_IsUsing(int nSP)
|
||||
hll_unimplemented(SACT2, SP_IsUsing)
|
||||
// int SP_ExistAlpha(int nSP)
|
||||
hll_unimplemented(SACT2, SP_ExistAlpha)
|
||||
|
||||
// int SP_GetPosX(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetPosX)
|
||||
hll_defun(SP_GetPosX, args)
|
||||
{
|
||||
hll_return(sprites[args[0].i].pos.x);
|
||||
}
|
||||
|
||||
// int SP_GetPosY(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetPosY)
|
||||
hll_defun(SP_GetPosY, args)
|
||||
{
|
||||
hll_return(sprites[args[0].i].pos.y);
|
||||
}
|
||||
|
||||
// int SP_GetWidth(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetWidth)
|
||||
hll_defun(SP_GetWidth, args)
|
||||
{
|
||||
struct SACT2_sprite *sp = &sprites[args[0].i];
|
||||
if (sp->cg)
|
||||
hll_return(sp->cg->width);
|
||||
hll_return(sp->width);
|
||||
}
|
||||
|
||||
// int SP_GetHeight(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetHeight)
|
||||
hll_defun(SP_GetHeight, args)
|
||||
{
|
||||
struct SACT2_sprite *sp = &sprites[args[0].i];
|
||||
if (sp->cg)
|
||||
hll_return(sp->cg->height);
|
||||
hll_return(sp->width);
|
||||
}
|
||||
|
||||
// int SP_GetZ(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetZ)
|
||||
hll_defun(SP_GetZ, args)
|
||||
{
|
||||
hll_return(sprites[args[0].i].z);
|
||||
}
|
||||
|
||||
// int SP_GetBlendRate(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetBlendRate)
|
||||
hll_defun(SP_GetBlendRate, args)
|
||||
{
|
||||
hll_return(sprites[args[0].i].a);
|
||||
}
|
||||
|
||||
// int SP_GetShow(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetShow)
|
||||
hll_defun(SP_GetShow, args)
|
||||
{
|
||||
hll_return(sprites[args[0].i].show);
|
||||
}
|
||||
|
||||
// int SP_GetDrawMethod(int nSP)
|
||||
hll_unimplemented(SACT2, SP_GetDrawMethod)
|
||||
hll_warn_unimplemented(SACT2, SP_GetDrawMethod, 0)
|
||||
// int SP_SetTextHome(int nSP, int nX, int nY)
|
||||
hll_unimplemented(SACT2, SP_SetTextHome)
|
||||
hll_warn_unimplemented(SACT2, SP_SetTextHome, 0)
|
||||
// int SP_SetTextLineSpace(int nSP, int nPx)
|
||||
hll_unimplemented(SACT2, SP_SetTextLineSpace)
|
||||
// int SP_SetTextCharSpace(int nSP, int nPx)
|
||||
hll_unimplemented(SACT2, SP_SetTextCharSpace)
|
||||
// int SP_SetTextPos(int nSP, int nX, int nY)
|
||||
hll_unimplemented(SACT2, SP_SetTextPos)
|
||||
hll_warn_unimplemented(SACT2, SP_SetTextPos, 0)
|
||||
// int SP_TextDraw(int nSP, string text, struct tm)
|
||||
hll_unimplemented(SACT2, SP_TextDraw)
|
||||
// int SP_TextClear(int nSP)
|
||||
|
||||
@@ -26,22 +26,22 @@
|
||||
#include "../system4.h"
|
||||
|
||||
#define hll_defun(fname, args) \
|
||||
static union vm_value _hllfun_ ## fname(unused union vm_value *args); \
|
||||
static union vm_value _hllfun_ ## fname(possibly_unused union vm_value *args); \
|
||||
static struct hll_function _hllstruct_ ## fname = { \
|
||||
.name = #fname, \
|
||||
.fun = _hllfun_ ## fname \
|
||||
}; \
|
||||
static union vm_value _hllfun_ ## fname(unused union vm_value *args)
|
||||
static union vm_value _hllfun_ ## fname(possibly_unused union vm_value *args)
|
||||
|
||||
#define hll_unimplemented(libname, fname) \
|
||||
hll_defun(fname, args) { \
|
||||
ERROR("Unimplemented HLL function: " #libname "." #fname); \
|
||||
VM_ERROR("Unimplemented HLL function: " #libname "." #fname); \
|
||||
}
|
||||
|
||||
#define hll_warn_unimplemented(libname, fname) \
|
||||
#define hll_warn_unimplemented(libname, fname, rval) \
|
||||
hll_defun(fname, args) { \
|
||||
WARNING("Unimplemented HLL function: " #libname "." #fname); \
|
||||
hll_return(0); \
|
||||
hll_return(rval); \
|
||||
}
|
||||
|
||||
#define hll_export(fname) &_hllstruct_ ## fname
|
||||
|
||||
+7
-1
@@ -7,8 +7,13 @@ system4 = ['ain.c',
|
||||
]
|
||||
xsystem4 = ['ald.c',
|
||||
'cg.c',
|
||||
'bmp.c',
|
||||
'pms.c',
|
||||
'qnt.c',
|
||||
'vsp.c',
|
||||
'ini.c',
|
||||
'page.c',
|
||||
'sdl_video.c',
|
||||
'system4.c',
|
||||
'vm.c',
|
||||
]
|
||||
@@ -18,6 +23,7 @@ hll_libs = ['hll/Math.c',
|
||||
]
|
||||
zdep = dependency('zlib')
|
||||
mdep = meson.get_compiler('c').find_library('m', required: false)
|
||||
sdl2 = dependency('sdl2')
|
||||
|
||||
executable('system4', xsystem4 + system4 + hll_libs, dependencies: [mdep, zdep])
|
||||
executable('system4', xsystem4 + system4 + hll_libs, dependencies: [mdep, zdep, sdl2])
|
||||
executable('aindump', ['aindump.c'] + system4, dependencies: [mdep, zdep])
|
||||
|
||||
@@ -178,6 +178,11 @@ void create_struct(int no, union vm_value *var)
|
||||
heap[memb].s = string_ref(&EMPTY_STRING);
|
||||
heap[slot].page->values[i].i = memb;
|
||||
break;
|
||||
case AIN_ARRAY_TYPE:
|
||||
memb = heap_alloc_slot(VM_PAGE);
|
||||
heap[memb].page = NULL;
|
||||
heap[slot].page->values[i].i = memb;
|
||||
break;
|
||||
case AIN_STRUCT:
|
||||
create_struct(s->members[i].struct_type, &heap[slot].page->values[i]);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* pms.c extract 8/16 bit PMS 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
|
||||
*
|
||||
* pms256.c
|
||||
* 0.00 97/11/06 初版
|
||||
* 0.01 97/11/13 ヘッダ情報の返しかたの変更
|
||||
* 0.01-01 97/11/27 記憶子の変更
|
||||
* 0.02 98/02/26 デバッグ完了
|
||||
* pms64k.c
|
||||
* 0.00 97/11/06 初版
|
||||
* 0.01 97/11/13 ヘッダ情報の返しかたの変更
|
||||
* 0.02 98/02/26 デバッグ完了
|
||||
* 0.03 98/07/27 うそぷ〜。透明色の展開まずってた。
|
||||
* @version 1.1 00/09/17 rewrite for changeing interface
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "little_endian.h"
|
||||
#include "graphics.h"
|
||||
#include "cg.h"
|
||||
#include "pms.h"
|
||||
|
||||
/*
|
||||
* static methods
|
||||
*/
|
||||
static struct pms_header *extract_header(uint8_t *b);
|
||||
static void getpal(Pallet256 *pal, uint8_t *b);
|
||||
static void extract_8bit(struct pms_header *pms, uint8_t *pic, uint8_t *b);
|
||||
static void extract_16bit(struct pms_header *pms, uint16_t *pic, uint8_t *b);
|
||||
|
||||
/*
|
||||
* Get information from cg header
|
||||
* b: raw data (pointer to header)
|
||||
* return: acquired pms information object
|
||||
*/
|
||||
static struct pms_header *extract_header(uint8_t *b) {
|
||||
struct pms_header *pms = malloc(sizeof(struct pms_header));
|
||||
|
||||
pms->pmsVer = LittleEndian_getW(b, 2);
|
||||
pms->pmsHdrSize = LittleEndian_getW(b, 4);
|
||||
pms->pmsBpp = b[6];
|
||||
pms->pmsBppS = b[7];
|
||||
pms->pmsSf = b[8];
|
||||
pms->pmsBf = LittleEndian_getW(b, 10);
|
||||
pms->pmsX0 = LittleEndian_getDW(b, 16);
|
||||
pms->pmsY0 = LittleEndian_getDW(b, 20);
|
||||
pms->pmsXW = LittleEndian_getDW(b, 24);
|
||||
pms->pmsYW = LittleEndian_getDW(b, 28);
|
||||
pms->pmsDp = LittleEndian_getDW(b, 32);
|
||||
pms->pmsPp = LittleEndian_getDW(b, 36);
|
||||
pms->pmsCp = LittleEndian_getDW(b, 40);
|
||||
|
||||
return pms;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get pallet from raw data
|
||||
* pal: pallet to be stored
|
||||
* b : raw data (pointer to pallet)
|
||||
*/
|
||||
static void getpal(Pallet256 *pal, uint8_t *b) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
pal->red[i] = *b++;
|
||||
pal->green[i] = *b++;
|
||||
pal->blue[i] = *b++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do extract 8bit pms image
|
||||
* pms: pms header information
|
||||
* pic: pixel to be stored
|
||||
* b : raw data (pointer to pixel)
|
||||
*/
|
||||
static void extract_8bit(struct pms_header *pms, uint8_t *pic, uint8_t *b) {
|
||||
int c0, c1;
|
||||
int x, y, loc, l, i;
|
||||
int scanline = pms->pmsXW;
|
||||
|
||||
for (y = 0; y < pms->pmsYW; y ++) {
|
||||
for (x = 0; x < pms->pmsXW; ) {
|
||||
loc = y * scanline + x;
|
||||
c0 = *b++;
|
||||
if (c0 <= 0xf7) {
|
||||
*(pic + loc) = c0; x++;
|
||||
} else if (c0 == 0xff) {
|
||||
l = (*b) + 3; x+=l; b++;
|
||||
memcpy(pic + loc, pic + loc - scanline, l);
|
||||
} else if (c0 == 0xfe) {
|
||||
l = (*b) + 3; x+=l; b++;
|
||||
memcpy(pic + loc, pic + loc - scanline * 2, l);
|
||||
} else if (c0 == 0xfd) {
|
||||
l = (*b) + 4; x+=l; b++;
|
||||
c0 = *b++;
|
||||
memset(pic + loc, c0, l);
|
||||
} else if (c0 == 0xfc) {
|
||||
l = ((*b) + 3) * 2; x+=l; b++;
|
||||
c0 = *b++; c1 = *b++;
|
||||
for (i = 0; i < l; i+=2) {
|
||||
*(pic + loc + i ) = c0;
|
||||
*(pic + loc + i + 1) = c1;
|
||||
}
|
||||
} else {
|
||||
*(pic + loc) = *b++; x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do extract 16bit pms image
|
||||
* pms: pms header information
|
||||
* pic: pixel to be stored
|
||||
* b : raw data (pointer to pixel)
|
||||
*/
|
||||
static void extract_16bit(struct pms_header *pms, uint16_t *pic, uint8_t *b) {
|
||||
int c0, c1, pc0, pc1;
|
||||
int x, y, i, l, loc;
|
||||
int scanline = pms->pmsXW;
|
||||
|
||||
for (y = 0; y < pms->pmsYW; y++) {
|
||||
for (x = 0; x < pms->pmsXW;) {
|
||||
loc = y * scanline + x;
|
||||
c0 = *b++;
|
||||
if (c0 <= 0xf7) {
|
||||
c1 = *b++; x++;
|
||||
*(pic + loc) = c0 | (c1 << 8);
|
||||
} else if (c0 == 0xff) {
|
||||
l = (*b) + 2; x+=l; b++;
|
||||
for (i = 0; i < l; i++) {
|
||||
*(pic + loc + i) = *(pic + loc + i - scanline);
|
||||
}
|
||||
} else if (c0 == 0xfe) {
|
||||
l = (*b) + 2; x+=l; b++;
|
||||
for (i = 0; i < l; i++) {
|
||||
*(pic + loc + i) = *(pic + loc + i - scanline * 2);
|
||||
}
|
||||
} else if (c0 == 0xfd) {
|
||||
l = (*b) + 3; x+=l; b++;
|
||||
c0 = *b++; c1 = *b++;
|
||||
pc0 = c0 | (c1 << 8);
|
||||
for (i = 0; i < l; i++) {
|
||||
*(pic + loc + i) = pc0;
|
||||
}
|
||||
} else if (c0 == 0xfc) {
|
||||
l = ((*b) + 2) * 2; x+=l; b++;
|
||||
c0 = *b++; c1 = *b++; pc0 = c0 | (c1 << 8);
|
||||
c0 = *b++; c1 = *b++; pc1 = c0 | (c1 << 8);
|
||||
for (i = 0; i < l; i+=2) {
|
||||
*(pic + loc + i ) = pc0;
|
||||
*(pic + loc + i + 1) = pc1;
|
||||
}
|
||||
} else if (c0 == 0xfb) {
|
||||
x++;
|
||||
*(pic + loc) = *(pic + loc - scanline - 1);
|
||||
} else if (c0 == 0xfa) {
|
||||
x++;
|
||||
*(pic + loc) = *(pic + loc - scanline + 1);
|
||||
} else if (c0 == 0xf9) {
|
||||
l = (*b) + 1; x+=l; b++;
|
||||
c0 = *b++; c1 = *b++;
|
||||
pc0 = ((c0 & 0xe0) << 8) + ((c0 & 0x18) << 6) + ((c0 & 0x07) << 2);
|
||||
pc1 = ((c1 & 0xc0) << 5) + ((c1 & 0x3c) << 3) + (c1 & 0x03);
|
||||
*(pic + loc) = pc0 + pc1;
|
||||
for (i = 1; i < l; i++) {
|
||||
c1 = *b++;
|
||||
pc1 = ((c1 & 0xc0) << 5) + ((c1 & 0x3c) << 3) + (c1 & 0x03);
|
||||
*(pic + loc + i) = pc0 | pc1;
|
||||
}
|
||||
} else {
|
||||
c0 = *b++; c1 = *b++; x++;
|
||||
*(pic + loc) = c0 | (c1 << 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check data is 8bit pms format cg or not
|
||||
* data: raw data (pointer to data top)
|
||||
* return: true if data is pms
|
||||
*/
|
||||
bool pms256_checkfmt(uint8_t *data) {
|
||||
int x, y, w, h;
|
||||
|
||||
if (data[0] != 0x50 || data[1] != 0x4d) return false;
|
||||
if (data[6] != 8) return false;
|
||||
|
||||
x = LittleEndian_getDW(data, 16);
|
||||
y = LittleEndian_getDW(data, 20);
|
||||
w = LittleEndian_getDW(data, 24);
|
||||
h = LittleEndian_getDW(data, 28);
|
||||
|
||||
if (x < 0 || y < 0 || w < 0 || h < 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract 8bit pms, header, pallet and pixel
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted image data and information
|
||||
*/
|
||||
struct cg *pms256_extract(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct pms_header *pms = extract_header(data);
|
||||
|
||||
cg->pal = malloc(sizeof(Pallet256));
|
||||
getpal(cg->pal, data + pms->pmsPp);
|
||||
|
||||
// +10: margin for broken cg
|
||||
cg->pic = malloc(sizeof(uint8_t) * ((pms->pmsXW + 10) * (pms->pmsYW + 10)));
|
||||
extract_8bit(pms, cg->pic, data + pms->pmsDp);
|
||||
|
||||
cg->type = ALCG_PMS8;
|
||||
cg->x = pms->pmsX0;
|
||||
cg->y = pms->pmsY0;
|
||||
cg->width = pms->pmsXW;
|
||||
cg->height = pms->pmsYW;
|
||||
cg->pms_bank = pms->pmsBf;
|
||||
cg->alpha = NULL;
|
||||
|
||||
free(pms);
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check data is 16bit pms format cg or not
|
||||
* data: raw data (pointer to data top)
|
||||
* return: true if data is pms
|
||||
*/
|
||||
bool pms64k_checkfmt(uint8_t *data) {
|
||||
int x, y, w, h;
|
||||
|
||||
if (data[0] != 0x50 || data[1] != 0x4d) return false;
|
||||
if (data[6] != 16) return false;
|
||||
|
||||
x = LittleEndian_getDW(data, 16);
|
||||
y = LittleEndian_getDW(data, 20);
|
||||
w = LittleEndian_getDW(data, 24);
|
||||
h = LittleEndian_getDW(data, 28);
|
||||
|
||||
if (x < 0 || y < 0 || w < 0 || h < 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract 16bit pms, header, pallet and pixel
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted image data and information
|
||||
*/
|
||||
struct cg *pms64k_extract(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct pms_header *pms = extract_header(data);
|
||||
|
||||
// +10: margin for broken cg
|
||||
cg->pic = (uint8_t *)malloc(sizeof(uint16_t) * ((pms->pmsXW + 10) * (pms->pmsYW + 10)));
|
||||
extract_16bit(pms, (uint16_t *)cg->pic, data + pms->pmsDp);
|
||||
|
||||
cg->alpha = NULL;
|
||||
if (pms->pmsPp != 0) {
|
||||
cg->alpha = malloc(sizeof(uint8_t) * ((pms->pmsXW + 10) * (pms->pmsYW + 10)));
|
||||
extract_8bit(pms, cg->alpha, data + pms->pmsPp);
|
||||
}
|
||||
|
||||
cg->type = ALCG_PMS16;
|
||||
cg->x = pms->pmsX0;
|
||||
cg->y = pms->pmsY0;
|
||||
cg->width = pms->pmsXW;
|
||||
cg->height = pms->pmsYW;
|
||||
cg->pal = NULL;
|
||||
|
||||
free(pms);
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract pms pallet only
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted pallet data
|
||||
*/
|
||||
struct cg *pms_getpal(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct pms_header *pms = extract_header(data);
|
||||
|
||||
cg->pal = malloc(sizeof(Pallet256));
|
||||
getpal(cg->pal, data + pms->pmsPp);
|
||||
|
||||
cg->type = ALCG_PMS8;
|
||||
cg->pic = NULL;
|
||||
cg->alpha = NULL;
|
||||
|
||||
free(pms);
|
||||
|
||||
return cg;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* pms.h extract 8/16 bit PMS 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.1 00/09/17 rewrite for changeing interface
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_PMS_H
|
||||
#define SYSTEM4_PMS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "cg.h"
|
||||
|
||||
struct pms_header {
|
||||
int pmsVer; // pms data version
|
||||
int pmsHdrSize; // size of header
|
||||
int pmsBpp; // pms data depth, 8 or 16
|
||||
int pmsBppS; // shadow data depth, if exists
|
||||
int pmsSf; // sprite flag (not used?)
|
||||
int pmsBf; // pallet bank
|
||||
int pmsX0; // display location x
|
||||
int pmsY0; // display location y
|
||||
int pmsXW; // image width
|
||||
int pmsYW; // image height
|
||||
int pmsDp; // pointer to data
|
||||
int pmsPp; // pointer to pallet or shadow
|
||||
int pmsCp; // pointer to comment
|
||||
};
|
||||
/*
|
||||
* pmsBppS
|
||||
* If pmsBpp is 16 and pmsPp is not 0, shadow (alpha data) is exists and
|
||||
* pmsBppS shows shadow's depth (normally 8).
|
||||
*
|
||||
* pmsBf
|
||||
* If pmsBpp is 8, pmsBf determine which pallets is used in this data and
|
||||
* needed to copy. The pmsBf is mask and if bit is on then copy.
|
||||
* For example, if pmsBf=0xff00, then copy pal[128] ~ pal[255].
|
||||
*
|
||||
* pmsPp
|
||||
* If pmsBpp is 8 then this is pointer to pallet. If pmsBpp is 16 and
|
||||
* pmsPp is not 0, then shadow is exists and this is pointer to it's data.
|
||||
*
|
||||
*/
|
||||
|
||||
bool pms256_checkfmt(uint8_t *data);
|
||||
struct cg *pms256_extract(uint8_t *data);
|
||||
bool pms64k_checkfmt(uint8_t *data);
|
||||
struct cg *pms64k_extract(uint8_t *data);
|
||||
struct cg *pms_getpal(uint8_t *data);
|
||||
|
||||
#endif /* SYSTEM4_PMS_H */
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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 "little_endian.h"
|
||||
#include "cg.h"
|
||||
#include "qnt.h"
|
||||
#include "system4.h"
|
||||
|
||||
/*
|
||||
zlib の展開バッファで、幅×高さ×3に、さらにどれくらい余裕をとるか
|
||||
(リクルスで 1164バイトというのがあった)
|
||||
*/
|
||||
#define ZLIBBUF_MARGIN 5*1024
|
||||
|
||||
/*
|
||||
static methods
|
||||
*/
|
||||
static struct qnt_header *extract_header(uint8_t *b);
|
||||
static void extract_pixel(struct qnt_header *qnt, uint8_t *pic, uint8_t *b);
|
||||
static void extract_alpha(struct qnt_header *qnt, uint8_t *pic, uint8_t *b);
|
||||
|
||||
|
||||
/*
|
||||
* Get information from header
|
||||
*
|
||||
* b: raw data
|
||||
*
|
||||
* return: acquired qnt information object
|
||||
*/
|
||||
static struct qnt_header *extract_header(uint8_t *b) {
|
||||
struct qnt_header *qnt = malloc(sizeof(struct qnt_header));
|
||||
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);
|
||||
}
|
||||
|
||||
return qnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract qnt header and pixel
|
||||
*
|
||||
* data: raw data (pointer to data top)
|
||||
*
|
||||
* return: extracted image data and information
|
||||
*/
|
||||
struct cg *qnt_extract(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct qnt_header *qnt = extract_header(data);
|
||||
|
||||
cg->pic = malloc(sizeof(uint8_t) * ((qnt->width+10) * (qnt->height+10) * 3));
|
||||
extract_pixel(qnt, cg->pic, data + qnt->hdr_size);
|
||||
|
||||
if (qnt->alpha_size != 0) {
|
||||
cg->alpha = malloc(sizeof(uint8_t) * ((qnt->width+10) * (qnt->height+10)));
|
||||
extract_alpha(qnt, (uint8_t *)cg->alpha, data + qnt->hdr_size + qnt->pixel_size);
|
||||
}
|
||||
|
||||
cg->type = ALCG_QNT;
|
||||
cg->x = qnt->x0;
|
||||
cg->y = qnt->y0;
|
||||
cg->width = qnt->width;
|
||||
cg->height = qnt->height;
|
||||
cg->pal = NULL;
|
||||
|
||||
return cg;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* qnt.h 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/11/28 add header size information
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_QNT_H
|
||||
#define SYSTEM4_QNT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "cg.h"
|
||||
|
||||
struct qnt_header {
|
||||
int hdr_size; // header size
|
||||
int x0; // display location x
|
||||
int y0; // display location y
|
||||
int width; // image width
|
||||
int height; // image height
|
||||
int bpp; // image data depth
|
||||
int rsv; // reserved data
|
||||
int pixel_size; // compressed pixel size
|
||||
int alpha_size; // compressed alpha pixel size
|
||||
};
|
||||
|
||||
bool qnt_checkfmt(uint8_t *data);
|
||||
struct cg *qnt_extract(uint8_t *data);
|
||||
|
||||
#endif /* __QNT_H__ */
|
||||
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_QUEUE_H
|
||||
#define SYSTEM4_QUEUE_H
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The
|
||||
* elements are singly linked for minimum space and pointer manipulation
|
||||
* overhead at the expense of O(n) removal for arbitrary elements. New
|
||||
* elements can be added to the list after an existing element or at the
|
||||
* head of the list. Elements being removed from the head of the list
|
||||
* should use the explicit macro for this purpose for optimum
|
||||
* efficiency. A singly-linked list may only be traversed in the forward
|
||||
* direction. Singly-linked lists are ideal for applications with large
|
||||
* datasets and few or no removals or for implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define LIST_INIT(head) do { \
|
||||
(head)->lh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->lh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.le_next))
|
||||
|
||||
/*
|
||||
* List access methods.
|
||||
*/
|
||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) do { \
|
||||
(head)->slh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
while(curelm->field.sle_next != (elm)) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue declarations.
|
||||
*/
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first; /* first element */ \
|
||||
struct type **stqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue functions.
|
||||
*/
|
||||
#define STAILQ_INIT(head) do { \
|
||||
(head)->stqh_first = NULL; \
|
||||
(head)->stqh_last = &(head)->stqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
(head)->stqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.stqe_next = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
(listelm)->field.stqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
|
||||
(head)->stqh_last = &(head)->stqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->stqh_first == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->stqh_first; \
|
||||
while (curelm->field.stqe_next != (elm)) \
|
||||
curelm = curelm->field.stqe_next; \
|
||||
if ((curelm->field.stqe_next = \
|
||||
curelm->field.stqe_next->field.stqe_next) == NULL) \
|
||||
(head)->stqh_last = &(curelm)->field.stqe_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->stqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.stqe_next))
|
||||
|
||||
#define STAILQ_CONCAT(head1, head2) do { \
|
||||
if (!STAILQ_EMPTY((head2))) { \
|
||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue access methods.
|
||||
*/
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->sqh_first == (elm)) { \
|
||||
SIMPLEQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->sqh_first; \
|
||||
while (curelm->field.sqe_next != (elm)) \
|
||||
curelm = curelm->field.sqe_next; \
|
||||
if ((curelm->field.sqe_next = \
|
||||
curelm->field.sqe_next->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(curelm)->field.sqe_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->sqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.sqe_next))
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL)
|
||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define _TAILQ_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
qual type *tqh_first; /* first element */ \
|
||||
qual type *qual *tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define _TAILQ_ENTRY(type, qual) \
|
||||
struct { \
|
||||
qual type *tqe_next; /* next element */ \
|
||||
qual type *qual *tqe_prev; /* address of previous next element */\
|
||||
}
|
||||
#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->tqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.tqe_next))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
|
||||
(var); \
|
||||
(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
|
||||
|
||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
/*
|
||||
* Tail queue access methods.
|
||||
*/
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ (void *)&head, (void *)&head }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = (void *)(head); \
|
||||
(head)->cqh_last = (void *)(head); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == (void *)(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == (void *)(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = (void *)(head); \
|
||||
if ((head)->cqh_last == (void *)(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (void *)(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == (void *)(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == (void *)(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == (void *)(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->cqh_first); \
|
||||
(var) != (const void *)(head); \
|
||||
(var) = ((var)->field.cqe_next))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for ((var) = ((head)->cqh_last); \
|
||||
(var) != (const void *)(head); \
|
||||
(var) = ((var)->field.cqe_prev))
|
||||
|
||||
/*
|
||||
* Circular queue access methods.
|
||||
*/
|
||||
#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
|
||||
#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
|
||||
(((elm)->field.cqe_next == (void *)(head)) \
|
||||
? ((head)->cqh_first) \
|
||||
: (elm->field.cqe_next))
|
||||
#define CIRCLEQ_LOOP_PREV(head, elm, field) \
|
||||
(((elm)->field.cqe_prev == (void *)(head)) \
|
||||
? ((head)->cqh_last) \
|
||||
: (elm->field.cqe_prev))
|
||||
|
||||
#endif /* sys/queue.h */
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
* Copyright (C) 2000- Fumihiko Murata <fmurata@p1.tcnet.ne.jp>
|
||||
*
|
||||
* 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, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_SDL_CORE_H
|
||||
#define SYSTEM4_SDL_CORE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int sdl_initialize(void);
|
||||
void sdl_remove(void);
|
||||
|
||||
void sdl_set_window_size(int x, int y, int w, int h);
|
||||
void sdl_fullscreen(bool on);
|
||||
|
||||
#endif /* SYSTEM4_SDL_CORE_H */
|
||||
@@ -0,0 +1,58 @@
|
||||
/* sdl_private.h SDL only private data
|
||||
*
|
||||
* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
* Copyright (C) 2000- Fumihiko Murata <fmurata@p1.tcnet.ne.jp>
|
||||
*
|
||||
* 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, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_SDL_PRIVATE_H
|
||||
#define SYSTEM4_SDL_PRIVATE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <SDL.h>
|
||||
|
||||
//#include "ags.h"
|
||||
//#include "font.h"
|
||||
|
||||
struct sdl_private_data {
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Texture *texture;
|
||||
SDL_Surface *display; /* toplevel surface */
|
||||
SDL_Surface *dib; /* offscreen surface */
|
||||
SDL_Color col[256]; /* color pallet */
|
||||
unsigned long white; /* white pixel */
|
||||
//agsurface_t *cimg;
|
||||
SDL_Rect view;
|
||||
//FONT *font;
|
||||
bool dirty;
|
||||
bool ms_active; /* mouse is active */
|
||||
bool fs_on;
|
||||
int winoffset_x; /* draw offset in Window x */
|
||||
int winoffset_y; /* y */
|
||||
};
|
||||
|
||||
struct sdl_private_data sdl;
|
||||
|
||||
extern void sdl_cursor_init(void);
|
||||
extern void sdl_shadow_init(void);
|
||||
extern int sdl_nearest_color(int r, int g, int b);
|
||||
|
||||
#define SDL_AllocSurface(flags,w,h,d,r,g,b,a) SDL_CreateRGBSurface(0,w,h,d,r,g,b,a)
|
||||
|
||||
#define setRect(r,xx,yy,ww,hh) (r).x=(xx),(r).y=(yy),(r).w=(ww),(r).h=(hh)
|
||||
#define setOffset(s,x,y) (s->pixels) + (x) * (s->format->BytesPerPixel) + (y) * s->pitch
|
||||
|
||||
#endif /* SYSTEM4_SDL_PRIVATE_H */
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
* Copyright (C) 2000- Fumihiko Murata <fmurata@p1.tcnet.ne.jp>
|
||||
*
|
||||
* 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, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <SDL.h>
|
||||
#include "system4.h"
|
||||
#include "sdl_private.h"
|
||||
|
||||
int sdl_initialize(void)
|
||||
{
|
||||
memset(&sdl, 0, sizeof(struct sdl_private_data));
|
||||
|
||||
// make toplevel window
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
sdl.window = SDL_CreateWindow("XSystem4",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
config.view_width,
|
||||
config.view_height,
|
||||
SDL_WINDOW_RESIZABLE);
|
||||
sdl.renderer = SDL_CreateRenderer(sdl.window, -1, 0);
|
||||
|
||||
// offscreen pixmap
|
||||
//makeDIB(config.view_width, config.view_height, SYS4_DEFAULT_DEPTH);
|
||||
|
||||
// init cursor
|
||||
//sdl_cursor_init();
|
||||
|
||||
//sdl_setWindowSize(0, 0, config.view_width, config.view_height);
|
||||
|
||||
//sdl_shadow_init();
|
||||
|
||||
//joy_open();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sdl_remove(void)
|
||||
{
|
||||
if (!sdl.window)
|
||||
return;
|
||||
|
||||
//SDL_FreeSurface(sdl.dib);
|
||||
SDL_DestroyRenderer(sdl.renderer);
|
||||
//joy_close();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void sdl_fullscreen(bool on)
|
||||
{
|
||||
if (on && !sdl.fs_on) {
|
||||
sdl.fs_on = true;
|
||||
SDL_SetWindowFullscreen(sdl.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
} else if (!on && sdl.fs_on) {
|
||||
sdl.fs_on = false;
|
||||
SDL_SetWindowFullscreen(sdl.window, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void sdl_set_window_size(int x, int y, int w, int h)
|
||||
{
|
||||
sdl.view.x = x;
|
||||
sdl.view.y = y;
|
||||
|
||||
if (w == sdl.view.w && h == sdl.view.h)
|
||||
return;
|
||||
|
||||
sdl.view.w = w;
|
||||
sdl.view.h = h;
|
||||
|
||||
SDL_SetWindowSize(sdl.window, w, h);
|
||||
SDL_RenderSetLogicalSize(sdl.renderer, w, h);
|
||||
if (sdl.display)
|
||||
SDL_FreeSurface(sdl.display);
|
||||
if (sdl.texture)
|
||||
SDL_DestroyTexture(sdl.texture);
|
||||
sdl.display = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);
|
||||
sdl.texture = SDL_CreateTexture(sdl.renderer, sdl.display->format->format,
|
||||
SDL_TEXTUREACCESS_STATIC, w, h);
|
||||
}
|
||||
@@ -57,25 +57,34 @@ mem_alloc char *_xstrdup(const char *in, const char *func)
|
||||
return out;
|
||||
}
|
||||
|
||||
noreturn void sys_error(char *fmt, ...)
|
||||
noreturn void sys_verror(const char *fmt, va_list ap)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
sys_exit(1);
|
||||
}
|
||||
|
||||
void sys_warning(char *fmt, ...)
|
||||
noreturn void sys_error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
sys_verror(fmt, ap);
|
||||
}
|
||||
|
||||
void sys_vwarning(const char *fmt, va_list ap)
|
||||
{
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
|
||||
void sys_warning(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
sys_vwarning(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void sys_message(char *fmt, ...)
|
||||
void sys_message(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
@@ -45,7 +45,7 @@ static char *config_strdup(const char *str)
|
||||
return out;
|
||||
}
|
||||
|
||||
static int config_handler(void *user, unused const char *section, const char *name, const char *value)
|
||||
static int config_handler(void *user, possibly_unused const char *section, const char *name, const char *value)
|
||||
{
|
||||
struct config *config = (struct config*)user;
|
||||
if (!strcmp(name, "GameName")) {
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
#ifndef SYSTEM4_H
|
||||
#define SYSTEM4_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// TODO: should put in a separate header and guard with feature checks
|
||||
#define const_pure __attribute__((const))
|
||||
#define mem_alloc __attribute__((malloc))
|
||||
#define noreturn _Noreturn
|
||||
#define unused __attribute__((unused))
|
||||
#define possibly_unused __attribute__((unused))
|
||||
|
||||
#define ERROR(fmt, ...) \
|
||||
sys_error("*ERROR*(%s:%s:%d): " fmt "\n", __FILE__, __func__, __LINE__, ##__VA_ARGS__)
|
||||
@@ -34,9 +35,11 @@
|
||||
#define NOTICE(fmt, ...) \
|
||||
sys_message(fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
noreturn void sys_error(char *fmt, ...);
|
||||
void sys_warning(char *fmt, ...);
|
||||
void sys_message(char *fmt, ...);
|
||||
noreturn void sys_verror(const char *fmt, va_list ap);
|
||||
noreturn void sys_error(const char *fmt, ...);
|
||||
void sys_vwarning(const char *fmt, va_list ap);
|
||||
void sys_warning(const char *fmt, ...);
|
||||
void sys_message(const char *fmt, ...);
|
||||
|
||||
noreturn void sys_exit(int code);
|
||||
|
||||
|
||||
@@ -34,9 +34,6 @@
|
||||
// When the IP is set to VM_RETURN, the VM halts
|
||||
#define VM_RETURN 0xFFFFFFFF
|
||||
|
||||
#define EXECUTION_ERROR(msg, ...) \
|
||||
ERROR("%s (0x%X): " msg, current_instruction_name(), instr_ptr, ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* NOTE: The current implementation is a simple bytecode interpreter.
|
||||
* System40.exe uses a JIT compiler, and we should too.
|
||||
@@ -66,7 +63,7 @@ static int32_t heap_free_ptr = 0;
|
||||
|
||||
// Stack of function call frames
|
||||
static struct function_call call_stack[4096];
|
||||
static int32_t call_stack_ptr = 1; // 0 = imaginary frame before main()
|
||||
static int32_t call_stack_ptr = 0; // 0 = imaginary frame before main()
|
||||
|
||||
struct ain *ain;
|
||||
static size_t instr_ptr = 0;
|
||||
@@ -131,7 +128,7 @@ static const char *vm_ptrtype_string(enum vm_pointer_type type) {
|
||||
void heap_unref(int slot)
|
||||
{
|
||||
if (heap[slot].ref <= 0) {
|
||||
EXECUTION_ERROR("double free of slot %d (%s)", slot, vm_ptrtype_string(heap[slot].type));
|
||||
VM_ERROR("double free of slot %d (%s)", slot, vm_ptrtype_string(heap[slot].type));
|
||||
}
|
||||
if (--heap[slot].ref <= 0) {
|
||||
switch (heap[slot].type) {
|
||||
@@ -211,7 +208,7 @@ static union vm_value *stack_pop_var(void)
|
||||
int32_t page_index = stack_pop().i;
|
||||
int32_t heap_index = stack_pop().i;
|
||||
if (!heap[heap_index].page || page_index >= heap[heap_index].page->nr_vars)
|
||||
EXECUTION_ERROR("Out of bounds page index: %d/%d", heap_index, page_index);
|
||||
VM_ERROR("Out of bounds page index: %d/%d", heap_index, page_index);
|
||||
return &heap[heap_index].page->values[page_index];
|
||||
}
|
||||
|
||||
@@ -310,7 +307,7 @@ static void hll_call(int libno, int fno)
|
||||
{
|
||||
struct ain_hll_function *f = &ain->libraries[libno].functions[fno];
|
||||
if (!f->fun)
|
||||
EXECUTION_ERROR("Unimplemented HLL function: %s.%s", ain->libraries[libno].name, f->name);
|
||||
VM_ERROR("Unimplemented HLL function: %s.%s", ain->libraries[libno].name, f->name);
|
||||
|
||||
union vm_value args[HLL_MAX_ARGS];
|
||||
for (int i = f->nr_arguments - 1; i >= 0; i--) {
|
||||
@@ -950,7 +947,7 @@ static void execute_instruction(int16_t opcode)
|
||||
b = stack_pop().i;
|
||||
a = stack_pop().i;
|
||||
if (a == -1)
|
||||
EXECUTION_ERROR("Assignment to null-pointer");
|
||||
VM_ERROR("Assignment to null-pointer");
|
||||
if (heap[a].page)
|
||||
delete_page(heap[a].page);
|
||||
heap[a].page = copy_page(heap[b].page);
|
||||
@@ -1050,7 +1047,7 @@ static void execute_instruction(int16_t opcode)
|
||||
case FUNC:
|
||||
break;
|
||||
default:
|
||||
EXECUTION_ERROR("Unimplemented instruction");
|
||||
VM_ERROR("Unimplemented instruction");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1061,11 +1058,11 @@ static void vm_execute(void)
|
||||
if (instr_ptr == VM_RETURN)
|
||||
return;
|
||||
if (instr_ptr >= ain->code_size) {
|
||||
EXECUTION_ERROR("Illegal instruction pointer: 0x%08lX", instr_ptr);
|
||||
VM_ERROR("Illegal instruction pointer: 0x%08lX", instr_ptr);
|
||||
}
|
||||
opcode = get_opcode(instr_ptr);
|
||||
if (opcode >= NR_OPCODES) {
|
||||
EXECUTION_ERROR("Illegal opcode: 0x%04X", opcode);
|
||||
VM_ERROR("Illegal opcode: 0x%04X", opcode);
|
||||
}
|
||||
execute_instruction(opcode);
|
||||
instr_ptr += instructions[opcode].ip_inc;
|
||||
@@ -1140,6 +1137,7 @@ void vm_execute_ain(struct ain *program)
|
||||
// Initialize globals
|
||||
heap[0].page = alloc_page(GLOBAL_PAGE, 0, ain->nr_globals);
|
||||
for (int i = 0; i < ain->nr_globals; i++) {
|
||||
int slot;
|
||||
switch (ain->globals[i].data_type) {
|
||||
case AIN_STRING:
|
||||
heap[0].page->values[i].i = heap_alloc_slot(VM_STRING);
|
||||
@@ -1147,6 +1145,11 @@ void vm_execute_ain(struct ain *program)
|
||||
case AIN_REF_TYPE:
|
||||
heap[0].page->values[i].i = -1;
|
||||
break;
|
||||
case AIN_ARRAY_TYPE:
|
||||
slot = heap_alloc_slot(VM_PAGE);
|
||||
heap[0].page->values[i].i = slot;
|
||||
heap[slot].page = NULL;
|
||||
break;
|
||||
case AIN_STRUCT:
|
||||
create_struct(ain->globals[i].struct_type, &heap[0].page->values[i]);
|
||||
break;
|
||||
@@ -1172,3 +1175,21 @@ void vm_execute_ain(struct ain *program)
|
||||
vm_call(ain->main, -1);
|
||||
}
|
||||
|
||||
void vm_stack_trace(void)
|
||||
{
|
||||
for (int i = call_stack_ptr - 1; i >= 0; i--) {
|
||||
sys_warning("\t%s\n", ain->functions[call_stack[i].fno].name);
|
||||
}
|
||||
}
|
||||
|
||||
noreturn void _vm_error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
sys_vwarning(fmt, ap);
|
||||
va_end(ap);
|
||||
sys_warning("at %s (0x%X) in:\n", current_instruction_name(), instr_ptr);
|
||||
vm_stack_trace();
|
||||
sys_exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "system4.h"
|
||||
|
||||
// Non-heap values. Stored in pages and on the stack.
|
||||
union vm_value {
|
||||
@@ -126,4 +127,10 @@ union vm_value vm_copy(union vm_value v, enum ain_data_type type);
|
||||
|
||||
void vm_call(int fno, int struct_page);
|
||||
|
||||
void vm_stack_trace(void);
|
||||
noreturn void _vm_error(const char *fmt, ...);
|
||||
|
||||
#define VM_ERROR(fmt, ...) \
|
||||
_vm_error("*ERROR*(%s:%s:%d): " fmt "\n", __FILE__, __func__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#endif /* SYSTEM4_VM_H */
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* vsp.c extract VSP 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
|
||||
*
|
||||
* 0.00 97/11/06 初版
|
||||
* 0.01 97/11/12 TYPO
|
||||
* 0.01-01 97/11/13 ヘッダ情報の返しかたの変更
|
||||
* 0.01-02 97/11/27 記憶子の変更
|
||||
* 0.01-03 97/12/06 ヘッダの誤認識の修正
|
||||
* 0.02 98/02/26 デバッグ済み
|
||||
* 0.03 98/03/20 ヘッダチェックのミス
|
||||
* 0.03 98/12/19 dalkで640x401なCGがあったのでその対策
|
||||
* @version 1.5 00/09/17 rewrite for changeing interface
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "little_endian.h"
|
||||
#include "graphics.h"
|
||||
#include "cg.h"
|
||||
#include "vsp.h"
|
||||
|
||||
/*
|
||||
* static methods
|
||||
*/
|
||||
static struct vsp_header *extract_header(uint8_t *b);
|
||||
static void getpal(Pallet256 *pal, uint8_t *b);
|
||||
static void extract(struct vsp_header *vsp, uint8_t *pic, uint8_t *b);
|
||||
|
||||
/*
|
||||
* extraction buffer
|
||||
*/
|
||||
static uint8_t _bc[4][480];
|
||||
static uint8_t _bp[4][480];
|
||||
static uint8_t *bc[4];
|
||||
static uint8_t *bp[4];
|
||||
|
||||
/*
|
||||
* Get information from cg header
|
||||
* b: raw data (pointer to header)
|
||||
* return: acquired vsp information object
|
||||
*/
|
||||
static struct vsp_header *extract_header(uint8_t *b) {
|
||||
struct vsp_header *vsp = malloc(sizeof(struct vsp_header));
|
||||
|
||||
vsp->vspX0 = LittleEndian_getW(b, 0);
|
||||
vsp->vspY0 = LittleEndian_getW(b, 2);
|
||||
vsp->vspXW = LittleEndian_getW(b, 4) - vsp->vspX0;
|
||||
vsp->vspYW = LittleEndian_getW(b, 6) - vsp->vspY0;
|
||||
vsp->vspPb = b[9];
|
||||
vsp->vspPp = 0x0a;
|
||||
vsp->vspDp = 0x3a;
|
||||
|
||||
return vsp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get pallet from raw data
|
||||
* pal: pallet to be stored
|
||||
* b : raw data (pointer to pallet)
|
||||
*/
|
||||
static void getpal(Pallet256 *pal, uint8_t *b) {
|
||||
int red, green, blue, i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
blue = b[i * 3 + 0];
|
||||
red = b[i * 3 + 1];
|
||||
green = b[i * 3 + 2];
|
||||
pal->red[i] = (red << 4);
|
||||
pal->green[i] = (green << 4);
|
||||
pal->blue[i] = (blue << 4);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do extract vsp image
|
||||
* vsp: vsp header information
|
||||
* pic: pixel to be stored
|
||||
* b : raw data (pointer to pixel)
|
||||
*/
|
||||
static void extract(struct vsp_header *vsp, uint8_t *pic, uint8_t *b) {
|
||||
int c0;
|
||||
uint8_t b0, b1, b2, b3, mask = 0;
|
||||
uint8_t *bt;
|
||||
int i, l, x, y, pl, loc;
|
||||
|
||||
bp[0] = _bp[0]; bc[0] = _bc[0];
|
||||
bp[1] = _bp[1]; bc[1] = _bc[1];
|
||||
bp[2] = _bp[2]; bc[2] = _bc[2];
|
||||
bp[3] = _bp[3]; bc[3] = _bc[3];
|
||||
|
||||
for (x = 0; x < vsp->vspXW; x++) {
|
||||
for (pl = 0; pl < 4; pl++) {
|
||||
y = 0;
|
||||
while(y < vsp->vspYW) {
|
||||
c0 = *b++;
|
||||
if (c0 >= 0x08) {
|
||||
*(bc[pl] + y) = c0; y++;
|
||||
} else if (c0 == 0x00) {
|
||||
l = (*b) + 1; b++;
|
||||
memcpy(bc[pl] + y, bp[pl] + y, l);
|
||||
y+=l;
|
||||
} else if (c0 == 0x01) {
|
||||
l = (*b) + 1; b++;
|
||||
b0 = *b++;
|
||||
memset(bc[pl] + y, b0, l);
|
||||
y+=l;
|
||||
} else if (c0 == 0x02) {
|
||||
l = (*b) + 1; b++;
|
||||
b0 = *b++; b1 = *b++;
|
||||
for (i = 0; i < l; i++) {
|
||||
*(bc[pl] + y) = b0; y++;
|
||||
*(bc[pl] + y) = b1; y++;
|
||||
}
|
||||
} else if (c0 == 0x03) {
|
||||
l = (*b) + 1; b++;
|
||||
for (i = 0; i < l; i++) {
|
||||
*(bc[pl] + y) = (*(bc[0] + y) ^ mask); y++;
|
||||
}
|
||||
mask = 0;
|
||||
} else if (c0 == 0x04) {
|
||||
l = (*b) + 1; b++;
|
||||
for (i = 0; i < l; i++) {
|
||||
*(bc[pl] + y) = (*(bc[1] + y) ^ mask); y++;
|
||||
}
|
||||
mask = 0;
|
||||
} else if (c0 == 0x05) {
|
||||
l = (*b) + 1; b++;
|
||||
for (i = 0; i < l; i++) {
|
||||
*(bc[pl] + y) = (*(bc[2] + y) ^ mask); y++;
|
||||
}
|
||||
mask = 0;
|
||||
} else if (c0 == 0x06) {
|
||||
mask = 0xff;
|
||||
} else if (c0 == 0x07) {
|
||||
*(bc[pl] + y) = *b++ ; y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* plane -> packed 展開 */
|
||||
for (y = 0; y < vsp->vspYW; y++) {
|
||||
loc = (y * vsp->vspXW + x) * 8;
|
||||
b0 = bc[0][y]; b1 = bc[1][y];
|
||||
b2 = bc[2][y]; b3 = bc[3][y];
|
||||
*(pic + loc + 0) = ((b0>>7)&0x01)|((b1>>6)&0x02)|((b2>>5)&0x04)|((b3>>4)&0x08);
|
||||
*(pic + loc + 1) = ((b0>>6)&0x01)|((b1>>5)&0x02)|((b2>>4)&0x04)|((b3>>3)&0x08);
|
||||
*(pic + loc + 2) = ((b0>>5)&0x01)|((b1>>4)&0x02)|((b2>>3)&0x04)|((b3>>2)&0x08);
|
||||
*(pic + loc + 3) = ((b0>>4)&0x01)|((b1>>3)&0x02)|((b2>>2)&0x04)|((b3>>1)&0x08);
|
||||
*(pic + loc + 4) = ((b0>>3)&0x01)|((b1>>2)&0x02)|((b2>>1)&0x04)|((b3 )&0x08);
|
||||
*(pic + loc + 5) = ((b0>>2)&0x01)|((b1>>1)&0x02)|((b2 )&0x04)|((b3<<1)&0x08);
|
||||
*(pic + loc + 6) = ((b0>>1)&0x01)|((b1 )&0x02)|((b2<<1)&0x04)|((b3<<2)&0x08);
|
||||
*(pic + loc + 7) = ((b0 )&0x01)|((b1<<1)&0x02)|((b2<<2)&0x04)|((b3<<3)&0x08);
|
||||
}
|
||||
/* bc -> bpにコピー */
|
||||
bt = bp[0]; bp[0] = bc[0]; bc[0] = bt;
|
||||
bt = bp[1]; bp[1] = bc[1]; bc[1] = bt;
|
||||
bt = bp[2]; bp[2] = bc[2]; bc[2] = bt;
|
||||
bt = bp[3]; bp[3] = bc[3]; bc[3] = bt;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check data is vsp format cg or not
|
||||
* data: raw data (pointer to data top)
|
||||
* return: true if data is vsp
|
||||
*/
|
||||
bool vsp_checkfmt(uint8_t *data) {
|
||||
int x0 = LittleEndian_getW(data, 0);
|
||||
int y0 = LittleEndian_getW(data, 2);
|
||||
int w = LittleEndian_getW(data, 4) - x0;
|
||||
int h = LittleEndian_getW(data, 6) - y0;
|
||||
|
||||
if (x0 < 0 || x0 > 80 || y0 < 0 || y0 > 400) return false;
|
||||
/* 401: for dalk's broken cg */
|
||||
if (w < 0 || w > 80 || h < 0 || h > 401) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract vsp, header, pallet and pixel
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted image data and information
|
||||
*/
|
||||
struct cg *vsp_extract(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct vsp_header *vsp = extract_header(data);
|
||||
|
||||
cg->pal = malloc(sizeof(Pallet256));
|
||||
getpal(cg->pal, data + vsp->vspPp);
|
||||
|
||||
/* +10: margin for broken cg */
|
||||
cg->pic = malloc(sizeof(uint8_t) * ((vsp->vspXW * 8 + 10) * (vsp->vspYW + 10)));
|
||||
extract(vsp, cg->pic, data + vsp->vspDp);
|
||||
|
||||
cg->type = ALCG_VSP;
|
||||
cg->x = vsp->vspX0 * 8;
|
||||
cg->y = vsp->vspY0;
|
||||
cg->width = vsp->vspXW * 8;
|
||||
cg->height = vsp->vspYW;
|
||||
cg->vsp_bank = vsp->vspPb;
|
||||
cg->alpha = NULL;
|
||||
|
||||
free(vsp);
|
||||
|
||||
return cg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract vsp pallet only
|
||||
* data: raw data (pointer to data top)
|
||||
* return: extracted pallet data
|
||||
*/
|
||||
struct cg *vsp_getpal(uint8_t *data) {
|
||||
struct cg *cg = calloc(1, sizeof(struct cg));
|
||||
struct vsp_header *vsp = extract_header(data);
|
||||
|
||||
cg->pal = malloc(sizeof(Pallet256));
|
||||
getpal(cg->pal, data + vsp->vspPp);
|
||||
|
||||
cg->type = ALCG_VSP;
|
||||
cg->pic = NULL;
|
||||
cg->alpha = NULL;
|
||||
|
||||
free(vsp);
|
||||
|
||||
return cg;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* vsp.h extract VSP 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, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM4_VSP_H
|
||||
#define SYSTEM4_VSP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "cg.h"
|
||||
|
||||
struct vsp_header {
|
||||
int vspX0; // display location x
|
||||
int vspY0; // display location y
|
||||
int vspXW; // image width
|
||||
int vspYW; // image height
|
||||
int vspPb; // default pallet bank
|
||||
int vspPp; // pointer to pallet
|
||||
int vspDp; // pointer to pixel data
|
||||
};
|
||||
/*
|
||||
* vspPb:
|
||||
* VSP has only 16 pallets. When 256 pallets mode, this parameter determine
|
||||
* where to copy these 16 pallets in 256 pallets.
|
||||
* The parameter is from 0 to 15, and for example, if it is 1 then copy
|
||||
* 16 palltes into pal[16] ~ pal[31].
|
||||
*/
|
||||
|
||||
bool vsp_checkfmt(uint8_t *data);
|
||||
struct cg *vsp_extract(uint8_t *data);
|
||||
struct cg *vsp_getpal(uint8_t *data);
|
||||
|
||||
#endif /* SYSTEM4_VSP_H */
|
||||
Reference in New Issue
Block a user