diff --git a/ald.c b/ald.c index 0e5d423..33eb849 100644 --- a/ald.c +++ b/ald.c @@ -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; diff --git a/bmp.c b/bmp.c new file mode 100644 index 0000000..3da938a --- /dev/null +++ b/bmp.c @@ -0,0 +1,254 @@ +/* + * bmp.c extract 8/24 bit BMP cg + * + * Copyright (C) 1999 TAJIRI,Yasuhiro + * rewrited 2000 CHIKAMA Masaki + * 2019 Nunuhara Cabbage + * + * 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 +#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; +} diff --git a/bmp.h b/bmp.h new file mode 100644 index 0000000..757c47d --- /dev/null +++ b/bmp.h @@ -0,0 +1,57 @@ +/* + * bmp.h extract 8/24 bit BMP cg + * + * Copyright (C) 1999 TAJIRI,Yasuhiro + * rewrited 2000 Masaki Chikam + * 2019 Nunuhara Cabbage + * + * 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 +#include +#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 */ diff --git a/cg.c b/cg.c index 001729f..e317b44 100644 --- a/cg.c +++ b/cg.c @@ -14,11 +14,161 @@ * along with this program; if not, see . */ +#include +#include +#include #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; +} + diff --git a/cg.h b/cg.h index 0392311..fa51fb6 100644 --- a/cg.h +++ b/cg.h @@ -1,4 +1,6 @@ -/* Copyright (C) 2019 Nunuhara Cabbage +/* Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage * * 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 +#include +#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 */ diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..1390e13 --- /dev/null +++ b/graphics.h @@ -0,0 +1,51 @@ +/* Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage + * + * 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 . + */ + +#ifndef SYSTEM4_GRAPHICS_H +#define SYSTEM4_GRAPHICS_H + +#include +#include + +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 */ diff --git a/hll/OutputLog.c b/hll/OutputLog.c index b4fe4bf..4210b9e 100644 --- a/hll/OutputLog.c +++ b/hll/OutputLog.c @@ -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), diff --git a/hll/SACT2.c b/hll/SACT2.c index 9e4edd9..3f46473 100644 --- a/hll/SACT2.c +++ b/hll/SACT2.c @@ -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) diff --git a/hll/hll.h b/hll/hll.h index 9a5aa86..7ed46a2 100644 --- a/hll/hll.h +++ b/hll/hll.h @@ -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 diff --git a/meson.build b/meson.build index b62d5a6..317e9a5 100644 --- a/meson.build +++ b/meson.build @@ -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]) diff --git a/page.c b/page.c index 48c4232..2b42539 100644 --- a/page.c +++ b/page.c @@ -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; diff --git a/pms.c b/pms.c new file mode 100644 index 0000000..ea62014 --- /dev/null +++ b/pms.c @@ -0,0 +1,320 @@ +/* + * pms.c extract 8/16 bit PMS cg + * + * Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage + * + * 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 +#include +#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; +} diff --git a/pms.h b/pms.h new file mode 100644 index 0000000..03fbf67 --- /dev/null +++ b/pms.h @@ -0,0 +1,70 @@ +/* + * pms.h extract 8/16 bit PMS cg + * + * Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage + * + * 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 +#include +#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 */ + diff --git a/qnt.c b/qnt.c new file mode 100644 index 0000000..17640e2 --- /dev/null +++ b/qnt.c @@ -0,0 +1,262 @@ +/* + * qnt.c extract QNT cg + * + * Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage + * + * 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 +#include + +#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; +} diff --git a/qnt.h b/qnt.h new file mode 100644 index 0000000..08003a6 --- /dev/null +++ b/qnt.h @@ -0,0 +1,48 @@ +/* + * qnt.h extract QNT cg + * + * Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage + * + * 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 +#include +#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__ */ diff --git a/queue.h b/queue.h new file mode 100644 index 0000000..b714506 --- /dev/null +++ b/queue.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 */ diff --git a/sdl_core.h b/sdl_core.h new file mode 100644 index 0000000..ddd387c --- /dev/null +++ b/sdl_core.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * Copyright (C) 2000- Fumihiko Murata + * + * 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 . + */ + +#ifndef SYSTEM4_SDL_CORE_H +#define SYSTEM4_SDL_CORE_H + +#include + +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 */ diff --git a/sdl_private.h b/sdl_private.h new file mode 100644 index 0000000..bf3f3a6 --- /dev/null +++ b/sdl_private.h @@ -0,0 +1,58 @@ +/* sdl_private.h SDL only private data + * + * Copyright (C) 2019 Nunuhara Cabbage + * Copyright (C) 2000- Fumihiko Murata + * + * 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 . + */ + +#ifndef SYSTEM4_SDL_PRIVATE_H +#define SYSTEM4_SDL_PRIVATE_H + +#include +#include + +//#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 */ diff --git a/sdl_video.c b/sdl_video.c new file mode 100644 index 0000000..d7c0ae3 --- /dev/null +++ b/sdl_video.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * Copyright (C) 2000- Fumihiko Murata + * + * 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 . + */ + +#include +#include +#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); +} diff --git a/system.c b/system.c index 56700d3..efecb52 100644 --- a/system.c +++ b/system.c @@ -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); diff --git a/system4.c b/system4.c index 3318aa5..f42f12d 100644 --- a/system4.c +++ b/system4.c @@ -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")) { diff --git a/system4.h b/system4.h index 8e40674..79b0520 100644 --- a/system4.h +++ b/system4.h @@ -17,13 +17,14 @@ #ifndef SYSTEM4_H #define SYSTEM4_H +#include #include // 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); diff --git a/vm.c b/vm.c index bdb6aa6..2ca8d74 100644 --- a/vm.c +++ b/vm.c @@ -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); +} + diff --git a/vm.h b/vm.h index 54f59d1..5642133 100644 --- a/vm.h +++ b/vm.h @@ -19,6 +19,7 @@ #include #include +#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 */ diff --git a/vsp.c b/vsp.c new file mode 100644 index 0000000..9442db5 --- /dev/null +++ b/vsp.c @@ -0,0 +1,247 @@ +/* + * vsp.c extract VSP cg + * + * Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage + * + * 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 +#include +#include +#include +#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; +} diff --git a/vsp.h b/vsp.h new file mode 100644 index 0000000..16758c6 --- /dev/null +++ b/vsp.h @@ -0,0 +1,50 @@ +/* + * vsp.h extract VSP cg + * + * Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * 2019 Nunuhara Cabbage + * + * 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 . +*/ + +#ifndef SYSTEM4_VSP_H +#define SYSTEM4_VSP_H + +#include +#include +#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 */