yigithanyigit 15602e77c7 CHAMBERS: Refactor code for HGA compatibility
Refactor the existing CGA rendering code to make it compatible with HGA rendering. The main changes include the introduction of engine variables and a move away from macros.
2024-04-25 00:42:36 +02:00

330 lines
7.1 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "chamber/chamber.h"
#include "chamber/common.h"
#include "chamber/resdata.h"
#include "chamber/cga.h"
#include "chamber/room.h"
#include "chamber/sound.h"
namespace Chamber {
byte *anima_end_ofs;
byte last_anim_y = 0;
byte last_anim_x = 0;
byte anim_shift_y = 0;
byte anim_shift_x = 0;
byte last_anim_height;
byte last_anim_width;
byte anim_cycle;
byte anim_flags;
byte anim_use_dot_effect;
uint16 anim_draw_delay;
byte dot_effect_step;
uint16 dot_effect_delay;
extern uint16 cpu_speed_delay;
extern void loadLutinSprite(uint16 lutidx);
void getScratchBuffer(byte mode) {
byte *buffer = scratch_mem2;
uint16 offs = 0;
if (mode & 0x80)
offs += 3200;
if (mode & 0x40)
offs += 1600;
lutin_mem = buffer + offs;
}
void animLoadSprite(byte **panim) {
byte mode;
byte index;
mode = *((*panim)++);
index = *((*panim)++);
getScratchBuffer(mode);
loadLutinSprite(index);
}
void clipSprite(byte *x, byte *y, byte *sprw, byte *sprh, byte **sprite, int8 dx, int8 dy) {
if (anim_flags == 7)
return;
if (anim_flags & 4) {
if (anim_cycle == 0)
return;
if (anim_flags & 2) {
*sprh = anim_cycle;
if (anim_cycle >= dy)
anim_cycle -= dy;
else
anim_cycle = 0;
} else if (anim_flags & 1) {
*sprw = anim_cycle;
anim_cycle--;
} else {
*x -= dx;
*sprite += (*sprw - anim_cycle) * 2;
*sprw = anim_cycle;
anim_cycle--;
}
} else if (anim_flags & 2) {
if (*sprw == anim_cycle) {
anim_cycle = 0;
} else if (anim_flags & 1) {
*sprw = anim_cycle;
anim_cycle++;
} else {
*x -= dx;
*sprite += (*sprw - anim_cycle) * 2;
*sprw = anim_cycle;
anim_cycle++;
}
}
}
void copyScreenBlockWithDotEffect(byte *source, byte x, byte y, byte width, byte height, byte *target) {
uint16 offs;
uint16 xx = x * 4;
uint16 ww = width * 4;
uint16 cur_image_end = ww * height;
for (offs = 0; offs != cur_image_end;) {
byte mask = 0xC0 >> (((xx + offs % ww) % 4) * 2);
uint16 ofs = cga_CalcXY(xx + offs % ww, y + offs / ww);
target[ofs] = (target[ofs] & ~mask) | (source[ofs] & mask);
if (dot_effect_delay / 4 != 0) {
uint16 i;
for (i = 0; i < dot_effect_delay / 4; i++) ; /*TODO: weak delay*/
}
offs += dot_effect_step;
if (offs > cur_image_end)
offs -= cur_image_end;
}
}
void animDrawSprite(byte x, byte y, byte sprw, byte sprh, byte *pixels, uint16 pitch) {
uint16 delay;
byte ex, ey, updx, updy, updw, updh;
uint16 ofs = CalcXY_p(x, y);
cga_BackupImage(backbuffer, ofs, sprw, sprh, sprit_load_buffer);
cga_BlitSprite(pixels, pitch, sprw, sprh, backbuffer, ofs);
ex = x + sprw;
ey = y + sprh;
if (last_anim_height != 0) {
if (last_anim_x + last_anim_width > ex)
ex = last_anim_x + last_anim_width;
if (last_anim_y + last_anim_height > ey)
ey = last_anim_y + last_anim_height;
updx = (x > last_anim_x) ? last_anim_x : x;
updy = (y > last_anim_y) ? last_anim_y : y;
} else {
updx = x;
updy = y;
}
updw = ex - updx;
updh = ey - updy;
ofs = CalcXY_p(updx, updy);
/*TODO looks like here was some code before*/
for (delay = 0; delay < anim_draw_delay; delay++) {
g_system->delayMillis(1000 / 16 / 25);
}
waitVBlank();
if (anim_use_dot_effect)
copyScreenBlockWithDotEffect(backbuffer, updx, updy, updw, updh, frontbuffer);
else {
cga_CopyScreenBlock(backbuffer, updw, updh, frontbuffer, ofs);
}
cga_RestoreImage(sprit_load_buffer, backbuffer);
last_anim_x = x;
last_anim_y = y;
last_anim_width = sprw;
last_anim_height = sprh;
anim_shift_x = anim_shift_y = 0;
}
void animUndrawSprite(void) {
cga_CopyScreenBlock(backbuffer, last_anim_width, last_anim_height, CGA_SCREENBUFFER, CalcXY_p(last_anim_x, last_anim_y));
last_anim_height = 0;
}
void playAnimCore(byte **panim) {
byte mode;
uint16 count, count2;
byte *pframe;
mode = *((*panim)++);
anim_flags = mode & 7;
count = mode >> 3;
while (count--) {
pframe = *panim;
mode = *pframe++;
anim_draw_delay = ((mode & ~7) >> 3) << 1;
dot_effect_step = (mode & ~7) >> 3;
dot_effect_delay = 500;
count2 = mode & 7;
while (count2--) {
byte *sprite;
byte sprw, sprh;
byte x, y;
int8 dx, dy;
uint16 pitch;
mode = *pframe++;
getScratchBuffer(mode);
dy = mode & 7;
dx = (mode >> 3) & 7;
dx = (dx & 1) ? -(dx & ~1) : dx;
dx /= 2;
dy = (dy & 1) ? -(dy & ~1) : dy;
x = last_anim_x + dx + anim_shift_x;
y = last_anim_y + dy + anim_shift_y;
sprite = lutin_mem;
sprw = *sprite++;
sprh = *sprite++;
pitch = sprw * 2;
clipSprite(&x, &y, &sprw, &sprh, &sprite, dx, dy);
animDrawSprite(x, y, sprw, sprh, sprite, pitch);
if (anim_flags & 4) {
if (anim_cycle == 0) {
animUndrawSprite();
goto end;
}
} else if (anim_flags & 2) {
if (anim_cycle == 0) {
goto end;
}
}
}
}
end:
;
mode = *((*panim)++);
*panim += mode & 7;
}
void anim1(byte **panim) {
anim_cycle = 0xFF;
anim_use_dot_effect = 0;
playAnimCore(panim);
}
void anim2(byte **panim) {
anim_cycle = 1;
anim_use_dot_effect = 0;
playAnimCore(panim);
}
void anim3(byte **panim) {
anim_cycle = 1;
anim_use_dot_effect = 0;
playAnimCore(panim);
}
void anim4(byte **panim) {
anim_cycle = last_anim_width - 1;
anim_use_dot_effect = 0;
playAnimCore(panim);
}
void anim5(byte **panim) {
anim_cycle = last_anim_width - 1;
anim_use_dot_effect = 0;
playAnimCore(panim);
}
void anim6(byte **panim) {
anim_cycle = last_anim_height;
anim_use_dot_effect = 0;
playAnimCore(panim);
}
void anim7(byte **panim) {
anim_cycle = 0xFF;
anim_use_dot_effect = 1;
playAnimCore(panim);
}
typedef void (*animhandler_t)(byte **panim);
animhandler_t anim_handlers[] = {
animLoadSprite,
anim1,
anim2,
anim3,
anim4,
anim5,
anim6,
anim7
};
void playAnim(byte index, byte x, byte y) {
byte sound;
byte *panim;
last_anim_width = 0;
last_anim_height = 0;
last_anim_x = x;
last_anim_y = y;
panim = seekToEntry(anima_data, index - 1, &anima_end_ofs);
while (panim != anima_end_ofs) {
byte mode = *panim;
switch (mode) {
case 0xFE: /*set shift*/
panim++;
anim_shift_x = *panim++;
anim_shift_y = *panim++;
break;
case 0xFD: /*play sfx*/
panim++;
sound = *panim++;
panim++; /*unused*/
playSound(sound);
break;
case 0xFC: /*nothing*/
panim++;
break;
default:
anim_handlers[mode & 7](&panim);
}
}
}
} // End of namespace Chamber