/*
Copyright (C) 2015-2018 Night Dive Studios, LLC.
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 .
*/
#include "cit2d.h"
#include "gr2ss.h"
#include "frtypes.h"
#include "frintern.h"
#include "frprotox.h"
#include "gamescr.h"
#ifdef STEREO_SUPPORT
#include
extern uchar inp6d_stereo_active;
#define S_DELTA 5
#endif
#ifdef SVGA_SUPPORT
uchar gr2ss_override = OVERRIDE_NONE;
char convert_type = 0;
char convert_use_mode = 0;
char mode_count[MAX_CONVERT_TYPES];
fix convert_x[MAX_CONVERT_TYPES][MAX_USE_MODES];
fix convert_y[MAX_CONVERT_TYPES][MAX_USE_MODES];
fix inv_convert_x[MAX_CONVERT_TYPES][MAX_USE_MODES];
fix inv_convert_y[MAX_CONVERT_TYPES][MAX_USE_MODES];
#define SVGA_CONV_NONE 0
#define SVGA_CONV_NORMAL 1
#define SVGA_CONV_SCREEN 2
// Internal prototypes
uchar perform_svga_conversion(uchar mask) {
extern uchar full_game_3d;
if (gr2ss_override & OVERRIDE_FAIL)
return (SVGA_CONV_NONE);
// for now - if ((convert_use_mode == 0) && (!inp6d_stereo_active))
if (convert_use_mode == 0)
return (SVGA_CONV_NONE);
if (_fr->draw_canvas.bm.bits == grd_canvas->bm.bits)
return (SVGA_CONV_SCREEN);
if (grd_canvas->bm.bits == grd_screen_canvas->bm.bits)
return (SVGA_CONV_SCREEN);
if (gr2ss_override & mask)
return (SVGA_CONV_NORMAL);
if (convert_use_mode == 3) // KLC - the normal mode for Mac Shock.
return (SVGA_CONV_SCREEN);
return (SVGA_CONV_NONE);
}
// Conversion functions from "abstract" shock 2d functions
// to the actual 2d functions, with appropriate compensations
// for screen mode coordinates and aspect ratios.
// Note, x and y already converted here!
void ss_scale_string(char *s, short x, short y) {
// needs to scale still!
// know about different fonts instead? That would be better...
grs_font *ttfont = (grs_font *)ResLock(RES_tinyTechFont);
grs_font *mlfont = (grs_font *)ResLock(RES_mediumLEDFont);
grs_font *f = gr_get_font();
int c = gr_get_fcolor();
Id use_font = ID_NULL;
#ifdef STEREO_SUPPORT
uchar rv = perform_svga_conversion(OVERRIDE_SCALE);
#endif
if (convert_use_mode == 0) {
gr_string(s, x, y);
return;
}
if ((f == ttfont) || (f == mlfont)) {
switch (convert_use_mode) {
case 1:
if (f == ttfont)
use_font = RES_tallTinyTechFont;
break;
case 2:
case 3:
if (f == ttfont)
use_font = RES_doubleTinyTechFont;
else if (f == mlfont)
use_font = RES_doubleMediumLEDFont;
break;
case 4:
if (f == ttfont)
use_font = RES_megaTinyTechFont;
else if (f == mlfont)
use_font = RES_megaMediumLEDFont;
break;
}
#ifdef STEREO_SUPPORT
if ((rv == SVGA_CONV_SCREEN) && inp6d_stereo_active) {
if (use_font == ID_NULL) {
short w, h;
gr_string_size(s, (short *)&w, (short *)&h);
gr_push_canvas(i6d_ss->cf_left);
gr_set_font(f);
gr_set_fcolor(c);
gr_scale_string(s, x + S_DELTA, y, SCONV_X(w) + S_DELTA, SCONV_Y(h));
gr_pop_canvas();
gr_push_canvas(i6d_ss->cf_right);
gr_set_font(f);
gr_set_fcolor(c);
gr_scale_string(s, x - S_DELTA, y, SCONV_X(w) - S_DELTA, SCONV_Y(h));
} else {
gr_push_canvas(i6d_ss->cf_left);
gr_set_font((grs_font *)ResLock(use_font));
gr_set_fcolor(c);
gr_string(s, x + S_DELTA, y);
gr_pop_canvas();
gr_push_canvas(i6d_ss->cf_right);
gr_set_font((grs_font *)ResLock(use_font));
gr_set_fcolor(c);
gr_string(s, x - S_DELTA, y);
}
gr_pop_canvas();
} else {
#endif
if (use_font == ID_NULL) {
short w, h;
gr_string_size(s, (short *)&w, (short *)&h);
gr_scale_string(s, x, y, SCONV_X(w), SCONV_Y(h));
} else {
gr_set_font((grs_font *)ResLock(use_font));
gr_string(s, x, y);
}
#ifdef STEREO_SUPPORT
}
#endif
if (use_font != ID_NULL)
ResUnlock(use_font);
gr_set_font(ttfont);
ResUnlock(RES_tinyTechFont);
ResUnlock(RES_mediumLEDFont);
} else {
// Attempt to scale it
short w, h;
gr_string_size(s, (short *)&w, (short *)&h);
gr_scale_string(s, x, y, SCONV_X(w), SCONV_Y(h));
}
}
void ss_string(char *s, short x, short y) {
uchar rv;
if ((rv = perform_svga_conversion(OVERRIDE_SCALE))) {
#ifdef STEREO_SUPPORT
if ((rv == SVGA_CONV_SCREEN) && (inp6d_stereo_active)) {
gr_push_canvas(i6d_ss->cf_left);
if (convert_use_mode)
ss_scale_string(s, SCONV_X(x) + S_DELTA, SCONV_Y(y));
else
ss_scale_string(s, x + S_DELTA, y);
gr_set_canvas(i6d_ss->cf_right);
if (convert_use_mode)
ss_scale_string(s, SCONV_X(x) - S_DELTA, SCONV_Y(y));
else
ss_scale_string(s, x - S_DELTA, y);
gr_pop_canvas();
} else
#endif
ss_scale_string(s, SCONV_X(x), SCONV_Y(y));
} else {
gr_string(s, x, y);
}
}
void ss_bitmap(grs_bitmap *bmp, short x, short y) {
uchar rv;
if ((rv = perform_svga_conversion(OVERRIDE_SCALE))) {
#ifdef STEREO_SUPPORT
if ((rv == SVGA_CONV_SCREEN) && (inp6d_stereo_active)) {
gr_push_canvas(i6d_ss->cf_left);
if (convert_use_mode)
gr_scale_bitmap(bmp, SCONV_X(x) + S_DELTA, SCONV_Y(y), SCONV_X(bmp->w) + S_DELTA, SCONV_Y(bmp->h));
else
gr_bitmap(bmp, x + S_DELTA, y);
gr_set_canvas(i6d_ss->cf_right);
if (convert_use_mode)
gr_scale_bitmap(bmp, SCONV_X(x) - S_DELTA, SCONV_Y(y), SCONV_X(bmp->w) - S_DELTA, SCONV_Y(bmp->h));
else
gr_bitmap(bmp, x - S_DELTA, y);
gr_pop_canvas();
} else
#endif
gr_scale_bitmap(bmp, SCONV_X(x), SCONV_Y(y), SCONV_X(bmp->w), SCONV_Y(bmp->h));
// Warning(("scaling %d x %d to %d x %d\n",bmp->w,bmp->h,SCONV_X(bmp->w),SCONV_Y(bmp->h)));
} else
gr_bitmap(bmp, x, y);
}
void ss_ubitmap(grs_bitmap *bmp, short x, short y) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_scale_ubitmap(bmp, SCONV_X(x), SCONV_Y(y), SCONV_X(bmp->w), SCONV_Y(bmp->h));
else
gr_ubitmap(bmp, x, y);
}
void ss_noscale_bitmap(grs_bitmap *bmp, short x, short y) {
uchar rv;
if ((rv = perform_svga_conversion(OVERRIDE_SCALE))) // ?
#ifdef STEREO_SUPPORT
if ((rv == SVGA_CONV_SCREEN) && (inp6d_stereo_active)) {
gr_push_canvas(i6d_ss->cf_left);
if (convert_use_mode)
gr_bitmap(bmp, SCONV_X(x) + S_DELTA, SCONV_Y(y));
else
gr_bitmap(bmp, x + S_DELTA, y);
gr_set_canvas(i6d_ss->cf_right);
if (convert_use_mode)
gr_bitmap(bmp, SCONV_X(x) - S_DELTA, SCONV_Y(y));
else
gr_bitmap(bmp, x - S_DELTA, y);
gr_pop_canvas();
} else
#endif
gr_bitmap(bmp, SCONV_X(x), SCONV_Y(y));
else
gr_bitmap(bmp, x, y);
}
void ss_scale_bitmap(grs_bitmap *bmp, short x, short y, short w, short h) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_scale_bitmap(bmp, SCONV_X(x), SCONV_Y(y), SCONV_X(w), SCONV_Y(h));
else
gr_scale_bitmap(bmp, x, y, w, h);
}
void ss_rect(short x1, short y1, short x2, short y2) {
uchar rv;
if ((rv = perform_svga_conversion(OVERRIDE_SCALE))) {
#ifdef STEREO_SUPPORT
if ((rv == SVGA_CONV_SCREEN) && (inp6d_stereo_active)) {
int c = gr_get_fcolor();
gr_push_canvas(i6d_ss->cf_left);
gr_set_fcolor(c);
if (convert_use_mode)
gr_rect(SCONV_X(x1) + S_DELTA, SCONV_Y(y1), SCONV_X(x2) + S_DELTA, SCONV_Y(y2));
else
gr_rect(x1 + S_DELTA, y1, x2 + S_DELTA, y2);
gr_set_canvas(i6d_ss->cf_right);
gr_set_fcolor(c);
if (convert_use_mode)
gr_rect(SCONV_X(x1) - S_DELTA, SCONV_Y(y1), SCONV_X(x2) - S_DELTA, SCONV_Y(y2));
else
gr_rect(x1 - S_DELTA, y1, x2 - S_DELTA, y2);
gr_pop_canvas();
} else
#endif
gr_rect(SCONV_X(x1), SCONV_Y(y1), SCONV_X(x2), SCONV_Y(y2));
} else {
gr_rect(x1, y1, x2, y2);
}
}
void ss_box(short x1, short y1, short x2, short y2) {
uchar rv;
if ((rv = perform_svga_conversion(OVERRIDE_SCALE))) {
#ifdef STEREO_SUPPORT
if ((rv == SVGA_CONV_SCREEN) && (inp6d_stereo_active)) {
int c = gr_get_fcolor();
gr_push_canvas(i6d_ss->cf_left);
gr_set_fcolor(c);
if (convert_use_mode)
gr_box(SCONV_X(x1) + S_DELTA, SCONV_Y(y1), SCONV_X(x2) + S_DELTA, SCONV_Y(y2));
else
gr_box(x1 + S_DELTA, y1, x2 + S_DELTA, y2);
gr_set_canvas(i6d_ss->cf_right);
gr_set_fcolor(c);
if (convert_use_mode)
gr_box(SCONV_X(x1) - S_DELTA, SCONV_Y(y1), SCONV_X(x2) - S_DELTA, SCONV_Y(y2));
else
gr_box(x1 - S_DELTA, y1, x2 - S_DELTA, y2);
gr_pop_canvas();
} else
#endif
gr_box(RSCONV_X(x1), RSCONV_Y(y1), RSCONV_X(x2), RSCONV_Y(y2));
} else {
gr_box(x1, y1, x2, y2);
}
}
void ss_safe_set_cliprect(short x1, short y1, short x2, short y2) {
if (perform_svga_conversion(OVERRIDE_CLIP)) {
// Warning(("setting rect (%d, %d) (%d,%d)!\n",SCONV_X(x1),SCONV_Y(y1),SCONV_X(x2),SCONV_Y(y2)));
safe_set_cliprect(SCONV_X(x1), SCONV_Y(y1), SCONV_X(x2), SCONV_Y(y2));
} else
safe_set_cliprect(x1, y1, x2, y2);
}
void ss_cset_cliprect(grs_canvas *pcanv, short x, short y, short w, short h) {
if (perform_svga_conversion(OVERRIDE_CLIP)) {
// Warning(("cset to %d,%d %d, %d!\n",SCONV_X(x), SCONV_Y(y), SCONV_X(w), SCONV_Y(h)));
gr_cset_cliprect(pcanv, SCONV_X(x), SCONV_Y(y), SCONV_X(w), SCONV_Y(h));
} else
gr_cset_cliprect(pcanv, x, y, w, h);
}
void ss_int_line(short x1, short y1, short x2, short y2) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_int_line(SCONV_X(x1), SCONV_Y(y1), SCONV_X(x2), SCONV_Y(y2));
else
gr_int_line(x1, y1, x2, y2);
}
void ss_thick_int_line(short x1, short y1, short x2, short y2) {
if (perform_svga_conversion(OVERRIDE_SCALE)) {
short min_y, max_y, use_y, min_x, max_x, use_x;
min_y = SCONV_Y(y1);
max_y = SCONV_Y(y1 + 1);
min_x = SCONV_X(x1);
max_x = SCONV_X(x1 + 1);
for (use_y = min_y; use_y < max_y; use_y++)
gr_int_line(SCONV_X(x1), use_y, SCONV_X(x2), SCONV_Y(y2) + use_y - min_y);
for (use_x = min_x; use_x < max_x; use_x++)
gr_int_line(use_x, SCONV_Y(y1), SCONV_X(x2) + use_x - min_x, SCONV_Y(y2));
} else
gr_int_line(x1, y1, x2, y2);
}
void ss_int_disk(short x1, short y1, short diam) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_int_disk(SCONV_X(x1), SCONV_Y(y1), SCONV_X(diam) >> 1);
// Hm, should we convert rad?
// Yes, but sadly it's hosed in 320x400 mode, where
// we need to draw an ellipse. This stuff really
// needs to be in the 2D.
else
gr_int_disk(x1, y1, diam >> 1);
}
void ss_vline(short x1, short y1, short y2) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_vline(SCONV_X(x1), SCONV_Y(y1), SCONV_Y(y2));
else
gr_vline(x1, y1, y2);
}
void ss_hline(short x1, short y1, short x2) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_hline(SCONV_X(x1), SCONV_Y(y1), SCONV_X(x2));
else
gr_hline(x1, y1, x2);
}
void ss_fix_line(fix x1, fix y1, fix x2, fix y2) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_fix_line(FIXCONV_X(x1), FIXCONV_Y(y1), FIXCONV_X(x2), FIXCONV_Y(y2));
else
gr_fix_line(x1, y1, x2, y2);
}
void ss_thick_fix_line(fix x1, fix y1, fix x2, fix y2) {
if (perform_svga_conversion(OVERRIDE_SCALE)) {
fix min_y, max_y, use_y, min_x, max_x, use_x;
min_y = FIXCONV_Y(y1);
max_y = FIXCONV_Y(y1 + FIX_UNIT);
min_x = FIXCONV_X(x1);
max_x = FIXCONV_X(x1 + FIX_UNIT);
for (use_y = min_y; use_y < max_y; use_y = use_y + FIX_UNIT)
gr_fix_line(FIXCONV_X(x1), use_y, FIXCONV_X(x2), FIXCONV_Y(y2) + use_y - min_y);
for (use_x = min_x; use_x < max_x; use_x = use_x + FIX_UNIT)
gr_fix_line(use_x, FIXCONV_Y(y1), FIXCONV_X(x2) + use_x - min_x, FIXCONV_Y(y2));
} else
gr_fix_line(x1, y1, x2, y2);
}
void ss_get_bitmap(grs_bitmap *bmp, short x, short y) {
if (perform_svga_conversion(OVERRIDE_GET_BM))
gr_get_bitmap(bmp, SCONV_X(x), SCONV_Y(y));
else
gr_get_bitmap(bmp, x, y);
}
void ss_set_pixel(long color, short x, short y) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_set_pixel(color, SCONV_X(x), SCONV_Y(y));
else
gr_set_pixel(color, x, y);
}
void ss_set_thick_pixel(long color, short x, short y) {
if (perform_svga_conversion(OVERRIDE_SCALE)) {
// gr_set_pixel(color, SCONV_X(x), SCONV_Y(y));
gr_set_fcolor(color);
gr_box(SCONV_X(x), SCONV_Y(y), SCONV_X(x + 1) - 1, SCONV_Y(y + 1) - 1);
} else
gr_set_pixel(color, x, y);
}
void ss_clut_ubitmap(grs_bitmap *bmp, short x, short y, uchar *cl) {
if (perform_svga_conversion(OVERRIDE_SCALE))
gr_clut_scale_ubitmap(bmp, SCONV_X(x), SCONV_Y(y), SCONV_X(bmp->w), SCONV_Y(bmp->h), cl);
else
gr_clut_ubitmap(bmp, x, y, cl);
}
// Registration!
// Note that the zeroth element of the conversion arrays
// are used to store the base size, since perform_svga_conversion
// already filters out calls with use_mode of 0.
void gr2ss_register_init(char ctype, short init_x, short init_y) {
convert_x[ctype][0] = fix_make(init_x, 0);
convert_y[ctype][0] = fix_make(init_y, 0);
}
#define WACKY_FIX_COMPENSATION
void gr2ss_register_mode(char conv_mode, short nx, short ny) {
char m;
mode_count[conv_mode]++;
m = mode_count[conv_mode];
convert_x[conv_mode][m] = fix_div(fix_make(nx, 0), convert_x[conv_mode][0]);
convert_y[conv_mode][m] = fix_div(fix_make(ny, 0), convert_y[conv_mode][0]);
inv_convert_x[conv_mode][m] = fix_div(convert_x[conv_mode][0], fix_make(nx, 0));
inv_convert_y[conv_mode][m] = fix_div(convert_y[conv_mode][0], fix_make(ny, 0));
#ifdef WACKY_FIX_COMPENSATION
// wacky fix point compensation!
if (convert_x[conv_mode][m] & 0xF)
convert_x[conv_mode][m]++;
if (convert_y[conv_mode][m] & 0xF)
convert_y[conv_mode][m]++;
if (inv_convert_x[conv_mode][m] & 0xF)
inv_convert_x[conv_mode][m]++;
if (inv_convert_y[conv_mode][m] & 0xF)
inv_convert_y[conv_mode][m]++;
#endif
}
void ss_recompute_zoom(frc *which_frc, short oldm) {
fr_mod_cams(which_frc, FR_NOCAM, fix_div(convert_x[convert_type][convert_use_mode], convert_x[convert_type][oldm]));
}
void ss_point_convert(short *px, short *py, uchar down) {
#ifdef SVGA_SUPPORT
if (convert_use_mode != 0) {
short ox, oy;
ox = *px;
oy = *py;
if (down) {
*px = INV_SCONV_X(*px);
*py = INV_SCONV_Y(*py);
} else {
*px = SCONV_X(*px);
*py = SCONV_Y(*py);
}
// Warning(("%d >> %d %d --> %d %d\n",down,ox,oy,*px,*py));
}
#endif
}
short ss_curr_mode_width(void) { return (SCONV_X(convert_x[convert_type][0])); }
short ss_curr_mode_height(void) { return (SCONV_Y(convert_y[convert_type][0])); }
// Basically, if you are in the secret hack mode 5
// then MODE_SCONV_X will act as if you are in mode M
// otherwise it behaves like SCONV_{X,Y}
short MODE_SCONV_X(short cval, short m) {
if ((!m) || (convert_use_mode != 5))
return (SCONV_X(cval));
return (fast_fix_mul_int(fix_make(cval, 0), convert_x[convert_type][m]));
}
short MODE_SCONV_Y(short cval, short m) {
if ((!m) || (convert_use_mode != 5))
return (SCONV_Y(cval));
return (fast_fix_mul_int(fix_make(cval, 0), convert_y[convert_type][m]));
}
// This allows us to override the real mode with some
// fake pretender mode, but only if we are in the magic hack mode 5
short hack_mode_on;
void ss_set_hack_mode(short new_m, short *tval) {
if ((convert_use_mode != 5) && (!hack_mode_on))
return;
if (new_m) {
*tval = convert_use_mode;
convert_use_mode = new_m;
hack_mode_on++;
} else {
convert_use_mode = *tval;
hack_mode_on--;
}
}
#endif
void ss_mouse_convert(short *px, short *py, uchar down) {
if (convert_use_mode != 0) {
#ifdef STEREO_SUPPORT
if (convert_use_mode == 5) {
switch (i6d_device) {
case I6D_CTM:
return;
break;
case I6D_VFX1:
if (down)
*py = fix_int(fix_mul_div(fix_make(*py, 0), fix_make(200, 0), fix_make(480, 0)));
else
*py = fix_int(fix_mul_div(fix_make(*py, 0), fix_make(480, 0), fix_make(200, 0)));
return;
}
}
#endif
if (down) {
*px = INV_SCONV_X(*px);
*py = INV_SCONV_Y(*py);
} else {
*px = SCONV_X(*px);
*py = SCONV_Y(*py);
}
}
}
void ss_mouse_convert_round(short *px, short *py, uchar down) {
short ox, oy;
if (convert_use_mode != 0) {
#ifdef STEREO_SUPPORT
if (convert_use_mode == 5) {
ss_mouse_convert(px, py, down);
return;
}
#endif
ox = *px;
oy = *py;
if (down) {
*px = fix_int(INV_FIXCONV_X(fix_make(*px, 0x8000)));
*py = fix_int(INV_FIXCONV_Y(fix_make(*py, 0x8000)));
} else {
*px = fix_int(FIXCONV_X(fix_make(*px, 0x8000)));
*py = fix_int(FIXCONV_Y(fix_make(*py, 0x8000)));
}
}
}
void mouse_unconstrain(void) {
/* for now
#ifdef SVGA_SUPPORT
if (convert_use_mode == 5)
{
switch (i6d_device)
{
case I6D_CTM:
mouse_constrain_xy(0,0,grd_cap->w-1,grd_cap->h-1);
break;
case I6D_VFX1:
mouse_constrain_xy(0,0,i6d_ss->scr_w >> 1, i6d_ss->scr_h);
break;
}
}
else
#endif */
mouse_constrain_xy(0, 0, grd_cap->w - 1, grd_cap->h - 1);
}