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:
Nunuhara Cabbage
2019-11-15 19:01:08 -08:00
parent 13b359058e
commit d3de009e1d
26 changed files with 2583 additions and 56 deletions
+4 -1
View File
@@ -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;
+254
View File
@@ -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;
}
+57
View File
@@ -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 */
+151 -1
View File
@@ -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;
}
+47 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+5 -5
View File
@@ -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
View File
@@ -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])
+5
View File
@@ -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;
+320
View File
@@ -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;
}
+70
View File
@@ -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 */
+262
View File
@@ -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;
}
+48
View File
@@ -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__ */
+574
View File
@@ -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
View File
@@ -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 */
+58
View File
@@ -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
View File
@@ -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);
}
+16 -7
View File
@@ -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);
+1 -1
View File
@@ -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")) {
+7 -4
View File
@@ -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);
+32 -11
View File
@@ -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);
}
+7
View File
@@ -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 */
+247
View File
@@ -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;
}
+50
View File
@@ -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 */