Files
px68k-libretro/x11/windraw.c
T
2014-07-09 17:29:07 +09:00

2155 lines
46 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2003 NONAKA Kimihiro
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "common.h"
#include <SDL.h>
#ifdef USE_OGLES11
#include <SDL_opengles.h>
#endif
#ifdef PSP
#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspgu.h>
#endif
//#include <SDL_rotozoom.h>
#include "winx68k.h"
#include "winui.h"
#include "bg.h"
#include "crtc.h"
#include "gvram.h"
#include "mouse.h"
#include "palette.h"
#include "prop.h"
#include "status.h"
#include "tvram.h"
#include "joystick.h"
#include "keyboard.h"
#if 0
#include "../icons/keropi.xpm"
#endif
extern BYTE Debug_Text, Debug_Grp, Debug_Sp;
#ifdef PSP
WORD *ScrBufL = 0, *ScrBufR = 0;
#else
WORD *ScrBuf = 0;
#endif
#if defined(PSP) || defined(USE_OGLES11)
WORD *menu_buffer;
WORD *kbd_buffer;
#endif
#ifdef USE_SDLGFX
SDL_Surface *sdl_rgbsurface;
#endif
int Draw_Opaque;
int FullScreenFlag = 0;
extern BYTE Draw_RedrawAllFlag;
BYTE Draw_DrawFlag = 1;
BYTE Draw_ClrMenu = 0;
BYTE Draw_BitMask[800];
BYTE Draw_TextBitMask[800];
int winx = 0, winy = 0;
DWORD winh = 0, winw = 0;
DWORD root_width, root_height;
WORD FrameCount = 0;
int SplashFlag = 0;
WORD WinDraw_Pal16B, WinDraw_Pal16R, WinDraw_Pal16G;
DWORD WindowX = 0;
DWORD WindowY = 0;
#ifdef USE_OGLES11
static GLuint texid[11];
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
extern SDL_Window *sdl_window;
#endif
void WinDraw_InitWindowSize(WORD width, WORD height)
{
static BOOL inited = FALSE;
if (!inited) {
inited = TRUE;
}
winw = width;
winh = height;
if (root_width < winw)
winx = (root_width - winw) / 2;
else if (winx < 0)
winx = 0;
else if ((winx + winw) > root_width)
winx = root_width - winw;
if (root_height < winh)
winy = (root_height - winh) / 2;
else if (winy < 0)
winy = 0;
else if ((winy + winh) > root_height)
winy = root_height - winh;
}
void WinDraw_ChangeSize(void)
{
DWORD oldx = WindowX, oldy = WindowY;
int dif;
Mouse_ChangePos();
switch (Config.WinStrech) {
case 0:
WindowX = TextDotX;
WindowY = TextDotY;
break;
case 1:
WindowX = 768;
WindowY = 512;
break;
case 2:
if (TextDotX <= 384)
WindowX = TextDotX * 2;
else
WindowX = TextDotX;
if (TextDotY <= 256)
WindowY = TextDotY * 2;
else
WindowY = TextDotY;
break;
case 3:
if (TextDotX <= 384)
WindowX = TextDotX * 2;
else
WindowX = TextDotX;
if (TextDotY <= 256)
WindowY = TextDotY * 2;
else
WindowY = TextDotY;
dif = WindowX - WindowY;
if ((dif > -32) && (dif < 32)) {
// 正方形に近い画面なら、としておこう
WindowX = (int)(WindowX * 1.25);
}
break;
}
if ((WindowX > 768) || (WindowX <= 0)) {
if (oldx)
WindowX = oldx;
else
WindowX = oldx = 768;
}
if ((WindowY > 512) || (WindowY <= 0)) {
if (oldy)
WindowY = oldy;
else
WindowY = oldy = 512;
}
if ((oldx == WindowX) && (oldy == WindowY))
return;
WinDraw_InitWindowSize((WORD)WindowX, (WORD)WindowY);
StatBar_Show(Config.WindowFDDStat);
Mouse_ChangePos();
}
//static int dispflag = 0;
void WinDraw_StartupScreen(void)
{
}
void WinDraw_CleanupScreen(void)
{
}
void WinDraw_ChangeMode(int flag)
{
/* full screen mode(TRUE) <-> window mode(FALSE) */
(void)flag;
}
void WinDraw_ShowSplash(void)
{
}
void WinDraw_HideSplash(void)
{
}
#ifdef PSP
/*
<----- 512byte ------>
0x04000000+--------------------+
| |A
| draw/disp 0 buffer ||272*2byte (16bit color)
| |V
0x04044000+--------------------+
| |A
| draw/disp 1 buffer ||272*2byte
| |V
0x04088000+--------------------+
| |A
| z bufer ||272*2byte
| |V
0x040cc000+--------------------+
| |A
| ScrBufL (left) ||512*2byte (x68k screen size: 756x512)
| |V
0x0414c000+----------+---------+
|<- 256B ->|A
| ScrBufR ||512*2byte (x68k screen size: 756x512)
| (right) |V
0x0418c000+----------+---------+A
|仮想キーボード用 || 512*256*2byte
| に使うかも領域 |V
0x041cc000+--------------------+
| |
| Virtexes |
| |
+--------------------+
*/
static unsigned int __attribute__((aligned(16))) list[262144];
void *fbp0, *fbp1, *zbp;
struct Vertexes {
unsigned short u, v; // Texture (sx, sy)
unsigned short color;
short x, y, z; // Screen (sx, sy, sz)
unsigned short u2, v2; // Texture (ex, ey)
unsigned short color2;
short x2, y2, z2; // Screen (ex, ey, ez)
};
struct Vertexes *vtxl = (struct Vertexes *)0x41cc000;
struct Vertexes *vtxr = (struct Vertexes *)(0x41cc000 + sizeof(struct Vertexes));
struct Vertexes *vtxm = (struct Vertexes *)(0x41cc000 + sizeof(struct Vertexes) * 2);
struct Vertexes *vtxk = (struct Vertexes *)(0x41cc000 + sizeof(struct Vertexes) * 3);
#define PSP_BUF_WIDTH (512)
#define PSP_SCR_WIDTH (480)
#define PSP_SCR_HEIGHT (272)
#endif // PSP
static void draw_kbd_to_tex(void);
int WinDraw_Init(void)
{
int i, j;
#ifndef USE_OGLES11
SDL_Surface *sdl_surface;
#if SDL_VERSION_ATLEAST(2, 0, 0)
sdl_surface = SDL_GetWindowSurface(sdl_window);
#else
sdl_surface = SDL_GetVideoSurface();
#endif
if (sdl_surface == NULL) {
fprintf(stderr, "can't create surface.\n");
return 1;
}
#endif
WindowX = 768;
WindowY = 512;
#if SDL_VERSION_ATLEAST(2, 0, 0)
WinDraw_Pal16R = 0xf800;
WinDraw_Pal16G = 0x07e0;
WinDraw_Pal16B = 0x001f;
#else
WinDraw_Pal16R = sdl_surface->format->Rmask;
WinDraw_Pal16G = sdl_surface->format->Gmask;
WinDraw_Pal16B = sdl_surface->format->Bmask;
printf("R: %x, G: %x, B: %x\n", WinDraw_Pal16R, WinDraw_Pal16G, WinDraw_Pal16B);
#endif
#if defined(USE_OGLES11)
ScrBuf = malloc(1024*1024*2); // OpenGL ES 1.1 needs 2^x pixels
if (ScrBuf == NULL) {
return FALSE;
}
kbd_buffer = malloc(1024*1024*2); // OpenGL ES 1.1 needs 2^x pixels
if (kbd_buffer == NULL) {
return FALSE;
}
p6logd("kbd_buffer 0x%x", kbd_buffer);
memset(texid, 0, sizeof(texid));
glGenTextures(11, &texid[0]);
// texid[0] for the main screen
glBindTexture(GL_TEXTURE_2D, texid[0]);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
// glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 1024, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, ScrBuf);
WORD BtnTex[32*32];
//とりあえず薄めの緑で。
for (i = 0; i < 32*32; i++) {
BtnTex[i] = 0x03e0;
}
// ボタン用テクスチャ。とりあえず全部同じ色。
for (i = 1; i < 9; i++) {
glBindTexture(GL_TEXTURE_2D, texid[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
if (i == 7) {
// とりあえずキーボードonボタンは薄めの黄色で。
for (j = 0; j < 32*32; j++) {
BtnTex[j] = (0x7800 | 0x03e0);
}
}
if (i == 8) {
// とりあえずmenu onボタンは薄めの白色で。
for (j = 0; j < 32*32; j++) {
BtnTex[j] = (0x7800 | 0x03e0 | 0x0f);
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 32, 32, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, BtnTex);
}
// メニュー描画用テクスチャ。
glBindTexture(GL_TEXTURE_2D, texid[9]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 1024, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, menu_buffer);
draw_kbd_to_tex();
// ソフトウェアキーボード描画用テクスチャ。
glBindTexture(GL_TEXTURE_2D, texid[10]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 1024, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, kbd_buffer);
#elif defined(PSP)
fbp0 = 0; // offset 0
fbp1 = (void *)((unsigned int)fbp0 + PSP_BUF_WIDTH * PSP_SCR_HEIGHT * 2);
zbp = (void *)((unsigned int)fbp1 + PSP_BUF_WIDTH * PSP_SCR_HEIGHT * 2);
sceGuInit();
sceGuStart(GU_DIRECT,list);
sceGuDrawBuffer(GU_PSM_5650, fbp0, PSP_BUF_WIDTH);
sceGuDispBuffer(PSP_SCR_WIDTH, PSP_SCR_HEIGHT, fbp1, PSP_BUF_WIDTH);
sceGuDepthBuffer(zbp, PSP_BUF_WIDTH);
sceGuOffset(2048 - (PSP_SCR_WIDTH/2), 2048 - (PSP_SCR_HEIGHT/2));
sceGuViewport(2048, 2048, PSP_SCR_WIDTH, PSP_SCR_HEIGHT);
sceGuDepthRange(65535, 0);
sceGuScissor(0, 0, PSP_SCR_WIDTH, PSP_SCR_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
sceGuFrontFace(GU_CW);
sceGuEnable(GU_TEXTURE_2D);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
sceGuFinish();
sceGuSync(0, 0);
sceDisplayWaitVblankStart();
sceGuDisplay(GU_TRUE);
ScrBufL = (WORD *)0x040cc000;
ScrBufR = (WORD *)0x0414c000;
kbd_buffer = (WORD *)0x418c000;
draw_kbd_to_tex();
#else
#ifdef USE_SDLGFX
sdl_rgbsurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 800, 600, 16, WinDraw_Pal16R, WinDraw_Pal16G, WinDraw_Pal16B, 0);
if (sdl_rgbsurface == 0) {
puts("ScrBuf allocate failed");
exit(1);
}
ScrBuf = sdl_rgbsurface->pixels;
printf("drawbuf: 0x%x, ScrBuf: 0x%x\n", sdl_surface->pixels, ScrBuf);
#else
ScrBuf = malloc(800 * 600 * 2);
#endif
#endif
return TRUE;
}
void
WinDraw_Cleanup(void)
{
}
void
WinDraw_Redraw(void)
{
TVRAM_SetAllDirty();
}
#ifdef USE_OGLES11
#define SET_GLFLOATS(dst, a, b, c, d, e, f, g, h) \
{ \
dst[0] = (a); dst[1] = (b); dst[2] = (c); dst[3] = (d); \
dst[4] = (e); dst[5] = (f); dst[6] = (g); dst[7] = (h); \
}
static void draw_texture(GLfloat *coor, GLfloat *vert)
{
glTexCoordPointer(2, GL_FLOAT, 0, coor);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vert);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void draw_button(GLuint texid, GLfloat x, GLfloat y, GLfloat s, GLfloat *tex, GLfloat *ver)
{
glBindTexture(GL_TEXTURE_2D, texid);
// Texture から必要な部分を抜き出す(32x32を全部使う)
SET_GLFLOATS(tex, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f);
// s倍にして貼り付ける
SET_GLFLOATS(ver, x, y + 32.0f * s, x, y, x + 32.0f * s, y + 32.0f * s, x + 32.0f * s, y + 0.0f);
draw_texture(tex, ver);
}
void draw_all_buttons(GLfloat *tex, GLfloat *ver, GLfloat scale, int is_menu)
{
int i;
VBTN_POINTS *p;
p = Joystick_get_btn_points(scale);
// 仮想キーはtexid: 1から6まで、キーボードonボタンが7、menuボタンが8
for (i = 1; i < 9; i++) {
if (need_Vpad() || i >= 7 || (Config.JoyOrMouse && i >= 5)) {
draw_button(texid[i], p->x, p->y, scale, tex, ver);
}
p++;
}
}
#endif // USE_OGLES11
void FASTCALL
WinDraw_Draw(void)
{
SDL_Surface *sdl_surface;
static int oldtextx = -1, oldtexty = -1;
if (oldtextx != TextDotX) {
oldtextx = TextDotX;
p6logd("TextDotX: %d\n", TextDotX);
}
if (oldtexty != TextDotY) {
oldtexty = TextDotY;
p6logd("TextDotY: %d\n", TextDotY);
}
#if defined(USE_OGLES11)
GLfloat texture_coordinates[8];
GLfloat vertices[8];
GLfloat w;
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
// アルファブレンドしない(上のテクスチャが下のテクスチャを隠す)
glBlendFunc(GL_ONE, GL_ZERO);
glBindTexture(GL_TEXTURE_2D, texid[0]);
//ScrBufから800x600の領域を切り出してテクスチャに転送
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 800, 600, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, ScrBuf);
// magic numberがやたら多いが、テクスチャのサイズが1024x1024
// OpenGLでの描画領域がglOrthof()で定義した800x600
// X68K 画面描画
// Texture から必要な部分を抜き出す
// Texutre座標は0.0fから1.0fの間
SET_GLFLOATS(texture_coordinates,
0.0f, (GLfloat)TextDotY/1024,
0.0f, 0.0f,
(GLfloat)TextDotX/1024, (GLfloat)TextDotY/1024,
(GLfloat)TextDotX/1024, 0.0f);
// 実機の解像度(realdisp_w x realdisp_h)に関係なく、
// 座標は800x600
w = (realdisp_h * 1.33333) / realdisp_w * 800;
SET_GLFLOATS(vertices,
(800.0f - w)/2, (GLfloat)600,
(800.0f - w)/2, 0.0f,
(800.0f - w)/2 + w, (GLfloat)600,
(800.0f - w)/2 + w, 0.0f);
draw_texture(texture_coordinates, vertices);
// ソフトウェアキーボード描画
if (Keyboard_IsSwKeyboard()) {
glBindTexture(GL_TEXTURE_2D, texid[10]);
//kbd_bufferから800x600の領域を切り出してテクスチャに転送
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 800, 600, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, kbd_buffer);
// Texture から必要な部分を抜き出す
// Texutre座標は0.0fから1.0fの間
SET_GLFLOATS(texture_coordinates,
0.0f, (GLfloat)kbd_h/1024,
0.0f, 0.0f,
(GLfloat)kbd_w/1024, (GLfloat)kbd_h/1024,
(GLfloat)kbd_w/1024, 0.0f);
// 実機の解像度(realdisp_w x realdisp_h)に関係なく、
// 座標は800x600
float kbd_scale = 0.8;
SET_GLFLOATS(vertices,
(GLfloat)kbd_x, (GLfloat)(kbd_h * kbd_scale + kbd_y),
(GLfloat)kbd_x, (GLfloat)kbd_y,
(GLfloat)(kbd_w * kbd_scale + kbd_x), (GLfloat)(kbd_h * kbd_scale + kbd_y),
(GLfloat)(kbd_w * kbd_scale + kbd_x), (GLfloat)kbd_y);
draw_texture(texture_coordinates, vertices);
}
// 仮想パッド/ボタン描画
// アルファブレンドする(スケスケいやん)
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
draw_all_buttons(texture_coordinates, vertices, (GLfloat)WinUI_get_vkscale(), 0);
// glDeleteTextures(1, &texid);
SDL_GL_SwapWindow(sdl_window);
#elif defined(PSP)
sceGuStart(GU_DIRECT, list);
sceGuClearColor(0);
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
// 左半分
vtxl->u = 0;
vtxl->v = 0;
vtxl->color = 0;
vtxl->x = (480 - (272 * 1.33333)) / 2; // 1.3333 = 4 : 3
vtxl->y = 0;
vtxl->z = 0;
vtxl->u2 = (TextDotX >= 512)? 512 : TextDotX;
vtxl->v2 = TextDotY;
vtxl->color2 = 0;
vtxl->x2 = (TextDotX >= 512)?
vtxl->x + 272 * 1.33333 * (512.0 / TextDotX) :
vtxl->x + 272 * 1.33333;
vtxl->y2 = 272;
vtxl->z2 = 0;
sceGuTexMode(GU_PSM_5650, 0, 0, 0);
sceGuTexImage(0, 512, 512, 512, ScrBufL);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_16BIT|GU_COLOR_5650|GU_VERTEX_16BIT|GU_TRANSFORM_2D, 2, 0, vtxl);
if (TextDotX > 512) {
// 右半分
vtxr->u = 0;
vtxr->v = 0;
vtxr->color = 0;
vtxr->x = vtxl->x2;
vtxr->y = 0;
vtxr->z = 0;
vtxr->u2 = TextDotX - 512;
vtxr->v2 = TextDotY;
vtxr->color2 = 0;
vtxr->x2 = vtxl->x + 272 * 1.33333;
vtxr->y2 = 272;
vtxr->z2 = 0;
sceGuTexMode(GU_PSM_5650, 0, 0, 0);
sceGuTexImage(0, 256, 512, 256, ScrBufR);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_16BIT|GU_COLOR_5650|GU_VERTEX_16BIT|GU_TRANSFORM_2D, 2, 0, vtxr);
}
if (Keyboard_IsSwKeyboard()) {
vtxk->u = 0;
vtxk->v = 0;
vtxk->color = 0;
vtxk->x = kbd_x;
vtxk->y = kbd_y;
vtxk->z = 0;
vtxk->u2 = kbd_w;
vtxk->v2 = kbd_h;
vtxk->color2 = 0;
vtxk->x2 = kbd_x + kbd_w;
vtxk->y2 = kbd_y + kbd_h;
vtxk->z2 = 0;
sceGuTexImage(0, 512, 256, 512, kbd_buffer);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_16BIT|GU_COLOR_5650|GU_VERTEX_16BIT|GU_TRANSFORM_2D, 2, 0, vtxk);
}
sceGuFinish();
sceGuSync(0, 0);
sceGuSwapBuffers();
#else // OpenGL ES 未使用
#if SDL_VERSION_ATLEAST(2, 0, 0)
sdl_surface = SDL_GetWindowSurface(sdl_window);
#else
sdl_surface = SDL_GetVideoSurface();
#endif
#ifdef USE_SDLGFX
SDL_Surface *roto_surface = NULL;
int ret;
if (sdl_rgbsurface == NULL) {
puts("xxx sdl_rgbsurface not allocated yet");
return;
}
if (TextDotX <= 512) {
roto_surface = rotozoomSurfaceXY(sdl_rgbsurface, 0.0, 512.0*1.33333/TextDotX, 512.0/TextDotY, 0);
}
if (roto_surface) {
ret = SDL_BlitSurface(roto_surface, NULL, sdl_surface, NULL);
SDL_FreeSurface(roto_surface);
} else {
ret = SDL_BlitSurface(sdl_rgbsurface, NULL, sdl_surface, NULL);
}
if (ret < 0) {
printf("SDL_BlitSurface() failed %d\n", ret);
}
#else
int x, y, Bpp;
// WORD c, *p, *p2, dummy, *dst16;
WORD *p, *dst16;
DWORD *dst32, dat32;
Bpp = sdl_surface->format->BytesPerPixel;
// 2倍に拡大する
if (TextDotX <= 256 && TextDotY <= 256) {
for (y = 0; y < 256; y++) {
p = ScrBuf + 800 * y;
// surface->pixelsはvoid *
dst16 = sdl_surface->pixels + sdl_surface->w * Bpp * y * 2;
dst32 = (DWORD *)dst16;
for (x = 0; x < 256; x++) {
if (Bpp == 4) {
dat32 = (DWORD)(*p & 0xf800) << 8 | (*p & 0x07e0) << 5 | (*p & 0x001f) << 3;
*dst32++ = dat32;
*dst32 = dat32;
dst32 += sdl_surface->w;
*dst32-- = dat32;
*dst32 = dat32;
p++;
dst32 -= sdl_surface->w;
dst32 += 2;
} else if (Bpp == 2) {
*dst16++ = *p;
*dst16 = *p;
dst16 += sdl_surface->w;
*dst16-- = *p;
*dst16 = *p;
p++;
dst16 -= sdl_surface->w;
dst16 += 2;
} else {
// xxx 未サポート
}
}
}
} else {
for (y = 0; y < 512; y++) {
p = ScrBuf + 800 * y;
// surface->pixelsはvoid *
dst16 = sdl_surface->pixels + sdl_surface->w * Bpp * y;
dst32 = (DWORD *)dst16;
for (x = 0; x < 800; x++) {
if (Bpp == 4) {
*dst32++ = (DWORD)(*p & 0xf800) << 8 | (*p & 0x07e0) << 5 | (*p & 0x001f) << 3;
} else if (Bpp == 2) {
*dst16++ = *p;
}
p++;
}
}
}
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_UpdateWindowSurface(sdl_window);
#else
SDL_UpdateRect(sdl_surface, 0, 0, FULLSCREEN_WIDTH, FULLSCREEN_HEIGHT);
#endif
#endif
FrameCount++;
if (!Draw_DrawFlag/* && is_installed_idle_process()*/)
return;
Draw_DrawFlag = 0;
if (SplashFlag)
WinDraw_ShowSplash();
}
#ifdef PSP
#ifdef FULLSCREEN_WIDTH
#undef FULLSCREEN_WIDTH
#endif
//PSPのテクスチャは一辺が最大512なので、X68000の768x512画面を
//512x512と256x512の左右二つに分ける。
//以下のDrawLine系の関数処理もPSPは左右のテクスチャを別々に
//処理しなければならない。
//ということで、以下のdefineは左側テクスチャの横幅を表している。
#define FULLSCREEN_WIDTH 512
#endif
#ifdef PSP
#define WD_MEMCPY(src) \
{ \
if (TextDotX > 512) { \
memcpy(&ScrBufL[adr], (src), 512 * 2); \
adr = VLINE * 256; \
memcpy(&ScrBufR[adr], (WORD *)(src) + 512, TextDotX * 2 - 512 * 2); \
} else { \
memcpy(&ScrBufL[adr], (src), TextDotX * 2); \
} \
}
#else
#define WD_MEMCPY(src) memcpy(&ScrBuf[adr], (src), TextDotX * 2)
#endif
#ifdef PSP
#define WD_LOOP(start, end, sub) \
{ \
if (TextDotX > 512) { \
for (i = (start); i < 512 + (start); i++, adr++) { \
sub(L); \
} \
adr = VLINE * 256; \
for (i = 512 + (start); i < (end); i++, adr++) { \
sub(R); \
} \
} else { \
for (i = (start); i < (end); i++, adr++) { \
sub(L); \
} \
} \
}
#else
#define WD_LOOP(start, end, sub) \
{ \
for (i = (start); i < (end); i++, adr++) { \
sub(); \
} \
}
#endif
#define WD_SUB(SUFFIX, src) \
{ \
w = (src); \
if (w != 0) \
ScrBuf##SUFFIX[adr] = w; \
}
INLINE void WinDraw_DrawGrpLine(int opaq)
{
#define _DGL_SUB(SUFFIX) WD_SUB(SUFFIX, Grp_LineBuf[i])
DWORD adr = VLINE*FULLSCREEN_WIDTH;
WORD w;
int i;
if (opaq) {
WD_MEMCPY(Grp_LineBuf);
} else {
WD_LOOP(0, TextDotX, _DGL_SUB);
}
}
INLINE void WinDraw_DrawGrpLineNonSP(int opaq)
{
#define _DGL_NSP_SUB(SUFFIX) WD_SUB(SUFFIX, Grp_LineBufSP2[i])
DWORD adr = VLINE*FULLSCREEN_WIDTH;
WORD w;
int i;
if (opaq) {
WD_MEMCPY(Grp_LineBufSP2);
} else {
WD_LOOP(0, TextDotX, _DGL_NSP_SUB);
}
}
INLINE void WinDraw_DrawTextLine(int opaq, int td)
{
#define _DTL_SUB2(SUFFIX) WD_SUB(SUFFIX, BG_LineBuf[i])
#define _DTL_SUB(SUFFIX) \
{ \
if (Text_TrFlag[i] & 1) { \
_DTL_SUB2(SUFFIX); \
} \
}
DWORD adr = VLINE*FULLSCREEN_WIDTH;
WORD w;
int i;
if (opaq) {
WD_MEMCPY(&BG_LineBuf[16]);
} else {
if (td) {
WD_LOOP(16, TextDotX + 16, _DTL_SUB);
} else {
WD_LOOP(16, TextDotX + 16, _DTL_SUB2);
}
}
}
INLINE void WinDraw_DrawTextLineTR(int opaq)
{
#define _DTL_TR_SUB(SUFFIX) \
{ \
w = Grp_LineBufSP[i - 16]; \
if (w != 0) { \
w &= Pal_HalfMask; \
v = BG_LineBuf[i]; \
if (v & Ibit) \
w += Pal_Ix2; \
v &= Pal_HalfMask; \
v += w; \
v >>= 1; \
} else { \
if (Text_TrFlag[i] & 1) \
v = BG_LineBuf[i]; \
else \
v = 0; \
} \
ScrBuf##SUFFIX[adr] = (WORD)v; \
}
#define _DTL_TR_SUB2(SUFFIX) \
{ \
if (Text_TrFlag[i] & 1) { \
w = Grp_LineBufSP[i - 16]; \
v = BG_LineBuf[i]; \
\
if (v != 0) { \
if (w != 0) { \
w &= Pal_HalfMask; \
if (v & Ibit) \
w += Pal_Ix2; \
v &= Pal_HalfMask; \
v += w; \
v >>= 1; \
} \
ScrBuf##SUFFIX[adr] = (WORD)v; \
} \
} \
}
DWORD adr = VLINE*FULLSCREEN_WIDTH;
DWORD v;
WORD w;
int i;
if (opaq) {
WD_LOOP(16, TextDotX + 16, _DTL_TR_SUB);
} else {
WD_LOOP(16, TextDotX + 16, _DTL_TR_SUB2);
}
}
INLINE void WinDraw_DrawBGLine(int opaq, int td)
{
#define _DBL_SUB2(SUFFIX) WD_SUB(SUFFIX, BG_LineBuf[i])
#define _DBL_SUB(SUFFIX) \
{ \
if (Text_TrFlag[i] & 2) { \
_DBL_SUB2(SUFFIX); \
} \
}
DWORD adr = VLINE*FULLSCREEN_WIDTH;
WORD w;
int i;
#if 0 // debug for segv
static int log_start = 0;
if (TextDotX == 128 && TextDotY == 128) {
log_start = 1;
}
if (log_start) {
printf("opaq/td: %d/%d VLINE: %d, TextDotX: %d\n", opaq, td, VLINE, TextDotX);
}
#endif
if (opaq) {
WD_MEMCPY(&BG_LineBuf[16]);
} else {
if (td) {
WD_LOOP(16, TextDotX + 16, _DBL_SUB);
} else {
WD_LOOP(16, TextDotX + 16, _DBL_SUB2);
}
}
}
INLINE void WinDraw_DrawBGLineTR(int opaq)
{
#define _DBL_TR_SUB3() \
{ \
if (w != 0) { \
w &= Pal_HalfMask; \
if (v & Ibit) \
w += Pal_Ix2; \
v &= Pal_HalfMask; \
v += w; \
v >>= 1; \
} \
}
#define _DBL_TR_SUB(SUFFIX) \
{ \
w = Grp_LineBufSP[i - 16]; \
v = BG_LineBuf[i]; \
\
_DBL_TR_SUB3() \
ScrBuf##SUFFIX[adr] = (WORD)v; \
}
#define _DBL_TR_SUB2(SUFFIX) \
{ \
if (Text_TrFlag[i] & 2) { \
w = Grp_LineBufSP[i - 16]; \
v = BG_LineBuf[i]; \
\
if (v != 0) { \
_DBL_TR_SUB3() \
ScrBuf##SUFFIX[adr] = (WORD)v; \
} \
} \
}
DWORD adr = VLINE*FULLSCREEN_WIDTH;
DWORD v;
WORD w;
int i;
if (opaq) {
WD_LOOP(16, TextDotX + 16, _DBL_TR_SUB);
} else {
WD_LOOP(16, TextDotX + 16, _DBL_TR_SUB2);
}
}
INLINE void WinDraw_DrawPriLine(void)
{
#define _DPL_SUB(SUFFIX) WD_SUB(SUFFIX, Grp_LineBufSP[i])
DWORD adr = VLINE*FULLSCREEN_WIDTH;
WORD w;
int i;
WD_LOOP(0, TextDotX, _DPL_SUB);
}
void WinDraw_DrawLine(void)
{
int opaq, ton=0, gon=0, bgon=0, tron=0, pron=0, tdrawed=0;
if (!TextDirtyLine[VLINE]) return;
TextDirtyLine[VLINE] = 0;
Draw_DrawFlag = 1;
if (Debug_Grp)
{
switch(VCReg0[1]&3)
{
case 0: // 16 colors
if (VCReg0[1]&4) // 1024dot
{
if (VCReg2[1]&0x10)
{
if ( (VCReg2[0]&0x14)==0x14 )
{
Grp_DrawLine4hSP();
pron = tron = 1;
}
else
{
Grp_DrawLine4h();
gon=1;
}
}
}
else // 512dot
{
if ( (VCReg2[0]&0x10)&&(VCReg2[1]&1) )
{
Grp_DrawLine4SP((VCReg1[1] )&3/*, 1*/); // 半透明の下準備
pron = tron = 1;
}
opaq = 1;
if (VCReg2[1]&8)
{
Grp_DrawLine4((VCReg1[1]>>6)&3, 1);
opaq = 0;
gon=1;
}
if (VCReg2[1]&4)
{
Grp_DrawLine4((VCReg1[1]>>4)&3, opaq);
opaq = 0;
gon=1;
}
if (VCReg2[1]&2)
{
if ( ((VCReg2[0]&0x1e)==0x1e)&&(tron) )
Grp_DrawLine4TR((VCReg1[1]>>2)&3, opaq);
else
Grp_DrawLine4((VCReg1[1]>>2)&3, opaq);
opaq = 0;
gon=1;
}
if (VCReg2[1]&1)
{
// if ( (VCReg2[0]&0x1e)==0x1e )
// {
// Grp_DrawLine4SP((VCReg1[1] )&3, opaq);
// tron = pron = 1;
// }
// else
if ( (VCReg2[0]&0x14)!=0x14 )
{
Grp_DrawLine4((VCReg1[1] )&3, opaq);
gon=1;
}
}
}
break;
case 1:
case 2:
opaq = 1; // 256 colors
if ( (VCReg1[1]&3) <= ((VCReg1[1]>>4)&3) ) // 同じ値の時は、GRP0が優先(ドラスピ)
{
if ( (VCReg2[0]&0x10)&&(VCReg2[1]&1) )
{
Grp_DrawLine8SP(0); // 半透明の下準備
tron = pron = 1;
}
if (VCReg2[1]&4)
{
if ( ((VCReg2[0]&0x1e)==0x1e)&&(tron) )
Grp_DrawLine8TR(1, 1);
else
Grp_DrawLine8(1, 1);
opaq = 0;
gon=1;
}
if (VCReg2[1]&1)
{
if ( (VCReg2[0]&0x14)!=0x14 )
{
Grp_DrawLine8(0, opaq);
gon=1;
}
}
}
else
{
if ( (VCReg2[0]&0x10)&&(VCReg2[1]&1) )
{
Grp_DrawLine8SP(1); // 半透明の下準備
tron = pron = 1;
}
if (VCReg2[1]&4)
{
if ( ((VCReg2[0]&0x1e)==0x1e)&&(tron) )
Grp_DrawLine8TR(0, 1);
else
Grp_DrawLine8(0, 1);
opaq = 0;
gon=1;
}
if (VCReg2[1]&1)
{
if ( (VCReg2[0]&0x14)!=0x14 )
{
Grp_DrawLine8(1, opaq);
gon=1;
}
}
}
break;
case 3: // 65536 colors
if (VCReg2[1]&15)
{
if ( (VCReg2[0]&0x14)==0x14 )
{
Grp_DrawLine16SP();
tron = pron = 1;
}
else
{
Grp_DrawLine16();
gon=1;
}
}
break;
}
}
// if ( ( ((VCReg1[0]&0x30)>>4) < (VCReg1[0]&0x03) ) && (gon) )
// gdrawed = 1; // GrpよりBGの方が上
if ( ((VCReg1[0]&0x30)>>2) < (VCReg1[0]&0x0c) )
{ // BGの方が上
if ((VCReg2[1]&0x20)&&(Debug_Text))
{
Text_DrawLine(1);
ton = 1;
}
else
ZeroMemory(Text_TrFlag, TextDotX+16);
if ((VCReg2[1]&0x40)&&(BG_Regs[8]&2)&&(!(BG_Regs[0x11]&2))&&(Debug_Sp))
{
int s1, s2;
s1 = (((BG_Regs[0x11] &4)?2:1)-((BG_Regs[0x11] &16)?1:0));
s2 = (((CRTC_Regs[0x29]&4)?2:1)-((CRTC_Regs[0x29]&16)?1:0));
VLINEBG = VLINE;
VLINEBG <<= s1;
VLINEBG >>= s2;
if ( !(BG_Regs[0x11]&16) ) VLINEBG -= ((BG_Regs[0x0f]>>s1)-(CRTC_Regs[0x0d]>>s2));
BG_DrawLine(!ton, 0);
bgon = 1;
}
}
else
{ // Textの方が上
if ((VCReg2[1]&0x40)&&(BG_Regs[8]&2)&&(!(BG_Regs[0x11]&2))&&(Debug_Sp))
{
int s1, s2;
s1 = (((BG_Regs[0x11] &4)?2:1)-((BG_Regs[0x11] &16)?1:0));
s2 = (((CRTC_Regs[0x29]&4)?2:1)-((CRTC_Regs[0x29]&16)?1:0));
VLINEBG = VLINE;
VLINEBG <<= s1;
VLINEBG >>= s2;
if ( !(BG_Regs[0x11]&16) ) VLINEBG -= ((BG_Regs[0x0f]>>s1)-(CRTC_Regs[0x0d]>>s2));
ZeroMemory(Text_TrFlag, TextDotX+16);
BG_DrawLine(1, 1);
bgon = 1;
}
else
{
if ((VCReg2[1]&0x20)&&(Debug_Text))
{
int i;
for (i = 16; i < TextDotX + 16; ++i)
BG_LineBuf[i] = TextPal[0];
} else { // 20010120 (琥珀色)
bzero(&BG_LineBuf[16], TextDotX * 2);
}
ZeroMemory(Text_TrFlag, TextDotX+16);
bgon = 1;
}
if ((VCReg2[1]&0x20)&&(Debug_Text))
{
Text_DrawLine(!bgon);
ton = 1;
}
}
opaq = 1;
#if 0
// Pri = 3(違反)に設定されている画面を表示
if ( ((VCReg1[0]&0x30)==0x30)&&(bgon) )
{
if ( ((VCReg2[0]&0x5d)==0x1d)&&((VCReg1[0]&0x03)!=0x03)&&(tron) )
{
if ( (VCReg1[0]&3)<((VCReg1[0]>>2)&3) )
{
WinDraw_DrawBGLineTR(opaq);
tdrawed = 1;
opaq = 0;
}
}
else
{
WinDraw_DrawBGLine(opaq, /*tdrawed*/0);
tdrawed = 1;
opaq = 0;
}
}
if ( ((VCReg1[0]&0x0c)==0x0c)&&(ton) )
{
if ( ((VCReg2[0]&0x5d)==0x1d)&&((VCReg1[0]&0x03)!=0x0c)&&(tron) )
WinDraw_DrawTextLineTR(opaq);
else
WinDraw_DrawTextLine(opaq, /*tdrawed*/((VCReg1[0]&0x30)==0x30));
opaq = 0;
tdrawed = 1;
}
#endif
// Pri = 2 or 3(最下位)に設定されている画面を表示
// プライオリティが同じ場合は、GRP<SP<TEXT?(ドラスピ、桃伝、YsIII等)
// GrpよりTextが上にある場合にTextとの半透明を行うと、SPのプライオリティも
// Textに引きずられる?(つまり、Grpより下にあってもSPが表示される?)
// KnightArmsとかを見ると、半透明のベースプレーンは一番上になるみたい…。
if ( (VCReg1[0]&0x02) )
{
if (gon)
{
WinDraw_DrawGrpLine(opaq);
opaq = 0;
}
if (tron)
{
WinDraw_DrawGrpLineNonSP(opaq);
opaq = 0;
}
}
if ( (VCReg1[0]&0x20)&&(bgon) )
{
if ( ((VCReg2[0]&0x5d)==0x1d)&&((VCReg1[0]&0x03)!=0x02)&&(tron) )
{
if ( (VCReg1[0]&3)<((VCReg1[0]>>2)&3) )
{
WinDraw_DrawBGLineTR(opaq);
tdrawed = 1;
opaq = 0;
}
}
else
{
WinDraw_DrawBGLine(opaq, /*0*/tdrawed);
tdrawed = 1;
opaq = 0;
}
}
if ( (VCReg1[0]&0x08)&&(ton) )
{
if ( ((VCReg2[0]&0x5d)==0x1d)&&((VCReg1[0]&0x03)!=0x02)&&(tron) )
WinDraw_DrawTextLineTR(opaq);
else
WinDraw_DrawTextLine(opaq, tdrawed/*((VCReg1[0]&0x30)>=0x20)*/);
opaq = 0;
tdrawed = 1;
}
// Pri = 1(2番目)に設定されている画面を表示
if ( ((VCReg1[0]&0x03)==0x01)&&(gon) )
{
WinDraw_DrawGrpLine(opaq);
opaq = 0;
}
if ( ((VCReg1[0]&0x30)==0x10)&&(bgon) )
{
if ( ((VCReg2[0]&0x5d)==0x1d)&&(!(VCReg1[0]&0x03))&&(tron) )
{
if ( (VCReg1[0]&3)<((VCReg1[0]>>2)&3) )
{
WinDraw_DrawBGLineTR(opaq);
tdrawed = 1;
opaq = 0;
}
}
else
{
WinDraw_DrawBGLine(opaq, ((VCReg1[0]&0xc)==0x8));
tdrawed = 1;
opaq = 0;
}
}
if ( ((VCReg1[0]&0x0c)==0x04) && ((VCReg2[0]&0x5d)==0x1d) && (VCReg1[0]&0x03) && (((VCReg1[0]>>4)&3)>(VCReg1[0]&3)) && (bgon) && (tron) )
{
WinDraw_DrawBGLineTR(opaq);
tdrawed = 1;
opaq = 0;
if (tron)
{
WinDraw_DrawGrpLineNonSP(opaq);
}
}
else if ( ((VCReg1[0]&0x03)==0x01)&&(tron)&&(gon)&&(VCReg2[0]&0x10) )
{
WinDraw_DrawGrpLineNonSP(opaq);
opaq = 0;
}
if ( ((VCReg1[0]&0x0c)==0x04)&&(ton) )
{
if ( ((VCReg2[0]&0x5d)==0x1d)&&(!(VCReg1[0]&0x03))&&(tron) )
WinDraw_DrawTextLineTR(opaq);
else
WinDraw_DrawTextLine(opaq, ((VCReg1[0]&0x30)>=0x10));
opaq = 0;
tdrawed = 1;
}
// Pri = 0(最優先)に設定されている画面を表示
if ( (!(VCReg1[0]&0x03))&&(gon) )
{
WinDraw_DrawGrpLine(opaq);
opaq = 0;
}
if ( (!(VCReg1[0]&0x30))&&(bgon) )
{
WinDraw_DrawBGLine(opaq, /*tdrawed*/((VCReg1[0]&0xc)>=0x4));
tdrawed = 1;
opaq = 0;
}
if ( (!(VCReg1[0]&0x0c)) && ((VCReg2[0]&0x5d)==0x1d) && (((VCReg1[0]>>4)&3)>(VCReg1[0]&3)) && (bgon) && (tron) )
{
WinDraw_DrawBGLineTR(opaq);
tdrawed = 1;
opaq = 0;
if (tron)
{
WinDraw_DrawGrpLineNonSP(opaq);
}
}
else if ( (!(VCReg1[0]&0x03))&&(tron)&&(VCReg2[0]&0x10) )
{
WinDraw_DrawGrpLineNonSP(opaq);
opaq = 0;
}
if ( (!(VCReg1[0]&0x0c))&&(ton) )
{
WinDraw_DrawTextLine(opaq, 1);
tdrawed = 1;
opaq = 0;
}
// 特殊プライオリティ時のグラフィック
if ( ((VCReg2[0]&0x5c)==0x14)&&(pron) ) // 特殊Pri時は、対象プレーンビットは意味が無いらしい(ついんびー)
{
WinDraw_DrawPriLine();
}
else if ( ((VCReg2[0]&0x5d)==0x1c)&&(tron) ) // 半透明時に全てが透明なドットをハーフカラーで埋める
{ // (AQUALES)
#define _DL_SUB(SUFFIX) \
{ \
w = Grp_LineBufSP[i]; \
if (w != 0 && (ScrBuf##SUFFIX[adr] & 0xffff) == 0) \
ScrBuf##SUFFIX[adr] = (w & Pal_HalfMask) >> 1; \
}
DWORD adr = VLINE*FULLSCREEN_WIDTH;
WORD w;
int i;
WD_LOOP(0, TextDotX, _DL_SUB);
}
if (opaq)
{
DWORD adr = VLINE*FULLSCREEN_WIDTH;
#ifdef PSP
if (TextDotX > 512) {
bzero(&ScrBufL[adr], TextDotX * 2);
adr = VLINE * 256;
bzero(&ScrBufR[adr], (TextDotX - 512) * 2);
} else {
bzero(&ScrBufL[adr], TextDotX * 2);
}
#else
bzero(&ScrBuf[adr], TextDotX * 2);
#endif
}
}
/********** menu 関連ルーチン **********/
struct _px68k_menu {
WORD *sbp; // surface buffer ptr
WORD *mlp; // menu locate ptr
WORD mcolor; // color of chars to write
WORD mbcolor; // back ground color of chars to write
int ml_x;
int ml_y;
int mfs; // menu font size;
} p6m;
#if !defined(PSP) && !defined(USE_OGLES11)
SDL_Surface *menu_surface;
#endif
// 画面タイプを変更する
enum ScrType {x68k, pc98};
int scr_type = x68k;
/* sjis→jisコード変換 */
static WORD sjis2jis(WORD w)
{
BYTE wh, wl;
wh = w / 256, wl = w % 256;
wh <<= 1;
if (wl < 0x9f) {
wh += (wh < 0x3f)? 0x1f : -0x61;
wl -= (wl > 0x7e)? 0x20 : 0x1f;
} else {
wh += (wh < 0x3f)? 0x20 : -0x60;
wl -= 0x7e;
}
return (wh * 256 + wl);
}
/* JISコードから0 originのindexに変換する */
/* ただし0x2921-0x2f7eはX68KのROM上にないので飛ばす */
static WORD jis2idx(WORD jc)
{
if (jc >= 0x3000) {
jc -= 0x3021;
} else {
jc -= 0x2121;
}
jc = jc % 256 + (jc / 256) * 0x5e;
return jc;
}
#define isHankaku(s) ((s) >= 0x20 && (s) <= 0x7e || (s) >= 0xa0 && (s) <= 0xdf)
#if defined(PSP)
// display width 480, buffer width 512
#define MENU_WIDTH 512
#elif defined(ANDROID)
// display width 800, buffer width 1024 だけれど 800 にしないとだめ
#define MENU_WIDTH 800
#else
#define MENU_WIDTH 800
#endif
// fs : font size : 16 or 24
// 半角文字の場合は16bitの上位8bitにデータを入れておくこと
// (半角or全角の判断ができるように)
static DWORD get_font_addr(WORD sjis, int fs)
{
WORD jis, j_idx;
BYTE jhi;
int fsb; // file size in bytes
// 半角文字
if (isHankaku(sjis >> 8)) {
switch (fs) {
case 8:
return (0x3a000 + (sjis >> 8) * (1 * 8));
case 16:
return (0x3a800 + (sjis >> 8) * (1 * 16));
case 24:
return (0x3d000 + (sjis >> 8) * (2 * 24));
default:
return -1;
}
}
// 全角文字
if (fs == 16) {
fsb = 2 * 16;
} else if (fs == 24) {
fsb = 3 * 24;
} else {
return -1;
}
jis = sjis2jis(sjis);
j_idx = (DWORD)jis2idx(jis);
jhi = (BYTE)(jis >> 8);
#if 0
printf("sjis code = 0x%x\n", sjis);
printf("jis code = 0x%x\n", jis);
printf("jhi 0x%x j_idx 0x%x\n", jhi, j_idx);
#endif
if (jhi >= 0x21 && jhi <= 0x28) {
// 非漢字
return ((fs == 16)? 0x0 : 0x40000) + j_idx * fsb;
} else if (jhi >= 0x30 && jhi <= 0x74) {
// 第一水準/第二水準
return ((fs == 16)? 0x5e00 : 0x4d380) + j_idx * fsb;
} else {
// ここにくることはないはず
return -1;
}
}
// RGB565
static void set_mcolor(WORD c)
{
p6m.mcolor = c;
}
// mbcolor = 0 なら透明色とする
static void set_mbcolor(WORD c)
{
p6m.mbcolor = c;
}
// グラフィック座標
static void set_mlocate(int x, int y)
{
p6m.ml_x = x, p6m.ml_y = y;
}
// キャラクタ文字の座標 (横軸は1座標が半角文字幅になる)
static void set_mlocateC(int x, int y)
{
p6m.ml_x = x * p6m.mfs / 2, p6m.ml_y = y * p6m.mfs;
}
static void set_sbp(WORD *p)
{
p6m.sbp = p;
}
// menu font size (16 or 24)
static void set_mfs(int fs)
{
p6m.mfs = fs;
}
static WORD *get_ml_ptr()
{
p6m.mlp = p6m.sbp + MENU_WIDTH * p6m.ml_y + p6m.ml_x;
return p6m.mlp;
}
// ・半角文字の場合は16bitの上位8bitにデータを入れておくこと
// (半角or全角の判断ができるように)
// ・表示した分cursorは先に移動する
static void draw_char(WORD sjis)
{
DWORD f;
WORD *p;
int i, j, k, wc, w;
BYTE c;
WORD bc;
int h = p6m.mfs;
p = get_ml_ptr();
f = get_font_addr(sjis, h);
if (f < 0)
return;
// h=8は半角のみ
w = (h == 8)? 8 : (isHankaku(sjis >> 8)? h / 2 : h);
for (i = 0; i < h; i++) {
wc = w;
for (j = 0; j < ((w % 8 == 0)? w / 8 : w / 8 + 1); j++) {
c = FONT[f++];
for (k = 0; k < 8 ; k++) {
bc = p6m.mbcolor? p6m.mbcolor : *p;
*p = (c & 0x80)? p6m.mcolor : bc;
p++;
c = c << 1;
wc--;
if (wc == 0)
break;
}
}
p = p + MENU_WIDTH - w;
}
p6m.ml_x += w;
}
static void draw_str(char *cp)
{
int i, len;
BYTE *s;
WORD wc;
len = strlen(cp);
s = (BYTE *)cp;
for (i = 0; i < len; i++) {
if (isHankaku(*s)) {
// 最初の8bitで半全角を判断するので半角の場合は
// あらかじめ8bit左シフトしておく
draw_char((WORD)*s << 8);
s++;
} else {
wc = (WORD)(*s << 8) + *(s + 1);
draw_char(wc);
s += 2;
i++;
}
// 8x8描画(ソフトキーボードのFUNCキーは文字幅を縮める)
if (p6m.mfs == 8) {
p6m.ml_x -= 3;
}
}
}
int WinDraw_MenuInit(void)
{
#if defined(PSP)
// menuは速度遅くて良いのでメインメモリからmalloc()
menu_buffer = malloc(512 * 512 * 2);
if (menu_buffer == NULL) {
return FALSE;
}
set_sbp(menu_buffer);
// 使用フォントの変更 24 or 16
set_mfs(16);
#elif defined(USE_OGLES11)
//
menu_buffer = malloc(1024 * 1024 * 2);
if (menu_buffer == NULL) {
return FALSE;
}
set_sbp(menu_buffer);
set_mfs(24);
#else
#if SDL_VERSION_ATLEAST(2, 0, 0)
menu_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 800, 600, 16, WinDraw_Pal16R, WinDraw_Pal16G, WinDraw_Pal16B, 0);
#else
menu_surface = SDL_GetVideoSurface();
#endif
if (!menu_surface)
return FALSE;
set_sbp((WORD *)(menu_surface->pixels));
set_mfs(24);
#endif
set_mcolor(0xffff);
set_mbcolor(0);
return TRUE;
}
#include "menu_str_sjis.txt"
#ifdef PSP
static void psp_draw_menu(void)
{
sceKernelDcacheWritebackAll();
sceGuStart(GU_DIRECT, list);
sceGuClearColor(0);
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
// 左半分
vtxm->u = 0;
vtxm->v = 0;
vtxm->color = 0;
vtxm->x = 0;
vtxm->y = 0;
vtxm->z = 0;
vtxm->u2 = 480;
vtxm->v2 = 272;
vtxm->color2 = 0;
vtxm->x2 = 480;
vtxm->y2 = 272;
vtxm->z2 = 0;
sceGuTexMode(GU_PSM_5650, 0, 0, 0);
sceGuTexImage(0, 512, 512, 512, menu_buffer);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
//sceGuTexFilter(GU_LINEAR, GU_LINEAR);
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_16BIT|GU_COLOR_5650|GU_VERTEX_16BIT|GU_TRANSFORM_2D, 2, 0, vtxm);
sceGuFinish();
sceGuSync(0, 0);
sceGuSwapBuffers();
}
#endif
#ifdef USE_OGLES11
static void ogles11_draw_menu(void)
{
GLfloat texture_coordinates[8];
GLfloat vertices[8];
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBindTexture(GL_TEXTURE_2D, texid[9]);
//ScrBufから800x600の領域を切り出してテクスチャに転送
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 800, 600, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, menu_buffer);
// Texture から必要な部分を抜き出す
// Texutre座標は0.0fから1.0fの間
SET_GLFLOATS(texture_coordinates,
0.0f, (GLfloat)600/1024,
0.0f, 0.0f,
(GLfloat)800/1024, (GLfloat)600/1024,
(GLfloat)800/1024, 0.0f);
// 実機の解像度(realdisp_w x realdisp_h)に関係なく、
// 座標は800x600
SET_GLFLOATS(vertices,
40.0f, (GLfloat)600,
40.0f, 0.0f,
(GLfloat)800, (GLfloat)600,
(GLfloat)800, 0.0f);
draw_texture(texture_coordinates, vertices);
draw_all_buttons(texture_coordinates, vertices, (GLfloat)WinUI_get_vkscale(), 1);
SDL_GL_SwapWindow(sdl_window);
}
#endif
void WinDraw_DrawMenu(int menu_state, int mkey_pos, int mkey_y, int *mval_y)
{
int i, drv;
char tmp[256];
// ソフトウェアキーボード描画時にset_sbp(kbd_buffer)されているので戻す
#if defined(PSP) || defined(USE_OGLES11)
set_sbp(menu_buffer);
#endif
// ソフトウェアキーボード描画時にset_mfs(16)されているので戻す
#if defined(ANDROID) || TARGET_OS_IPHONE
set_mfs(24);
#endif
// タイトル
if (scr_type == x68k) {
set_mcolor(0x07ff); // cyan
set_mlocateC(0, 0);
draw_str(twaku_str);
set_mlocateC(0, 1);
draw_str(twaku2_str);
set_mlocateC(0, 2);
draw_str(twaku3_str);
set_mcolor(0xffff);
set_mlocateC(1, 1);
sprintf(tmp, "%s%s", title_str, PX68KVERSTR);
draw_str(tmp);
} else {
set_mcolor(0xffff);
set_mlocateC(0, 0);
sprintf(tmp, "%s%s", pc98_title1_str, PX68KVERSTR);
draw_str(tmp);
set_mlocateC(0, 2);
draw_str(pc98_title3_str);
set_mcolor(0x07ff);
set_mlocateC(0, 1);
draw_str(pc98_title2_str);
}
// 真ん中
if (scr_type == x68k) {
set_mcolor(0xffff);
set_mlocate(3 * p6m.mfs / 2, 3.5 * p6m.mfs);
draw_str(waku_val_str[0]);
set_mlocate(17 * p6m.mfs / 2, 3.5 * p6m.mfs);
draw_str(waku_val_str[1]);
// 真ん中枠
set_mcolor(0xffe0); // yellow
set_mlocateC(1, 4);
draw_str(waku_str);
for (i = 5; i < 12; i++) {
set_mlocateC(1, i);
draw_str(waku2_str);
}
set_mlocateC(1, 12);
draw_str(waku3_str);
}
// アイテム/キーワード
set_mcolor(0xffff);
for (i = 0; i < 7; i++) {
set_mlocateC(3, 5 + i);
if (menu_state == ms_key && i == (mkey_y - mkey_pos)) {
set_mcolor(0x0);
set_mbcolor(0xffe0); // yellow);
} else {
set_mcolor(0xffff);
set_mbcolor(0x0);
}
draw_str(menu_item_key[i + mkey_pos]);
}
// アイテム/現在値
set_mcolor(0xffff);
set_mbcolor(0x0);
for (i = 0; i < 7; i++) {
if ((menu_state == ms_value || menu_state == ms_hwjoy_set)
&& i == (mkey_y - mkey_pos)) {
set_mcolor(0x0);
set_mbcolor(0xffe0); // yellow);
} else {
set_mcolor(0xffff);
set_mbcolor(0x0);
}
if (scr_type == x68k) {
set_mlocateC(17, 5 + i);
} else {
set_mlocateC(25, 5 + i);
}
drv = WinUI_get_drv_num(i + mkey_pos);
if (drv >= 0 && mval_y[i + mkey_pos] == 0) {
char *p;
if (drv < 2) {
p = Config.FDDImage[drv];
} else {
p = Config.HDImage[drv - 2];
}
if (p[0] == '\0') {
draw_str(" -- no disk --");
} else {
// 先頭のカレントディレクトリ名を表示しない
if (!strncmp(cur_dir_str, p, cur_dir_slen)) {
draw_str(p + cur_dir_slen);
} else {
draw_str(p);
}
}
} else {
draw_str(menu_items[i + mkey_pos][mval_y[i + mkey_pos]]);
}
}
if (scr_type == x68k) {
// 下枠
set_mcolor(0x07ff); // cyan
set_mbcolor(0x0);
set_mlocateC(0, 13);
draw_str(swaku_str);
set_mlocateC(0, 14);
draw_str(swaku2_str);
set_mlocateC(0, 15);
draw_str(swaku2_str);
set_mlocateC(0, 16);
draw_str(swaku3_str);
}
// キャプション
set_mcolor(0xffff);
set_mbcolor(0x0);
set_mlocateC(2, 14);
draw_str(item_cap[mkey_y]);
if (menu_state == ms_value) {
set_mlocateC(2, 15);
draw_str(item_cap2[mkey_y]);
}
#if defined(PSP)
psp_draw_menu();
#elif defined(USE_OGLES11)
ogles11_draw_menu();
#else
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Surface *sdl_surface;
sdl_surface = SDL_GetWindowSurface(sdl_window);
SDL_BlitSurface(menu_surface, NULL, sdl_surface, NULL);
SDL_UpdateWindowSurface(sdl_window);
#else
SDL_UpdateRect(menu_surface, 0, 0, FULLSCREEN_WIDTH, FULLSCREEN_HEIGHT);
#endif
#endif
}
void WinDraw_DrawMenufile(struct menu_flist *mfl)
{
int i;
// 下枠
//set_mcolor(0xf800); // red
//set_mcolor(0xf81f); // magenta
set_mcolor(0xffff);
set_mbcolor(0x1); // 0x0だと透過モード
set_mlocateC(1, 1);
draw_str(swaku_str);
for (i = 2; i < 16; i++) {
set_mlocateC(1, i);
draw_str(swaku2_str);
}
set_mlocateC(1, 16);
draw_str(swaku3_str);
for (i = 0; i < 14; i++) {
if (i + 1 > mfl->num) {
break;
}
if (i == mfl->y) {
set_mcolor(0x0);
set_mbcolor(0xffff);
} else {
set_mcolor(0xffff);
set_mbcolor(0x1);
}
// ディレクトリだったらファイル名を[]で囲う
set_mlocateC(3, i + 2);
if (mfl->type[i + mfl->ptr]) draw_str("[");
draw_str(mfl->name[i + mfl->ptr]);
if (mfl->type[i + mfl->ptr]) draw_str("]");
}
set_mbcolor(0x0); // 透過モードに戻しておく
#if defined(PSP)
psp_draw_menu();
#elif defined(USE_OGLES11)
ogles11_draw_menu();
#else
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Surface *sdl_surface;
sdl_surface = SDL_GetWindowSurface(sdl_window);
SDL_BlitSurface(menu_surface, NULL, sdl_surface, NULL);
SDL_UpdateWindowSurface(sdl_window);
#else
SDL_UpdateRect(menu_surface, 0, 0, FULLSCREEN_WIDTH, FULLSCREEN_HEIGHT);
#endif
#endif
}
void WinDraw_ClearMenuBuffer(void)
{
#if defined(PSP)
memset(menu_buffer, 0, 512*272*2);
#elif defined(USE_OGLES11)
memset(menu_buffer, 0, 800*600*2);
#else
SDL_FillRect(menu_surface, NULL, 0);
#endif
}
/********** ソフトウェアキーボード描画 **********/
#if defined(PSP) || defined(USE_OGLES11)
#if defined(PSP)
// display width 480, buffer width 512
#define KBDBUF_WIDTH 512
#elif defined(USE_OGLES11)
// display width 800, buffer width 1024 だけれど 800 にしないとだめ
#define KBDBUF_WIDTH 800
#endif
#define KBD_FS 16 // keyboard font size : 16
// キーを反転する
void WinDraw_reverse_key(int x, int y)
{
WORD *p;
int kp;
int i, j;
kp = Keyboard_get_key_ptr(kbd_kx, kbd_ky);
p = kbd_buffer + KBDBUF_WIDTH * kbd_key[kp].y + kbd_key[kp].x;
for (i = 0; i < kbd_key[kp].h; i++) {
for (j = 0; j < kbd_key[kp].w; j++) {
*p = ~(*p);
p++;
}
p = p + KBDBUF_WIDTH - kbd_key[kp].w;
}
}
static void draw_kbd_to_tex()
{
int i, x, y;
WORD *p;
// SJIS 漢字コード
char zen[] = {0x91, 0x53, 0x00};
char larw[] = {0x81, 0xa9, 0x00};
char rarw[] = {0x81, 0xa8, 0x00};
char uarw[] = {0x81, 0xaa, 0x00};
char darw[] = {0x81, 0xab, 0x00};
char ka[] = {0x82, 0xa9, 0x00};
char ro[] = {0x83, 0x8d, 0x00};
char ko[] = {0x83, 0x52, 0x00};
char ki[] = {0x8b, 0x4c, 0x00};
char to[] = {0x93, 0x6f, 0x00};
char hi[] = {0x82, 0xd0, 0x00};
kbd_key[12].s = ka;
kbd_key[13].s = ro;
kbd_key[14].s = ko;
kbd_key[16].s = ki;
kbd_key[17].s = to;
kbd_key[76].s = uarw;
kbd_key[94].s = larw;
kbd_key[95].s = darw;
kbd_key[96].s = rarw;
kbd_key[101].s = hi;
kbd_key[108].s = zen;
#ifdef PSP
kbd_key[0].s = "BK";
kbd_key[1].s = "CP";
kbd_key[15].s = "CA";
kbd_key[18].s = "HP";
kbd_key[19].s = "EC";
kbd_key[34].s = "HM";
kbd_key[35].s = "IN";
kbd_key[36].s = "DL";
kbd_key[37].s = "CL";
kbd_key[55].s = "";
kbd_key[56].s = "RU";
kbd_key[57].s = "RD";
kbd_key[58].s = "UD";
kbd_key[63].s = "CTR";
kbd_key[81].s = "";
kbd_key[93].s = "";
kbd_key[100].s = "";
kbd_key[102].s = "X1";
kbd_key[103].s = "X2";
kbd_key[105].s = "X3";
kbd_key[106].s = "X4";
kbd_key[107].s = "X5";
kbd_key[109].s = "OP1";
kbd_key[110].s = "OP2";
#endif
set_sbp(kbd_buffer);
set_mfs(KBD_FS);
set_mbcolor(0);
set_mcolor(0);
// キーボードの背景
p = kbd_buffer;
for (y = 0; y < kbd_h; y++) {
for (x = 0; x < kbd_w; x++) {
*p++ = (0x7800 | 0x03e0 | 0x000f);
}
p = p + KBDBUF_WIDTH - kbd_w;
}
// キーの描画
for (i = 0; kbd_key[i].x != -1; i++) {
p = kbd_buffer + kbd_key[i].y * KBDBUF_WIDTH + kbd_key[i].x;
for (y = 0; y < kbd_key[i].h; y++) {
for (x = 0; x < kbd_key[i].w; x++) {
if (x == (kbd_key[i].w - 1)
|| y == (kbd_key[i].h - 1)) {
// キーに影をつけ立体的に見せる
*p++ = 0x0000;
} else {
*p++ = 0xffff;
}
}
p = p + KBDBUF_WIDTH - kbd_key[i].w;
}
if (strlen(kbd_key[i].s) == 3 && *(kbd_key[i].s) == 'F') {
// FUNCキー刻印描画
set_mlocate(kbd_key[i].x + kbd_key[i].w / 2
- strlen(kbd_key[i].s) * (8 / 2)
+ (strlen(kbd_key[i].s) - 1) * 3 / 2,
kbd_key[i].y + kbd_key[i].h / 2 - 8 / 2);
set_mfs(8);
draw_str(kbd_key[i].s);
set_mfs(KBD_FS);
} else {
// 刻印は上下左右ともセンタリングする
set_mlocate(kbd_key[i].x + kbd_key[i].w / 2
- strlen(kbd_key[i].s) * (KBD_FS / 2 / 2),
kbd_key[i].y
+ kbd_key[i].h / 2 - KBD_FS / 2);
draw_str(kbd_key[i].s);
}
}
WinDraw_reverse_key(kbd_kx, kbd_ky);
}
#endif