/* 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); }