mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-10-01 11:18:22 +03:00
508 lines
11 KiB
C
508 lines
11 KiB
C
/*
|
|
* cg.c load and display cg
|
|
*
|
|
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
|
* 1998- <masaki-c@is.aist-nara.ac.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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
/* $Id: cg.c,v 1.12 2001/09/16 15:59:11 chikama Exp $ */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "portab.h"
|
|
#include "system.h"
|
|
#include "graphics.h"
|
|
#include "nact.h"
|
|
#include "ags.h"
|
|
#include "cg.h"
|
|
#include "vsp.h"
|
|
#include "pms.h"
|
|
#include "bmp.h"
|
|
#include "qnt.h"
|
|
#include "jpeg.h"
|
|
#include "ald_manager.h"
|
|
#include "filecheck.h"
|
|
#include "cache.h"
|
|
|
|
/* VSPのパレット展開バンク */
|
|
int cg_vspPB;
|
|
/* cg,palette 展開フラグ (funciotn flag) */
|
|
int cg_fflg;
|
|
/* CGをロードした回数を書き込む変数 */
|
|
int *cg_loadCountVar;
|
|
/* Brightness (PD command) */
|
|
int cg_brightness;
|
|
|
|
#define GCMD_EXTRACTCG(c) ((c) & 0x01)
|
|
#define GCMD_SET_PALETTE(c) ((c) & 0x02)
|
|
#define GCMD_LOAD_PALETTE(c) ((c) & 0x04)
|
|
|
|
/* CG表示位置に関する情報 */
|
|
static CG_WHERETODISP loc_policy, loc_policy0;
|
|
static MyPoint loc_where, loc_where0;
|
|
|
|
/* extracted cg data cache control object */
|
|
static cacher *cacheid;
|
|
|
|
/* static methods */
|
|
static CG_TYPE check_cgformat(uint8_t *data);
|
|
static void set_vspbank(uint8_t *pic, int bank, int width, int height);
|
|
static MyPoint set_display_loc(cgdata *cg);
|
|
static void clear_display_loc();
|
|
static void display_cg(cgdata *cg, int x, int y, int sprite_color, bool alpha_blend);
|
|
static cgdata *loader(int no);
|
|
|
|
|
|
/*
|
|
* Identify cg format
|
|
* data: pointer to compressed data
|
|
* return: cg type
|
|
*/
|
|
static 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) && nact->ags.world_depth >= 15) {
|
|
return ALCG_PMS16;
|
|
} else if (bmp16m_checkfmt(data) && nact->ags.world_depth >= 15) {
|
|
return ALCG_BMP24;
|
|
} else if (bmp256_checkfmt(data)) {
|
|
return ALCG_BMP8;
|
|
} else if (vsp_checkfmt(data)) {
|
|
return ALCG_VSP;
|
|
} else if (jpeg_checkfmt(data) && nact->ags.world_depth >= 15) {
|
|
return ALCG_JPEG;
|
|
}
|
|
WARNING("Unknown Cg Type");
|
|
return ALCG_UNKNOWN;
|
|
}
|
|
|
|
/*
|
|
* Modify pixel accoding to palette bank (vsp only)
|
|
* pic : pixel to be modifyied.
|
|
* bank : palette 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 data
|
|
* cg: freeing data object
|
|
*/
|
|
void cgdata_free(cgdata *cg) {
|
|
if (cg->pic) free(cg->pic);
|
|
if (cg->pal) free(cg->pal);
|
|
if (cg->alpha) free(cg->alpha);
|
|
free(cg);
|
|
}
|
|
|
|
/*
|
|
* Determine the location of display image
|
|
* cg: cg information
|
|
* return: x and y for display location
|
|
*/
|
|
static MyPoint set_display_loc(cgdata *cg) {
|
|
MyPoint p;
|
|
|
|
switch(loc_policy) {
|
|
case OFFSET_ABSOLUTE_GC:
|
|
case OFFSET_ABSOLUTE_JC:
|
|
p.x = loc_where.x;
|
|
p.y = loc_where.y;
|
|
break;
|
|
case OFFSET_RELATIVE_GC:
|
|
case OFFSET_RELATIVE_JC:
|
|
p.x = cg->x + loc_where.x;
|
|
p.y = cg->y + loc_where.y;
|
|
break;
|
|
case OFFSET_NOMOVE:
|
|
p.x = cg->x;
|
|
p.y = cg->y;
|
|
break;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
* Reset location movement according to loc_policy
|
|
*/
|
|
static void clear_display_loc() {
|
|
switch(loc_policy) {
|
|
case OFFSET_ABSOLUTE_GC:
|
|
case OFFSET_RELATIVE_GC:
|
|
if (loc_policy0 == OFFSET_ABSOLUTE_JC ||
|
|
loc_policy0 == OFFSET_RELATIVE_JC ) {
|
|
loc_policy = loc_policy0;
|
|
loc_where = loc_where0;
|
|
loc_policy0 = OFFSET_NOMOVE;
|
|
} else {
|
|
loc_policy = OFFSET_NOMOVE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Call ags to display cg
|
|
* cg: cg to be drawn
|
|
* x : display location x
|
|
* y : display location y
|
|
*/
|
|
static void display_cg(cgdata *cg, int x, int y, int sprite_color, bool alpha_blend) {
|
|
ags_drawCg(cg, x, y, cg_brightness, sprite_color, alpha_blend);
|
|
ags_updateArea(x, y, cg->width, cg->height);
|
|
}
|
|
|
|
/*
|
|
* Load cg data from file or cache
|
|
* no: file no ( >= 0)
|
|
* return: cg object(extracted)
|
|
*/
|
|
static cgdata *loader(int no) {
|
|
dridata *dfile;
|
|
cgdata *cg = NULL;
|
|
|
|
/* search in cache */
|
|
if (NULL != (cg = (cgdata *)cache_foreach(cacheid, no))) return cg;
|
|
|
|
/* read from file */
|
|
if (NULL == (dfile = ald_getdata(DRIFILE_CG, no))) return NULL;
|
|
|
|
/* update load cg counter */
|
|
if (cg_loadCountVar != NULL) {
|
|
(*(cg_loadCountVar + no + 1))++;
|
|
}
|
|
|
|
/* extract cg */
|
|
switch (check_cgformat(dfile->data)) {
|
|
case ALCG_VSP:
|
|
cg = vsp_extract(dfile->data);
|
|
break;
|
|
case ALCG_PMS8:
|
|
cg = pms256_extract(dfile->data);
|
|
break;
|
|
case ALCG_PMS16:
|
|
cg = pms64k_extract(dfile->data);
|
|
break;
|
|
case ALCG_BMP8:
|
|
cg = bmp256_extract(dfile->data);
|
|
break;
|
|
case ALCG_BMP24:
|
|
cg = bmp16m_extract(dfile->data);
|
|
break;
|
|
case ALCG_QNT:
|
|
cg = qnt_extract(dfile->data);
|
|
break;
|
|
case ALCG_JPEG:
|
|
cg = jpeg_extract(dfile->data, dfile->size);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/* insert to cache */
|
|
if (cg) {
|
|
int size = cg->width * cg->height * (cg->depth / 8);
|
|
cache_insert(cacheid, no, cg, size, NULL);
|
|
}
|
|
|
|
/* ok to free */
|
|
ald_freedata(dfile);
|
|
|
|
return cg;
|
|
}
|
|
|
|
/*
|
|
* Initilize cache
|
|
*/
|
|
void cg_init(void) {
|
|
cacheid = cache_new(cgdata_free);
|
|
cg_reset();
|
|
}
|
|
|
|
void cg_reset(void) {
|
|
cg_vspPB = -1;
|
|
cg_fflg = 7;
|
|
cg_loadCountVar = NULL;
|
|
cg_brightness = 255;
|
|
loc_policy = loc_policy0 = OFFSET_NOMOVE;
|
|
memset(&loc_where, 0, sizeof(loc_where));
|
|
memset(&loc_where0, 0, sizeof(loc_where0));
|
|
}
|
|
|
|
/*
|
|
* Set cg display location
|
|
* x : display location x
|
|
* y : display location y
|
|
* policy: location offset policy
|
|
*/
|
|
void cg_set_display_location(int x, int y, CG_WHERETODISP policy) {
|
|
if (policy == OFFSET_ABSOLUTE_GC || policy == OFFSET_RELATIVE_GC) {
|
|
if (loc_policy == OFFSET_ABSOLUTE_JC ||
|
|
loc_policy == OFFSET_RELATIVE_JC) {
|
|
loc_policy0 = loc_policy;
|
|
loc_where0 = loc_where;
|
|
}
|
|
}
|
|
|
|
loc_policy = policy;
|
|
loc_where.x = x;
|
|
loc_where.y = y;
|
|
}
|
|
|
|
/*
|
|
* Load and display cg
|
|
* no : file no ( >= 0)
|
|
* flg: sprite color(!-1)
|
|
*/
|
|
void cg_load(int no, int flg) {
|
|
cgdata *cg;
|
|
MyPoint p;
|
|
int i, bank = cg_vspPB;
|
|
|
|
/* load and extract cg */
|
|
if (NULL == (cg = loader(no))) {
|
|
return;
|
|
}
|
|
|
|
/* need to set vsp bank or not */
|
|
if (GCMD_EXTRACTCG(cg_fflg) && cg->type == ALCG_VSP) {
|
|
bank = cg_vspPB == -1 ? cg->vsp_bank : cg_vspPB;
|
|
set_vspbank(cg->pic, bank << 4, cg->width, cg->height);
|
|
/* copy palettes 0 -> bank */
|
|
{
|
|
int i, i_dst = bank << 4;
|
|
for (i = 0; i < 16; i++) {
|
|
cg->pal->red[i + i_dst] = cg->pal->red[i];
|
|
cg->pal->green[i + i_dst] = cg->pal->green[i];
|
|
cg->pal->blue[i + i_dst] = cg->pal->blue[i];
|
|
}
|
|
}
|
|
if (flg != -1) {
|
|
flg |= (bank << 4);
|
|
}
|
|
}
|
|
|
|
/* copy palette to system */
|
|
if (GCMD_LOAD_PALETTE(cg_fflg)) {
|
|
switch(cg->type) {
|
|
case ALCG_VSP:
|
|
ags_setPalettes(cg->pal, 0, bank << 4, 16);
|
|
break;
|
|
case ALCG_PMS8:
|
|
if (cg->pms_bank & 1)
|
|
ags_setPalettes(cg->pal, 10, 10, 6);
|
|
if (cg->pms_bank & (1 << 15))
|
|
//ags_setPalettes(cg->pal, 240, 240, 15);
|
|
ags_setPalettes(cg->pal, 240, 240, 10);
|
|
for (i = 1; i < 15; i++) {
|
|
if (cg->pms_bank & (1 << i)) {
|
|
ags_setPalettes(cg->pal, i * 16, i * 16, 16);
|
|
}
|
|
}
|
|
break;
|
|
case ALCG_BMP8:
|
|
ags_setPalettes(cg->pal, 10, 10, 236);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* refrect palette change */
|
|
if (GCMD_SET_PALETTE(cg_fflg) && cg->depth == 8)
|
|
ags_setPaletteToSystem(0, 256);
|
|
|
|
/* draw cg */
|
|
if (GCMD_EXTRACTCG(cg_fflg)) {
|
|
/* set display offset */
|
|
p = set_display_loc(cg);
|
|
/* draw alpha pixel */
|
|
if (cg->alpha) {
|
|
ags_alpha_setPixel(p.x, p.y, cg->width, cg->height, cg->alpha);
|
|
}
|
|
/* draw cg pixel */
|
|
display_cg(cg, p.x, p.y, flg, flg != -1);
|
|
}
|
|
/* clear display offset */
|
|
clear_display_loc();
|
|
}
|
|
|
|
/*
|
|
* Load and display cg with alpha
|
|
* cgno : file no for cg ( >= 0 or -1(alpha only))
|
|
* shadowno: file no for alpha ( >= 0 )
|
|
*/
|
|
void cg_load_with_alpha(int cgno, int shadowno) {
|
|
cgdata *cg = NULL, *scg;
|
|
MyPoint p;
|
|
|
|
/* load pixel */
|
|
if (cgno >= 0) {
|
|
if (NULL == (cg = loader(cgno))) return;
|
|
if (cg->type != ALCG_PMS16) {
|
|
WARNING("commandGX cg_no != 16bitPMS");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* load alpha pixel */
|
|
if (NULL == (scg = loader(shadowno))) return;
|
|
if (scg->type != ALCG_PMS8) {
|
|
WARNING("commandGX shadow_no != 8bitPMS");
|
|
return;
|
|
}
|
|
|
|
/* set alpha pixel offset */
|
|
p = set_display_loc(scg);
|
|
/* draw alpha pixel */
|
|
ags_alpha_setPixel(p.x, p.y, scg->width, scg->height, scg->pic);
|
|
|
|
/* draw pixel */
|
|
if (cg) {
|
|
p = set_display_loc(cg);
|
|
display_cg(cg, p.x, p.y, -1, true);
|
|
}
|
|
|
|
/* clear display offset */
|
|
clear_display_loc();
|
|
}
|
|
|
|
static uint8_t* load_cg_from_file(char *fname_utf8, int *status, long *filesize) {
|
|
int size;
|
|
FILE *fp;
|
|
static uint8_t *tmp;
|
|
|
|
*status = 0;
|
|
|
|
if (NULL == (fp = fc_open(fname_utf8, 'r'))) {
|
|
*status = SAVE_LOADERR; return NULL;
|
|
}
|
|
|
|
fseek(fp, 0L, SEEK_END);
|
|
*filesize = ftell(fp);
|
|
if (*filesize == 0) {
|
|
*status = SAVE_LOADERR; return NULL;
|
|
}
|
|
|
|
tmp = (char *)malloc(*filesize);
|
|
if (tmp == NULL) {
|
|
WARNING("Out of memory");
|
|
*status = SAVE_LOADERR; return NULL;
|
|
}
|
|
fseek(fp, 0L, SEEK_SET);
|
|
size = fread(tmp, 1, *filesize,fp);
|
|
|
|
if (size != *filesize) {
|
|
*status = SAVE_LOADSHORTAGE;
|
|
} else {
|
|
*status = SAVE_LOADOK;
|
|
}
|
|
|
|
fclose(fp);
|
|
return tmp;
|
|
}
|
|
|
|
/*
|
|
* Load and display cg from file 'name' (not cached right now)
|
|
* name: file name to be read
|
|
* x : display location x
|
|
* y : display location y
|
|
* return: file read status
|
|
*/
|
|
int cg_load_with_filename(char *fname_utf8, int x, int y) {
|
|
int status, type;
|
|
long filesize;
|
|
uint8_t *data;
|
|
cgdata *cg = NULL;
|
|
MyPoint p;
|
|
|
|
data = load_cg_from_file(fname_utf8, &status, &filesize);
|
|
if (data == NULL) return status;
|
|
|
|
cg_set_display_location(x, y, OFFSET_ABSOLUTE_GC);
|
|
|
|
type = check_cgformat(data);
|
|
switch(type) {
|
|
case ALCG_BMP8:
|
|
cg = bmp256_extract(data);
|
|
break;
|
|
case ALCG_BMP24:
|
|
cg = bmp16m_extract(data);
|
|
break;
|
|
case ALCG_JPEG:
|
|
cg = jpeg_extract(data, filesize);
|
|
break;
|
|
default:
|
|
return status;
|
|
}
|
|
|
|
/* load palette if not extracted */
|
|
if (cg->depth == 8) {
|
|
if (GCMD_LOAD_PALETTE(cg_fflg))
|
|
ags_setPalettes(cg->pal, 10, 10, 236);
|
|
if (GCMD_SET_PALETTE(cg_fflg))
|
|
ags_setPaletteToSystem(0, 256);
|
|
}
|
|
|
|
/* draw cg */
|
|
if (GCMD_EXTRACTCG(cg_fflg)) {
|
|
/* set display offset */
|
|
p = set_display_loc(cg);
|
|
/* draw cg pixel */
|
|
display_cg(cg, p.x, p.y, -1, false);
|
|
/* clear display offset */
|
|
clear_display_loc();
|
|
}
|
|
|
|
cgdata_free(cg);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Get cg information
|
|
* no : file no for cg ( >= 0 )
|
|
* info: information to be retored
|
|
*/
|
|
void cg_get_info(int no, MyRectangle *info) {
|
|
cgdata *cg = loader(no);
|
|
MyPoint p;
|
|
|
|
if (cg == NULL) {
|
|
info->x = info->y = info->w = info->h = 0;
|
|
} else {
|
|
p = set_display_loc(cg);
|
|
info->x = p.x;
|
|
info->y = p.y;
|
|
info->w = cg->width;
|
|
info->h = cg->height;
|
|
}
|
|
}
|
|
|
|
void cg_clear_display_loc() {
|
|
clear_display_loc();
|
|
}
|