picodrive/platform/uiq2/vid.cpp
notaz cc68a136aa initial import
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@2 be3aeb3a-fb24-0410-a615-afba39da0efa
2006-12-19 20:53:21 +00:00

1017 lines
26 KiB
C++

// EmuScan routines for Pico, also simple text and shape drawing routines.
// (c) Copyright 2006, notaz
// All Rights Reserved
#include "vid.h"
#include "ClientServer.h"
#include "SimpleServer.h"
#include "pico\picoInt.h"
#include "blit.h"
#include "debug.h"
// global stuff
extern TPicoConfig currentConfig;
extern TPicoKeyConfigEntry *keyConfig;
extern TPicoAreaConfigEntry areaConfig[];
extern const char * actionNames[];
// main framebuffer
static void *screenbuff = 0; // pointer to real device video memory
//static
unsigned short *framebuff = 0; // temporary buffer in sega native BGR format
const int framebuffsize = (8+320)*(8+208+8)*2; // actual framebuffer size (in bytes+to support new rendering mode)
static int framebuff_offs = 0; // where to start copying (in pixels)
static int framebuff_len = 0; // how much of the framebuffer actually needs to be copied (in pixels)
static int fc_lines, fc_inc; // lines, inc for "0 fit2" mode
// drawer function pointers
void (*drawTextFps)(const char *text) = 0;
void (*drawTextNotice)(const char *text) = 0;
// blitter
void (*vidBlit)(int full) = 0;
void (*vidBlitKeyCfg)(int full) = 0;
// stuff for rendermode2
static unsigned short cram_high[0x40];
static unsigned short dt_dmask=0x0333;
unsigned short color_redM2 = 0x022F;
// colors
const unsigned short color_red = 0x022F;
const unsigned short color_red_dim = 0x0004;
const unsigned short color_green = 0x01F1;
const unsigned short color_blue = 0x0F11;
const unsigned short color_grey = 0x0222;
// other
int txtheight_fit = 138;
// bitmasks
static const unsigned long mask_numbers[] = {
0x12244800, // 47 2F /
0x69999600, // 48 30 0
0x26222200, // 49 31 1
0x69168F00, // 50 32 2
0x69219600, // 51 33 3
0x266AF200, // 52 34 4
0xF8E11E00, // 53 35 5
0x68E99600, // 54 36 6
0x71222200, // 55 37 7
0x69699600, // 56 38 8
0x69719600, // 57 39 9
0x04004000, // 58 3A :
0x04004400, // 59 3B ;
0x01242100, // 60 3C <
0x00707000, // 61 3D =
0x04212400, // 62 3E >
0x69240400, // 63 3F ?
0x00000000, // 64 40 @ [used instead of space for now]
0x22579900, // 65 41 A
0xE9E99E00, // 66 42 B
0x69889600, // 67 43 C
0xE9999E00, // 68 44 D
0xF8E88F00, // 69 45 E
0xF8E88800, // 70 46 F
0x698B9700, // 71 47 G
0x99F99900, // 72 48 H
0x44444400, // 73 49 I
0x11119600, // 74 4A J
0x9ACCA900, // 75 4B K
0x88888F00, // 76 4C L
0x9F999900, // 77 4D M
0x9DDBB900, // 78 4E N
0x69999600, // 79 4F O
0xE99E8800, // 80 50 P
0x6999A500, // 81 51 Q
0xE99E9900, // 82 52 R
0x69429600, // 83 53 S
0x72222200, // 84 54 T
0x99999600, // 85 55 U
0x55552200, // 86 56 V
0x9999F900, // 87 57 W
0x55225500, // 88 58 X
0x55222200, // 89 59 Y
0xF1248F00, // 90 5A Z
};
////////////////////////////////
// Cram functions
inline int EmuCramNull(int cram)
{
User::Panic(_L("Cram called!!"), 0);
return cram;
}
////////////////////////////////
// PicoScan functions in "center" mode
int EmuScanCenter0(unsigned int num, unsigned short *sdata)
{
//unsigned short *vidmem=framebuff;
//unsigned short *sp, *sto;
//sp=sdata+56; sto=sdata+264; vidmem += num*208;
//do { *vidmem++ = *sp++; } while(sp < sto);
memcpy(framebuff + num*208, sdata+56, 208*2); // memcpy gives ~1 fps (~2 with optimized memcpy)
return 0;
}
int EmuScanCenter90(unsigned int num, unsigned short *sdata)
{
// ignore top and bottom lines
if(num < 8) return 7-num; // skip first 8 lines
if(num > 215) return 223+8-num; // this should not happen, just in case
num -= 8;
if(!num) {
if(Pico.video.reg[12]&1) { // copy less in 32-col mode
framebuff_offs= 0;
framebuff_len = 208*320;
} else {
framebuff_offs= 208*32;
framebuff_len = 208*256;
}
}
unsigned short *vidmem=framebuff;
vidmem += 207-num; // adjust x
// do less copy in 32-column mode
unsigned short *sp, *sto;
int pixels;
if(!(Pico.video.reg[12]&1))
{ sp=sdata+32; sto=sdata+288; pixels = 288; vidmem += 32*208; }
else { sp=sdata; sto=sdata+320; pixels = 320; }
do { *vidmem = *sp++; vidmem+=208; } while(sp < sto);
if(num == 207) return 16; // skip bottom of this frame and top of next
return 0;
}
int EmuScanCenter180(unsigned int num, unsigned short *sdata)
{
unsigned short *vidmem=framebuff;
unsigned short *sp, *sto;
sp=sdata+56; sto=sdata+264; vidmem += (224-num)*208;
do { *(--vidmem) = *sp++; } while(sp < sto); // reversed
return 0;
}
int EmuScanCenter270(unsigned int num, unsigned short *sdata)
{
// ignore top and bottom lines
if(num < 8) return 7-num; // skip first 8 lines
if(num > 215) return 223-num+8;
num -= 8;
if(num > 207) return 0;
if(!num) {
if(Pico.video.reg[12]&1) {
framebuff_offs= 0;
framebuff_len = 208*320;
} else {
framebuff_offs= 208*32;
framebuff_len = 208*256;
}
}
unsigned short *vidmem=framebuff+320*208;
vidmem -= 208-num; // adjust x
// do less copy in 32-column mode
unsigned short *sp, *sto;
if(!(Pico.video.reg[12]&1))
{ sp=sdata+32; sto=sdata+288; vidmem -= 32*208; }
else { sp=sdata; sto=sdata+320; }
do { *vidmem = *sp++; vidmem-=208; } while(sp < sto);
if(num == 207) return 16; // skip bottom of this frame and top of next
return 0;
}
////////////////////////////////
// PicoScan functions in "fit" mode
static int EmuScanFit0(unsigned int num, unsigned short *sdata)
{
// 0.65, 145 lines in normal mode; 0.8125, 182 lines in 32-column mode
// draw this line? (ARM4s don't support division, so do some tricks here)
static int u = 0, num2 = 0;
if(!num) {
u = num2 = 0;
if(currentConfig.iScreenMode == TPicoConfig::PMFit) {
if(Pico.video.reg[12]&1) { // 32 col mode? This can change on any frame
fc_inc = 6500;
txtheight_fit = 138;
framebuff_len = 208*145;
memset(framebuff+208*145, 0, 208*37*2);
} else {
fc_inc = 8125;
txtheight_fit = 175;
framebuff_len = 208*182;
}
}
}
u += fc_inc;
if(u < 10000) return 0;
u -= 10000;
unsigned short *vidmem=framebuff;
int slen;
unsigned short *sp;
if(!(Pico.video.reg[12]&1))
{ sp=sdata+32; slen=256; }
else { sp=sdata; slen=320; }
vidmem += num2*208;
/*
int i=0;
while(sp < sto) {
i += inc;
if(i >= 10000) {
*vidmem++ = *sp;
i -= 10000;
}
sp++;
}
*/
PicuShrink(vidmem, 208, sp, slen);
num2++;
// calculate how many lines pico engine should skip,
// making sure this func will be called on scanline 0
int skip = 0;
while(u+fc_inc < 10000 && num+skip != 223) { u+=fc_inc; skip++; }
return skip;
}
int EmuScanFit90(unsigned int num, unsigned short *sdata)
{
// 0.9285
// draw this line?
static int u = 0, num2 = 0;
if(!num) {
u = num2 = 0;
if(Pico.video.reg[12]&1) {
framebuff_offs= 0;
framebuff_len = 208*320;
} else {
framebuff_offs= 208*32;
framebuff_len = 208*256;
}
}
u += 9285;
if(u < 10000) return 0;
u -= 10000;
unsigned short *vidmem=framebuff;
vidmem += 207-num2; // adjust x
// do less copy in 32-column mode
unsigned short *sp, *sto;
if(!(Pico.video.reg[12]&1))
{ sp=sdata+32; sto=sdata+288; vidmem += 32*208; }
else { sp=sdata; sto=sdata+320; }
do { *vidmem = *sp++; vidmem+=208; } while(sp < sto);
num2++;
// skip next line?
if(u+9285 < 10000 && num != 223) { u+=9285; return 1; }
return 0;
}
int EmuScanFit180(unsigned int num, unsigned short *sdata)
{
// 0.65, 145 lines in normal mode; 0.8125, 182 lines in 32-column mode
// draw this line? (ARM4s don't support division)
static int u = 0, num2 = 0;
if(!num) {
u = num2 = 0;
if(currentConfig.iScreenMode == TPicoConfig::PMFit) {
if(Pico.video.reg[12]&1) { // 32 col mode? This can change on any frame
fc_lines = 145;
fc_inc = 6500;
txtheight_fit = 138;
framebuff_len = 208*145;
memset(framebuff+208*145, 0, 208*37*2);
} else {
fc_lines = 182;
fc_inc = 8125;
txtheight_fit = 175;
framebuff_len = 208*182;
}
}
}
u += fc_inc;
if(u < 10000) return 0;
u -= 10000;
unsigned short *vidmem=framebuff;
int slen;
unsigned short *sp;
if(!(Pico.video.reg[12]&1))
{ sp=sdata+32; slen=256; }
else { sp=sdata; slen=320; }
vidmem += (fc_lines-num2)*208;
PicuShrinkReverse(vidmem, 208, sp, slen);
num2++;
// skip some lines?
int skip = 0;
while(u+fc_inc < 10000 && num+skip != 223) { u+=fc_inc; skip++; }
return skip;
}
int EmuScanFit270(unsigned int num, unsigned short *sdata)
{
// 0.9285
// draw this line?
static int u = 0, num2 = 0;
if(!num) {
u = num2 = 0;
if(Pico.video.reg[12]&1) {
framebuff_offs= 0;
framebuff_len = 208*320;
} else {
framebuff_offs= 208*32;
framebuff_len = 208*256;
}
}
u += 9285;
if(u < 10000) return 0;
u -= 10000;
unsigned short *vidmem=framebuff+320*208;
vidmem -= 208-num2; // adjust x
// do less copy in 32-column mode
unsigned short *sp, *sto;
if(!(Pico.video.reg[12]&1))
{ sp=sdata+32; sto=sdata+288; vidmem -= 32*208; }
else { sp=sdata; sto=sdata+320; }
do { *vidmem = *sp++; vidmem-=208; } while(sp < sto);
num2++;
// skip next line?
if(u+9285 < 10000 && num != 223) { u+=9285; return 1; }
return 0;
}
////////////////////////////////
// text drawers
// warning: text must be at least 1px away from screen borders
void drawTextM2(int x, int y, const char *text, long color)
{
unsigned short *vidmem=framebuff;
int charmask, i, cx = x, cy;
unsigned short *l, *le;
// darken the background (left border)
for(l=vidmem+(cx-1)+(y-1)*328, le=vidmem+(cx-1)+(y+7)*328; l < le; l+=328)
*l = (*l >> 2) & dt_dmask;
for(const char *p=text; *p; p++) {
cy = y;
charmask = *(mask_numbers + (*p - 0x2F));
for(l = vidmem+cx+(y-1)*328, le = vidmem+cx+(y+7)*328; l < le; l+=328-4) {
*l = (*l >> 2) & dt_dmask; l++; *l = (*l >> 2) & dt_dmask; l++;
*l = (*l >> 2) & dt_dmask; l++; *l = (*l >> 2) & dt_dmask; l++;
*l = (*l >> 2) & dt_dmask;
}
for(i=0; i < 24; i++) {
// draw dot. Is this fast?
if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*328 ) = color;
charmask <<= 1;
}
cx += 5;
}
}
void drawText0(int x, int y, const char *text, long color)
{
unsigned short *vidmem=framebuff;
int charmask, i, cx = x, cy;
unsigned short *l, *le, dmask=0x0333;
// darken the background (left border)
for(l=vidmem+(cx-1)+(y-1)*208, le=vidmem+(cx-1)+(y+7)*208; l < le; l+=208)
*l = (*l >> 2) & dmask;
for(const char *p=text; *p; p++) {
cy = y;
charmask = *(mask_numbers + (*p - 0x2F));
for(l = vidmem+cx+(y-1)*208, le = vidmem+cx+(y+7)*208; l < le; l+=208-4) {
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
*l = (*l >> 2) & dmask;
}
for(i=0; i < 24; i++) {
// draw dot. Is this fast?
if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*208 ) = color;
charmask <<= 1;
}
cx += 5;
}
}
void drawText90(int x, int y, const char *text, long color)
{
unsigned short *vidmem=framebuff;
unsigned short *l, *le, dmask=0x0333;
int charmask, i, cx, cy = y;
for(l=vidmem+(x+1)+(cy-1)*208, le=vidmem+(x-7)+(cy-1)*208; l > le; l--)
*l = (*l >> 2) & dmask;
for(const char *p=text; *p; p++) {
cx = x;
charmask = *(mask_numbers + (*p - 0x2F));
for(l = vidmem+(x+1)+(cy)*208, le = vidmem+(x+1)+(cy+5)*208; l < le; l+=208+7) {
*l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;
*l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;
*l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;
*l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask;
}
for(i=0; i < 24; i++) {
if(charmask&0x80000000) *( vidmem + (cy+(i&3))*208 + (cx-(i>>2)) ) = color;
charmask <<= 1;
}
cy += 5;
}
}
void drawText180(int x, int y, const char *text, long color)
{
unsigned short *vidmem=framebuff;
int charmask, i, cx = x, cy;
unsigned short *l, *le, dmask=0x0333;
for(l=vidmem+(cx+1)+(y+1)*208, le=vidmem+(cx+1)+(y-7)*208; l > le; l-=208)
*l = (*l >> 2) & dmask;
for(const char *p=text; *p; p++) {
cy = y;
charmask = *(mask_numbers + (*p - 0x2F));
for(l = vidmem+cx+(y+1)*208, le = vidmem+cx+(y-8)*208; l > le; l-=208-4) {
*l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;
*l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;
*l = (*l >> 2) & dmask;
}
for(i=0; i < 24; i++) {
if(charmask&0x80000000) *( vidmem + (cx-(i&3)) + (cy-(i>>2))*208 ) = color;
charmask <<= 1;
}
cx -= 5;
}
}
void drawText270(int x, int y, const char *text, long color)
{
unsigned short *vidmem=framebuff;
int charmask, i, cx, cy = y;
unsigned short *l, *le, dmask=0x0333;
for(l=vidmem+(x-1)+(cy+1)*208, le=vidmem+(x+7)+(cy+1)*208; l < le; l++)
*l = (*l >> 2) & dmask;
for(const char *p=text; *p; p++) {
cx = x;
charmask = *(mask_numbers + (*p - 0x2F));
for(l = vidmem+(x-1)+(cy)*208, le = vidmem+(x-1)+(cy-5)*208; l > le; l-=208+7) {
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
*l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask;
}
for(i=0; i < 24; i++) {
if(charmask&0x80000000) *( vidmem + (cy-(i&3))*208 + (cx+(i>>2)) ) = color;
charmask <<= 1;
}
cy -= 5;
}
}
void drawTextFpsM2(const char *text)
{
if(!text) return;
drawTextM2((Pico.video.reg[12]&1) ? 256 : 224, 200, text, color_redM2);
}
void drawTextFps0(const char *text)
{
if(!text) return;
drawText0(176, 216, text, color_red);
}
void drawTextFpsFit0(const char *text)
{
if(!text) return;
drawText0(176, txtheight_fit, text, color_red);
}
void drawTextFps90(const char *text)
{
if(!text) return;
drawText90(10, 256, text, color_red);
}
void drawTextFps180(const char *text)
{
if(!text) return;
drawText180(32, 8, text, color_red);
}
void drawTextFps270(const char *text)
{
if(!text) return;
drawText270(200, 64, text, color_red);
}
void drawTextNoticeM2(const char *text)
{
if(!text) return;
drawTextM2(20, 200, text, color_redM2);
}
void drawTextNotice0(const char *text)
{
if(!text) return;
drawText0(2, 216, text, color_red);
}
void drawTextNoticeFit0(const char *text)
{
if(!text) return;
drawText0(2, txtheight_fit, text, color_red);
}
void drawTextNotice90(const char *text)
{
if(!text) return;
drawText90(10, 34, text, color_red);
}
void drawTextNotice180(const char *text)
{
if(!text) return;
drawText180(206, 8, text, color_red);
}
void drawTextNotice270(const char *text)
{
if(!text) return;
drawText270(200, 286, text, color_red);
}
////////////////////////////////
// misc drawers
// draws rect with width - 1 and height - 1
void drawRect(const TRect &rc, unsigned short color)
{
if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {
int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;
int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;
for(int x = rc.iTl.iX;; x += stepX) {
*(framebuff + rc.iTl.iY*208 + x) = *(framebuff + (rc.iBr.iY - stepY)*208 + x) = color;
if(x == rc.iBr.iX - stepX) break;
}
for(int y = rc.iTl.iY;; y += stepY) {
*(framebuff + y*208 + rc.iTl.iX) = *(framebuff + y*208 + rc.iBr.iX - stepX) = color;
if(y == rc.iBr.iY - stepY) break;
}
}
}
// draws fullsize filled rect
void drawRectFilled(const TRect rc, unsigned short color)
{
if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {
int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;
int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;
for(int y = rc.iTl.iY;; y += stepY) {
for(int x = rc.iTl.iX;; x += stepX) {
*(framebuff + y*208 + x) = *(framebuff + y*208 + x) = color;
if(x == rc.iBr.iX) break;
}
if(y == rc.iBr.iY) break;
}
}
}
// direction: -1 left, 1 right
void drawArrow0(TPoint p, int direction, unsigned short color)
{
int width = 11;
int x = p.iX;
int y = p.iY;
for(; width > 0; x+=direction, y++, width -=2)
for(int i=0; i < width; i++)
*(framebuff + x + y*208 + i*208) = color;
}
void drawArrow90(TPoint p, int direction, unsigned short color)
{
int width = 11;
int x = p.iX - width;
int y = p.iY;
for(; width > 0; x++, y+=direction, width -=2)
for(int i=0; i < width; i++)
*(framebuff + x + y*208 + i) = color;
}
// copies temporary framebuff to real device framebuffer
void vidBlitRGB444(int full)
{
unsigned short *ps;
unsigned short *pd;
int pixels;
if(full) {
ps = framebuff;
pd = (unsigned short *) screenbuff;
pixels = 208*320;
} else {
ps = framebuff + framebuff_offs;
pd = (unsigned short *) screenbuff + framebuff_offs;
pixels = framebuff_len;
}
vidConvCpyRGB444(pd, ps, pixels);
//for(unsigned short *ps_end = ps + pixels; ps < ps_end; ps++)
// Convert 0000bbb0 ggg0rrr0
// to 0000rrr0 ggg0bbb0
// *pd++ = ((*ps&0x000F)<<8) | (*ps&0x00F0) | ((*ps&0x0F00)>>8);
}
void vidBlitRGB565(int full)
{
unsigned short *ps;
unsigned short *pd;
int pixels;
if(full) {
ps = framebuff;
pd = (unsigned short *) screenbuff;
pixels = 208*320;
} else {
ps = framebuff + framebuff_offs;
pd = (unsigned short *) screenbuff + framebuff_offs;
pixels = framebuff_len;
}
vidConvCpyRGB565(pd, ps, pixels);
//for(; ps < ps_end; ps++)
// Convert 0000bbb0 ggg0rrr0
// to rrr00ggg 000bbb00
// *pd++ = ((*ps&0x000F)<<12) | ((*ps&0x00F0)<<3) | ((*ps&0x0F00)>>7);
}
void vidBlitRGB32(int full)
{
unsigned short *ps;
unsigned long *pd;
int pixels;
if(full) {
ps = framebuff;
pd = (unsigned long *) screenbuff;
pixels = 208*320;
} else {
ps = framebuff + framebuff_offs;
pd = (unsigned long *) screenbuff + framebuff_offs;
pixels = framebuff_len;
}
vidConvCpyRGB32(pd, ps, pixels);
//for(; ps < ps_end; ps++)
// Convert 0000bbb0 ggg0rrr0
// to ..0 rrr00000 ggg00000 bbb00000
// *pd++ = ((*ps&0x000F)<<20) | ((*ps&0x00F0)<<8) | ((*ps&0x0F00)>>4);
}
// -------- rendermode 2 ---------
void vidBlit16M2(int full)
{
unsigned short *ps = framebuff+328*8;
unsigned short *pd = (unsigned short *) screenbuff;
if(currentConfig.iScreenRotation == TPicoConfig::PRot90) {
if(Pico.video.reg[12]&1)
vidConvCpyM2_16_90(pd, ps, 320/8);
else {
if(full) memset(pd, 0, 208*32*2);
pd += 208*32;
vidConvCpyM2_16_90(pd, ps, 256/8);
if(full) memset(pd + 208*256, 0, 208*32*2);
}
} else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) {
if(Pico.video.reg[12]&1)
vidConvCpyM2_16_270(pd, ps, 320/8);
else {
if(full) memset(pd, 0, 208*32*2);
pd += 208*32;
ps -= 64; // the blitter starts copying from the right border, so we need to adjust
vidConvCpyM2_16_270(pd, ps, 256/8);
if(full) memset(pd + 208*256, 0, 208*32*2);
}
}
/*
for(int x=0; x < 320; x++)
for(int y=207; y>=0; y--) {
*pd++ = *(ps+8+x+y*328);
}
*/
}
void vidBlitRGB32M2(int full)
{
unsigned short *ps = framebuff+328*8;
unsigned long *pd = (unsigned long *) screenbuff;
if(currentConfig.iScreenRotation == TPicoConfig::PRot90) {
if(Pico.video.reg[12]&1)
vidConvCpyM2_RGB32_90(pd, ps, 320/8);
else {
if(full) memset(pd, 0, 208*32*4);
pd += 208*32;
vidConvCpyM2_RGB32_90(pd, ps, 256/8);
if(full) memset(pd + 208*256, 0, 208*32*4);
}
} else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) {
if(Pico.video.reg[12]&1)
vidConvCpyM2_RGB32_270(pd, ps, 320/8);
else {
if(full) memset(pd, 0, 208*32*4);
pd += 208*32;
ps -= 64; // the blitter starts copying from the right border, so we need to adjust
vidConvCpyM2_RGB32_270(pd, ps, 256/8);
if(full) memset(pd + 208*256, 0, 208*32*4);
}
}
}
void PrepareCramRGB444M2()
{
vidConvCpyRGB444(cram_high, Pico.cram, 0x40);
}
void PrepareCramRGB565M2()
{
vidConvCpyRGB565(cram_high, Pico.cram, 0x40);
}
////////////////////////////////
// main functions
int vidInit(int displayMode, void *vidmem, int p800, int reinit)
{
if(!reinit) {
// prepare framebuffer
screenbuff = (unsigned short *) vidmem;
framebuff = (unsigned short *) malloc(framebuffsize);
if(!screenbuff) return KErrNotSupported;
if(!framebuff) return KErrNoMemory;
// Cram function: go and hack Pico so it never gets called
PicoCram = EmuCramNull;
}
// select suitable blitter
switch(displayMode) {
case EColor4K: vidBlit = vidBlitKeyCfg = vidBlitRGB444; break;
case EColor64K: vidBlit = vidBlitKeyCfg = vidBlitRGB565; break;
case EColor16M: vidBlit = vidBlitKeyCfg = vidBlitRGB32; break;
default: return KErrNotSupported;
}
memset(framebuff, 0, framebuffsize);
// rendermode 2?
if(PicoOpt&0x10) {
switch(displayMode) {
case EColor4K:
vidBlit = vidBlit16M2;
PicoPrepareCram = PrepareCramRGB444M2;
PicoCramHigh = cram_high;
color_redM2 = 0x0F22;
dt_dmask = 0x0333;
break;
case EColor64K:
vidBlit = vidBlit16M2;
PicoPrepareCram = PrepareCramRGB565M2;
PicoCramHigh = cram_high;
color_redM2 = 0xF882;
dt_dmask = 0x39e7;
break;
case EColor16M:
vidBlit = vidBlitRGB32M2;
break;
}
drawTextFps = drawTextFpsM2;
drawTextNotice = drawTextNoticeM2;
vidBlit(1);
return 0;
}
framebuff_offs = 0;
framebuff_len = 208*320;
vidBlit(1);
// setup all orientation related stuff
if(currentConfig.iScreenRotation == TPicoConfig::PRot0) {
if(currentConfig.iScreenMode == TPicoConfig::PMCenter) {
PicoScan = EmuScanCenter0;
framebuff_len = 208*224;
drawTextFps = drawTextFps0;
drawTextNotice = drawTextNotice0;
} else {
if(currentConfig.iScreenMode == TPicoConfig::PMFit2) {
if(p800) {
fc_inc = 6518; // 0.651786 (144+2)
txtheight_fit = 139;
framebuff_len = 208*146;
} else {
fc_inc = 9286; // 0.92857
txtheight_fit = 201;
framebuff_len = 208*208;
}
}
PicoScan = EmuScanFit0;
drawTextFps = drawTextFpsFit0;
drawTextNotice = drawTextNoticeFit0;
}
} else if(currentConfig.iScreenRotation == TPicoConfig::PRot90) {
if(currentConfig.iScreenMode == TPicoConfig::PMFit)
PicoScan = EmuScanFit90;
else PicoScan = EmuScanCenter90;
drawTextFps = drawTextFps90;
drawTextNotice = drawTextNotice90;
} else if(currentConfig.iScreenRotation == TPicoConfig::PRot180) {
if(currentConfig.iScreenMode == TPicoConfig::PMCenter) {
PicoScan = EmuScanCenter180;
framebuff_len = 208*224;
} else {
if(currentConfig.iScreenMode == TPicoConfig::PMFit2) {
if(p800) {
fc_inc = 6518; // 0.651786
fc_lines = 146;
framebuff_len = 208*146;
} else {
fc_inc = 9286; // 0.92857
fc_lines = 208;
framebuff_len = 208*208;
}
}
PicoScan = EmuScanFit180;
}
drawTextFps = drawTextFps180;
drawTextNotice = drawTextNotice180;
} else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) {
if(currentConfig.iScreenMode == TPicoConfig::PMFit)
PicoScan = EmuScanFit270;
else PicoScan = EmuScanCenter270;
drawTextFps = drawTextFps270;
drawTextNotice = drawTextNotice270;
}
return 0;
}
void vidFree()
{
free(framebuff);
framebuff = 0;
}
void vidDrawFrame(char *noticeStr, char *fpsStr, int num)
{
PicoFrame();
if(currentConfig.iFlags & 2)
drawTextFps(fpsStr);
drawTextNotice(noticeStr);
vidBlit(!num); // copy full frame once a second
}
void vidKeyConfigFrame(const TUint whichAction, TInt flipClosed)
{
int i;
char buttonNames[128];
buttonNames[0] = 0;
memset(framebuff, 0, framebuffsize);
unsigned long currentActCode = 1 << whichAction;
if(flipClosed) {
drawRectFilled(TRect(56, 2, 152, 16), color_grey); // 96x14
drawArrow0(TPoint(64, 3), -1, color_green);
drawArrow0(TPoint(144, 3), 1, color_green);
drawText0(64, 20, "USE@JOG@TO@SELECT", color_red);
drawText0(68, 6, actionNames[whichAction], color_red);
} else {
// draw all "buttons" in reverse order
const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0;
while(e->rect != TRect(0,0,0,0)) { e++; i++; }
for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--)
drawRect(e->rect, (currentConfig.iAreaBinds[i] & currentActCode) ? color_red : color_red_dim);
// draw config controls
drawRectFilled(TRect(190, 112, 204, 208), color_grey);
drawArrow90(TPoint(203, 120), -1, color_green);
drawArrow90(TPoint(203, 200), 1, color_green);
drawText90(200, 124, actionNames[whichAction], color_red);
}
// draw active button names if there are any
i = 0;
for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++)
if(currentConfig.iKeyBinds[i] & currentActCode) {
if(buttonNames[0]) strcat(buttonNames, ";@");
strcat(buttonNames, e->name);
}
if(buttonNames[0]) {
if(flipClosed) {
buttonNames[41] = 0; // only 61 chars fit
drawText0(2, 138, buttonNames, color_blue);
} else {
buttonNames[61] = 0;
drawText90(12, 10, buttonNames, color_blue);
}
}
vidBlitKeyCfg(1);
}
void vidDrawFCconfigDone()
{
drawText0(64, 20, "USE@JOG@TO@SELECT", 0); // blank prev text
drawText0(54, 30, "OPEN@FLIP@TO@CONTINUE", color_red);
vidBlitKeyCfg(1);
}
void vidDrawNotice(const char *txt)
{
if(framebuff) {
drawTextNotice(txt);
vidBlit(1);
}
}