diff --git a/360/file_browser.c b/360/file_browser.c index 3254db7e05..716a9c4c47 100644 --- a/360/file_browser.c +++ b/360/file_browser.c @@ -32,7 +32,7 @@ static const char * filebrowser_get_extension(const char * filename) void filebrowser_parse_directory(filebrowser_t * filebrowser, const char * path, const char *extensions) { - BOOL error = FALSE; + int error = FALSE; filebrowser->file_count = 0; WIN32_FIND_DATA ffd; diff --git a/360/main.c b/360/main.c index c5c9544a94..d0e393bd62 100644 --- a/360/main.c +++ b/360/main.c @@ -235,7 +235,7 @@ static void get_environment_settings (void) Mounted[DEVICE_MEMORY_ONBOARD] = Mount(DEVICE_MEMORY_ONBOARD,"OnBoardMU:"); Mounted[DEVICE_CDROM0] = Mount(DEVICE_CDROM0,"Dvd:"); - BOOL result_filecache = XSetFileCacheSize(0x100000); + int result_filecache = XSetFileCacheSize(0x100000); if(result_filecache != TRUE) { diff --git a/360/media/Arial_12.abc b/360/media/Arial_12.abc new file mode 100644 index 0000000000..f24f2f135a Binary files /dev/null and b/360/media/Arial_12.abc differ diff --git a/360/media/Arial_12.rdf b/360/media/Arial_12.rdf new file mode 100644 index 0000000000..8321cbd73a --- /dev/null +++ b/360/media/Arial_12.rdf @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/360/media/Arial_12.tga b/360/media/Arial_12.tga new file mode 100644 index 0000000000..e9061f54b0 Binary files /dev/null and b/360/media/Arial_12.tga differ diff --git a/360/menu.cpp b/360/menu.cpp index 73322d9268..8df3905298 100644 --- a/360/menu.cpp +++ b/360/menu.cpp @@ -55,7 +55,7 @@ static void filebrowser_fetch_directory_entries(const char *path, CXuiList * rom { filebrowser_parse_directory(&browser, path, ssnes_console_get_rom_ext()); - DWORD dwNum_rompath = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); + unsigned long dwNum_rompath = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); wchar_t * rompath_name = new wchar_t[dwNum_rompath]; MultiByteToWideChar(CP_ACP, 0, path, -1, rompath_name, dwNum_rompath); rompath_title->SetText(rompath_name); @@ -64,7 +64,7 @@ static void filebrowser_fetch_directory_entries(const char *path, CXuiList * rom romlist->InsertItems(0, browser.file_count); for(unsigned i = 0; i < browser.file_count; i++) { - DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, browser.cur[i].d_name, -1, NULL, 0); + unsigned long dwNum = MultiByteToWideChar(CP_ACP, 0, browser.cur[i].d_name, -1, NULL, 0); wchar_t * entry_name = new wchar_t[dwNum]; MultiByteToWideChar(CP_ACP, 0, browser.cur[i].d_name, -1, entry_name, dwNum); romlist->SetText(i, entry_name); @@ -124,8 +124,8 @@ HRESULT CSSNESMain::OnInit(XUIMessageInit * pInitData, BOOL& bHandled) const char * core_text = snes_library_id(); char package_version[32]; sprintf(package_version, "SSNES %s", PACKAGE_VERSION); - DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, core_text, -1, NULL, 0); - DWORD dwNum_package = MultiByteToWideChar(CP_ACP, 0, package_version, -1, NULL, 0); + unsigned long dwNum = MultiByteToWideChar(CP_ACP, 0, core_text, -1, NULL, 0); + unsigned long dwNum_package = MultiByteToWideChar(CP_ACP, 0, package_version, -1, NULL, 0); wchar_t * core_text_utf = new wchar_t[dwNum]; wchar_t * package_version_utf = new wchar_t[dwNum_package]; MultiByteToWideChar(CP_ACP, 0, core_text, -1, core_text_utf, dwNum); @@ -232,9 +232,7 @@ HRESULT CSSNESMain::OnNotifyPress( HXUIOBJ hObjPressed, BOOL& bHandled ) hr = XuiSceneCreate(L"file://game:/media/", L"ssnes_settings.xur", NULL, &app.hSSNESSettings); if (FAILED(hr)) - { SSNES_ERR("Failed to load scene.\n"); - } NavigateForward(app.hSSNESSettings); } diff --git a/360/xdk360_input.cpp b/360/xdk360_input.cpp index 3698fce409..1a9d9b3e9f 100644 --- a/360/xdk360_input.cpp +++ b/360/xdk360_input.cpp @@ -27,7 +27,7 @@ static XINPUT_STATE state[4]; -const int DEADZONE = 16000; +#define DEADZONE (16000) static void xdk360_input_poll(void *data) { diff --git a/360/xdk360_video.cpp b/360/xdk360_video.cpp index 7c38704e28..ecac2019db 100644 --- a/360/xdk360_video.cpp +++ b/360/xdk360_video.cpp @@ -68,8 +68,10 @@ typedef struct DrawVerticeFormats } DrawVerticeFormats; static bool g_quitting; +static bool g_first_msg; unsigned g_frame_count; void *g_d3d; +Console g_screen_console; static void xdk360_gfx_free(void * data) { @@ -273,6 +275,18 @@ static bool xdk360_gfx_frame(void *data, const void *frame, vid->xdk360_render_device->SetStreamSource(0, vid->vertex_buf, 0, sizeof(DrawVerticeFormats)); vid->xdk360_render_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + if (msg) + { + if(IS_TIMER_EXPIRED() || g_first_msg) + { + g_screen_console.Format(true, msg); + g_first_msg = 0; + SET_TIMER_EXPIRATION(60); + } + + g_screen_console.Render(); + } + vid->xdk360_render_device->Present(NULL, NULL, NULL, NULL); return true; @@ -311,6 +325,15 @@ void xdk360_video_init(void) video_info.input_scale = 2; g_d3d = xdk360_gfx_init(&video_info, NULL, NULL); + + g_first_msg = true; + + HRESULT hr = g_screen_console.Create("game:\\media\\Arial_12.xpr", + 0xff000000, 0xffffffff ); + if(FAILED(hr)) + { + SSNES_ERR("Couldn't create debug console.\n"); + } } void xdk360_video_deinit(void) diff --git a/360/xdk360_video.h b/360/xdk360_video.h index 76d010ca18..c1ca81304a 100644 --- a/360/xdk360_video.h +++ b/360/xdk360_video.h @@ -19,25 +19,42 @@ #ifndef _XDK360_VIDEO_H #define _XDK360_VIDEO_H +#include "xdk360_video_console.h" + +typedef struct { + float x; + float y; + float z; + float rhw; + float u; + float v; +} primitive_t; + +#define DFONT_MAX 4096 +#define PRIM_FVF (D3DFVF_XYZRHW | D3DFVF_TEX1) + typedef struct xdk360_video { + unsigned last_width, last_height; IDirect3D9* xdk360_device; IDirect3DDevice9* xdk360_render_device; IDirect3DVertexShader9 *pVertexShader; IDirect3DPixelShader9* pPixelShader; IDirect3DVertexDeclaration9* pVertexDecl; IDirect3DVertexBuffer9* vertex_buf; + IDirect3DTexture9* font_texture; IDirect3DTexture9* lpTexture; - unsigned last_width, last_height; D3DPRESENT_PARAMETERS d3dpp; } xdk360_video_t; -#define IS_TIMER_EXPIRED() (!(g_frame_count < g_console.timer_expiration_frame_count)) +#define IS_TIMER_NOT_EXPIRED() (g_frame_count < g_console.timer_expiration_frame_count) +#define IS_TIMER_EXPIRED() (!(IS_TIMER_NOT_EXPIRED())) #define SET_TIMER_EXPIRATION(value) g_console.timer_expiration_frame_count = g_frame_count + value; void xdk360_video_init(void); void xdk360_video_deinit(void); +extern Console g_screen_console; extern unsigned g_frame_count; extern void *g_d3d; diff --git a/360/xdk360_video_console.cpp b/360/xdk360_video_console.cpp new file mode 100644 index 0000000000..a872f693c5 --- /dev/null +++ b/360/xdk360_video_console.cpp @@ -0,0 +1,273 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#include +#include +#include "xdk360_video.h" +#include "xdk360_video_console.h" +#include "xdk360_video_debugfonts.h" +#include "../general.h" + +Console::Console() +{ + first_message = true; + m_Buffer = NULL; + m_Lines = NULL; + m_nScrollOffset = 0; +} + +Console::~Console() +{ + Destroy(); +} + +HRESULT Console::Create( LPCSTR strFontFileName, D3DCOLOR colBackColor, + D3DCOLOR colTextColor, unsigned int nLines ) +{ + xdk360_video_t *vid = (xdk360_video_t*)g_d3d; + D3DDevice *m_pd3dDevice = vid->xdk360_render_device; + + // Calculate the safe area + unsigned int uiSafeAreaPct = SAFE_AREA_PCT_HDTV; + + m_cxSafeArea = ( vid->d3dpp.BackBufferWidth * uiSafeAreaPct ) / 100; + m_cySafeArea = ( vid->d3dpp.BackBufferHeight * uiSafeAreaPct ) / 100; + + m_cxSafeAreaOffset = ( vid->d3dpp.BackBufferWidth - m_cxSafeArea ) / 2; + m_cySafeAreaOffset = ( vid->d3dpp.BackBufferHeight - m_cySafeArea ) / 2; + + // Create the font + HRESULT hr = m_Font.Create( strFontFileName ); + if( FAILED( hr ) ) + { + SSNES_ERR( "Could not create font.\n" ); + return -1; + } + + // Save the colors + m_colBackColor = colBackColor; + m_colTextColor = colTextColor; + + // Calculate the number of lines on the screen + float fCharWidth, fCharHeight; + m_Font.GetTextExtent( L"i", &fCharWidth, &fCharHeight, FALSE ); + + m_cScreenHeight = (unsigned int)( m_cySafeArea / fCharHeight ); + m_cScreenWidth = (unsigned int)( m_cxSafeArea / fCharWidth ); + + m_cScreenHeightVirtual = max( m_cScreenHeight, nLines ); + + m_fLineHeight = fCharHeight; + + // Allocate memory to hold the lines + m_Buffer = new wchar_t[ m_cScreenHeightVirtual * ( m_cScreenWidth + 1 ) ]; + m_Lines = new wchar_t *[ m_cScreenHeightVirtual ]; + + // Set the line pointers as indexes into the buffer + for( unsigned int i = 0; i < m_cScreenHeightVirtual; i++ ) + m_Lines[ i ] = m_Buffer + ( m_cScreenWidth + 1 ) * i; + + CLEAR_SCREEN(); + + return hr; +} + +//-------------------------------------------------------------------------------------- +// Name: Destroy() +// Desc: Tear everything down +//-------------------------------------------------------------------------------------- +void Console::Destroy() +{ + // Delete the memory we've allocated + if( m_Lines ) + { + delete[] m_Lines; + m_Lines = NULL; + } + + if( m_Buffer ) + { + delete[] m_Buffer; + m_Buffer = NULL; + } + + // Destroy the font + m_Font.Destroy(); +} + + +//-------------------------------------------------------------------------------------- +// Name: Render() +// Desc: Render the console to the screen +//-------------------------------------------------------------------------------------- +void Console::Render() +{ + xdk360_video_t *vid = (xdk360_video_t*)g_d3d; + D3DDevice *m_pd3dDevice = vid->xdk360_render_device; + + // The top line + unsigned int nTextLine = ( m_nCurLine - m_cScreenHeight + m_cScreenHeightVirtual - m_nScrollOffset + 1 ) + % m_cScreenHeightVirtual; + + m_Font.Begin(); + + for( unsigned int nScreenLine = 0; nScreenLine < m_cScreenHeight; nScreenLine++ ) + { + m_Font.DrawText( (float)( m_cxSafeAreaOffset ), + (float)( m_cySafeAreaOffset + m_fLineHeight * nScreenLine ), + m_colTextColor, m_Lines[nTextLine] ); + + nTextLine = ( nTextLine + 1 ) % m_cScreenHeightVirtual; + } + + m_Font.End(); +} + + +//-------------------------------------------------------------------------------------- +// Name: Add( CHAR ) +// Desc: Convert ANSI to WCHAR and add to the current line +//-------------------------------------------------------------------------------------- +void Console::Add( char ch ) +{ + wchar_t wch; + + int ret = MultiByteToWideChar( CP_ACP, // ANSI code page + 0, // No flags + &ch, // Character to convert + 1, // Convert one byte + &wch, // Target wide character buffer + 1 ); // One wide character + + Add( wch ); +} + + + +//-------------------------------------------------------------------------------------- +// Name: Add( WCHAR ) +// Desc: Add a wide character to the current line +//-------------------------------------------------------------------------------------- +void Console::Add( wchar_t wch ) +{ + // If this is a newline, just increment lines and move on + if( wch == L'\n' ) + { + INCREMENT_LINE(); + return; + } + + int bIncrementLine = FALSE; // Whether to wrap to the next line + + if( m_cCurLineLength == m_cScreenWidth ) + bIncrementLine = TRUE; + else + { + // Try to append the character to the line + m_Lines[ m_nCurLine ][ m_cCurLineLength ] = wch; + + if( m_Font.GetTextWidth( m_Lines[ m_nCurLine ] ) > m_cxSafeArea ) + { + // The line is too long, we need to wrap the character to the next line + m_Lines[ m_nCurLine][ m_cCurLineLength ] = L'\0'; + bIncrementLine = TRUE; + } + } + + // If we need to skip to the next line, do so + if( bIncrementLine ) + { + INCREMENT_LINE(); + m_Lines[ m_nCurLine ][0] = wch; + } + + if(IS_TIMER_EXPIRED()) + m_cCurLineLength++; +} + + +//-------------------------------------------------------------------------------------- +// Name: Format() +// Desc: Output a variable argument list using a format string +//-------------------------------------------------------------------------------------- +void Console::Format(int clear_screen, _In_z_ _Printf_format_string_ LPCSTR strFormat, ... ) +{ + if(clear_screen) + { + CLEAR_SCREEN(); + } + + va_list pArgList; + va_start( pArgList, strFormat ); + FormatV( strFormat, pArgList ); + va_end( pArgList ); + + // Render the output + Render(); +} + +void Console::Format(int clear_screen, _In_z_ _Printf_format_string_ LPCWSTR wstrFormat, ... ) +{ + if(clear_screen) + { + CLEAR_SCREEN(); + } + + va_list pArgList; + va_start( pArgList, wstrFormat ); + FormatV( wstrFormat, pArgList ); + va_end( pArgList ); + + // Render the output + Render(); +} + + +//-------------------------------------------------------------------------------------- +// Name: FormatV() +// Desc: Output a va_list using a format string +//-------------------------------------------------------------------------------------- +void Console::FormatV( _In_z_ _Printf_format_string_ LPCSTR strFormat, va_list pArgList ) +{ + // Count the required length of the string + unsigned long dwStrLen = _vscprintf( strFormat, pArgList ) + 1; // +1 = null terminator + char * strMessage = ( char * )_malloca( dwStrLen ); + vsprintf_s( strMessage, dwStrLen, strFormat, pArgList ); + + // Output the string to the console + unsigned long uStringLength = strlen( strMessage ); + for( unsigned long i = 0; i < uStringLength; i++ ) + Add( strMessage[i] ); + + _freea( strMessage ); +} + +void Console::FormatV( _In_z_ _Printf_format_string_ LPCWSTR wstrFormat, va_list pArgList ) +{ + // Count the required length of the string + unsigned long dwStrLen = _vscwprintf( wstrFormat, pArgList ) + 1; // +1 = null terminator + wchar_t * strMessage = ( wchar_t * )_malloca( dwStrLen * sizeof( wchar_t ) ); + vswprintf_s( strMessage, dwStrLen, wstrFormat, pArgList ); + + // Output the string to the console + unsigned long uStringLength = wcslen( strMessage ); + for( unsigned long i = 0; i < uStringLength; i++ ) + Add( strMessage[i] ); + + _freea( strMessage ); +} diff --git a/360/xdk360_video_console.h b/360/xdk360_video_console.h new file mode 100644 index 0000000000..e0a6c0bb08 --- /dev/null +++ b/360/xdk360_video_console.h @@ -0,0 +1,105 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#pragma once +#ifndef SSNES360_CONSOLE_H +#define SSNES360_CONSOLE_H + +#include +#include "xdk360_video_debugfonts.h" + +#define PAGE_UP (255) +#define PAGE_DOWN (-255) + +#define SCREEN_SIZE_X_DEFAULT 640 +#define SCREEN_SIZE_Y_DEFAULT 480 + +#define SAFE_AREA_PCT_4x3 85 +#define SAFE_AREA_PCT_HDTV 90 + +#define INCREMENT_LINE() \ + m_nCurLine = ( m_nCurLine + 1 ) % m_cScreenHeightVirtual; \ + m_cCurLineLength = 0; \ + memset( m_Lines[m_nCurLine], 0, ( m_cScreenWidth + 1 ) * sizeof( wchar_t ) ); + +#define CLEAR_SCREEN() \ + m_nCurLine = 0; \ + m_cCurLineLength = 0; \ + memset( m_Buffer, 0, m_cScreenHeightVirtual * ( m_cScreenWidth + 1 ) * sizeof( wchar_t ) ); \ + Render(); + +//-------------------------------------------------------------------------------------- +// Name: class Console +// Desc: Class to implement the console. +//-------------------------------------------------------------------------------------- +class Console +{ +public: + Console(); + ~Console(); + + // Initialization + HRESULT Create( LPCSTR strFontFileName, + D3DCOLOR colBackColor, + D3DCOLOR colTextColor, + unsigned int nLines = 0 ); + + void Destroy(); + + // Console output + void Format(int clear_screen, _In_z_ _Printf_format_string_ LPCSTR strFormat, ... ); + void Format(int clear_screen, _In_z_ _Printf_format_string_ LPCWSTR wstrFormat, ... ); + void FormatV( _In_z_ _Printf_format_string_ LPCSTR strFormat, va_list pArgList ); + void FormatV( _In_z_ _Printf_format_string_ LPCWSTR wstrFormat, va_list pArgList ); + + // method for rendering the console + void Render(); +private: + int first_message; + // Safe area dimensions + unsigned int m_cxSafeArea; + unsigned int m_cySafeArea; + + unsigned int m_cxSafeAreaOffset; + unsigned int m_cySafeAreaOffset; + + // Font for rendering text + XdkFont m_Font; + + // Colors + D3DCOLOR m_colBackColor; + D3DCOLOR m_colTextColor; + + // Text Buffers + unsigned int m_cScreenHeight; // height in lines of screen area + unsigned int m_cScreenHeightVirtual; // height in lines of text storage buffer + unsigned int m_cScreenWidth; // width in characters + float m_fLineHeight; // height of a single line in pixels + + wchar_t * m_Buffer; // buffer big enough to hold a full screen + wchar_t ** m_Lines; // pointers to individual lines + unsigned int m_nCurLine; // index of current line being written to + unsigned int m_cCurLineLength; // length of the current line + int m_nScrollOffset; // offset to display text (in lines) + + // Add a character to the current line + void Add( char ch ); + void Add( wchar_t wch ); +}; + +#endif diff --git a/360/xdk360_video_debugfonts.cpp b/360/xdk360_video_debugfonts.cpp new file mode 100644 index 0000000000..0e370437d8 --- /dev/null +++ b/360/xdk360_video_debugfonts.cpp @@ -0,0 +1,964 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#include +#include +#include "xdk360_video.h" +#include "xdk360_video_debugfonts.h" +#include "../general.h" + +#define CALCFONTFILEHEADERSIZE(x) ( sizeof(unsigned long) + (sizeof(float)* 4) + sizeof(unsigned short) + (sizeof(wchar_t)*(x)) ) +#define FONTFILEVERSION 5 + +typedef struct FontFileHeaderImage_t { + unsigned long m_dwFileVersion; // Version of the font file (Must match FONTFILEVERSION) + float m_fFontHeight; // Height of the font strike in pixels + float m_fFontTopPadding; // Padding above the strike zone + float m_fFontBottomPadding; // Padding below the strike zone + float m_fFontYAdvance; // Number of pixels to move the cursor for a line feed + unsigned short m_cMaxGlyph; // Number of font characters (Should be an odd number to maintain DWORD Alignment) + wchar_t m_TranslatorTable[1]; // ASCII to Glyph lookup table, NOTE: It's m_cMaxGlyph+1 in size. + // Entry 0 maps to the "Unknown" glyph. +} FontFileHeaderImage_t; + +// Font strike array. Immediately follows the FontFileHeaderImage_t +// structure image + +typedef struct FontFileStrikesImage_t { + unsigned long m_dwNumGlyphs; // Size of font strike array (First entry is the unknown glyph) + GLYPH_ATTR m_Glyphs[1]; // Array of font strike uv's etc... NOTE: It's m_dwNumGlyphs in size +} FontFileStrikesImage_t; + +//-------------------------------------------------------------------------------------- +// Vertex and pixel shaders for font rendering +// Please note the removal of comment or dead lines... +// They are commented out because the shader compiler has no use for them. +//-------------------------------------------------------------------------------------- +static const char g_strFontShader[] = + "struct VS_IN\n" + "{\n" + "float2 Pos : POSITION;\n" + "float2 Tex : TEXCOORD0;\n" + "float4 ChannelSelector : TEXCOORD1;\n" + "};\n" +// "\n" + "struct VS_OUT\n" + "{\n" + "float4 Position : POSITION;\n" + "float4 Diffuse : COLOR0_center;\n" + "float2 TexCoord0 : TEXCOORD0;\n" + "float4 ChannelSelector : TEXCOORD1;\n" + "};\n" +// "\n" + "uniform float4 Color : register(c1);\n" + "uniform float2 TexScale : register(c2);\n" +// "\n" + "sampler FontTexture : register(s0);\n" +// "\n" + "VS_OUT FontVertexShader( VS_IN In )\n" + "{\n" + "VS_OUT Out;\n" + "Out.Position.x = (In.Pos.x-0.5);\n" + "Out.Position.y = (In.Pos.y-0.5);\n" + "Out.Position.z = ( 0.0 );\n" + "Out.Position.w = ( 1.0 );\n" + "Out.Diffuse = Color;\n" + "Out.TexCoord0.x = In.Tex.x * TexScale.x;\n" + "Out.TexCoord0.y = In.Tex.y * TexScale.y;\n" + "Out.ChannelSelector = In.ChannelSelector;\n" + "return Out;\n" + "}\n" + // "\n" + "float4 FontPixelShader( VS_OUT In ) : COLOR0\n" + "{\n" +// "// Fetch a texel from the font texture\n" + "float4 FontTexel = tex2D( FontTexture, In.TexCoord0 );\n" +// "\n" + "if( dot( In.ChannelSelector, float4(1,1,1,1) ) )\n" + "{\n" +// "// Select the color from the channel\n" + "float value = dot( FontTexel, In.ChannelSelector );\n" +// "\n" +// "// For white pixels, the high bit is 1 and the low\n" +// "// bits are luminance, so r0.a will be > 0.5. For the\n" +// "// RGB channel, we want to lop off the msb and shift\n" +// "// the lower bits up one bit. This is simple to do\n" +// "// with the _bx2 modifier. Since these pixels are\n" +// "// opaque, we emit a 1 for the alpha channel (which\n" +// "// is 0.5 x2 ).\n" +// "\n" +// "// For black pixels, the high bit is 0 and the low\n" +// "// bits are alpha, so r0.a will be < 0.5. For the RGB\n" +// "// channel, we emit zero. For the alpha channel, we\n" +// "// just use the x2 modifier to scale up the low bits\n" +// "// of the alpha.\n" + "float4 Color;\n" + "Color.rgb = ( value > 0.5f ? 2*value-1 : 0.0f );\n" + "Color.a = 2 * ( value > 0.5f ? 1.0f : value );\n" +// "\n" +// "// Return the texture color modulated with the vertex\n" +// "// color\n" + "return Color * In.Diffuse;\n" + "}\n" + "else\n" + "{\n" + "return FontTexel * In.Diffuse;\n" + "}\n" + "}\n"; + +typedef struct AtgFont_Locals_t { + D3DVertexDeclaration* m_pFontVertexDecl; // Shared vertex buffer + D3DVertexShader* m_pFontVertexShader; // Created vertex shader + D3DPixelShader* m_pFontPixelShader; // Created pixel shader +} AtgFont_Locals_t; + +// All elements are defaulted to NULL +static AtgFont_Locals_t s_AtgFontLocals; // Global static instance + +//-------------------------------------------------------------------------------------- +// Name: CreateFontShaders() +// Desc: Creates the global font shaders +//-------------------------------------------------------------------------------------- + +HRESULT XdkFont::CreateFontShaders() +{ + // + // There are only two states the globals could be in, + // Initialized, in which the ref count is increased, + // Uninialized, in which the vertex/pixel shaders need to be + // started up and a vertex array created. + /// + + HRESULT hr; + + if (!s_AtgFontLocals.m_pFontVertexDecl) + { + // Use the do {} while(0); trick for a fake goto + // It simplies tear down on error conditions. + do + { + + // Step #1, create my vertex array with 16 bytes per entry + // Floats for the position, + // shorts for the uvs + // 32 bit packed ARGB 8:8:8:8 for color + + static const D3DVERTEXELEMENT9 decl[] = + { + { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 8, D3DDECLTYPE_USHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, + D3DDECL_END() + }; + + // Cache this global into a register + xdk360_video_t *vid = (xdk360_video_t*)g_d3d; + D3DDevice *pd3dDevice = vid->xdk360_render_device; + + hr = pd3dDevice->CreateVertexDeclaration( decl, &s_AtgFontLocals.m_pFontVertexDecl ); + if (SUCCEEDED(hr)) + { + + // Step #2, create my vertex shader + ID3DXBuffer* pShaderCode; + hr = D3DXCompileShader( g_strFontShader, sizeof(g_strFontShader)-1 , + NULL, NULL, "FontVertexShader", "vs.2.0", 0,&pShaderCode, NULL, NULL ); + if (SUCCEEDED(hr)) + { + hr = pd3dDevice->CreateVertexShader( ( unsigned long * )pShaderCode->GetBufferPointer(), + &s_AtgFontLocals.m_pFontVertexShader ); + // Release the compiled shader + pShaderCode->Release(); + + if(SUCCEEDED(hr)) + { + // Step #3, create my pixel shader + hr = D3DXCompileShader( g_strFontShader, sizeof(g_strFontShader)-1 , + NULL, NULL, "FontPixelShader", "ps.2.0", 0,&pShaderCode, NULL, NULL ); + if ( SUCCEEDED(hr)) + { + hr = pd3dDevice->CreatePixelShader( ( DWORD* )pShaderCode->GetBufferPointer(), + &s_AtgFontLocals.m_pFontPixelShader ); + // Release the compiled shader + pShaderCode->Release(); + + if (SUCCEEDED(hr)) + { + hr = S_OK; + break; // Skip the teardown code + } + } + // If the code got to here, a fatal error has occured + // and a clean shutdown needs to be performed. + + s_AtgFontLocals.m_pFontVertexShader->Release(); + } + // Ensure the pointer is NULL + s_AtgFontLocals.m_pFontVertexShader = NULL; + } + s_AtgFontLocals.m_pFontVertexDecl->Release(); + } + // Ensure this pointer is NULL + s_AtgFontLocals.m_pFontVertexDecl = NULL; + }while(0); // Exit point for the break command. + return hr; + } + else + { + // + // Already initialized, so just add to the ref counts + // + + s_AtgFontLocals.m_pFontVertexDecl->AddRef(); + s_AtgFontLocals.m_pFontVertexShader->AddRef(); + s_AtgFontLocals.m_pFontPixelShader->AddRef(); + hr = S_OK; + } + return hr; // Return the error code if any +} + +//-------------------------------------------------------------------------------------- +// Name: ReleaseFontShaders() +// Desc: Releases the font shaders by reference +//-------------------------------------------------------------------------------------- + +void XdkFont::ReleaseFontShaders() +{ + // Safely release shaders + // NOTE: They are released in reverse order of creation + // to make sure any interdependencies are dealt with + + if( ( s_AtgFontLocals.m_pFontPixelShader != NULL ) && ( s_AtgFontLocals.m_pFontPixelShader->Release() == 0 ) ) + s_AtgFontLocals.m_pFontPixelShader = NULL; + if( ( s_AtgFontLocals.m_pFontVertexShader != NULL ) && ( s_AtgFontLocals.m_pFontVertexShader->Release() == 0 ) ) + s_AtgFontLocals.m_pFontVertexShader = NULL; + if( ( s_AtgFontLocals.m_pFontVertexDecl != NULL ) && ( s_AtgFontLocals.m_pFontVertexDecl->Release() == 0 ) ) + s_AtgFontLocals.m_pFontVertexDecl = NULL; +} + +//-------------------------------------------------------------------------------------- +// Name: Font() +// Desc: Constructor +//-------------------------------------------------------------------------------------- +XdkFont::XdkFont() +{ + m_pFontTexture = NULL; + + m_dwNumGlyphs = 0L; + m_Glyphs = NULL; + + m_fCursorX = 0.0f; + m_fCursorY = 0.0f; + + m_fXScaleFactor = 2.0f; + m_fYScaleFactor = 2.0f; + m_fSlantFactor = 0.0f; + m_bRotate = FALSE; + m_dRotCos = cos( 0.0 ); + m_dRotSin = sin( 0.0 ); + + m_cMaxGlyph = 0; + m_TranslatorTable = NULL; + + m_dwNestedBeginCount = 0L; +} + + +//-------------------------------------------------------------------------------------- +// Name: ~Font() +// Desc: Destructor +//-------------------------------------------------------------------------------------- +XdkFont::~XdkFont() +{ + Destroy(); +} + + +//-------------------------------------------------------------------------------------- +// Name: Create() +// Desc: Create the font's internal objects (texture and array of glyph info) +// using the XPR packed resource file +//-------------------------------------------------------------------------------------- +HRESULT XdkFont::Create( const char * strFontFileName ) +{ + // Create the font + if( FAILED( m_xprResource.Create( strFontFileName ) ) ) + return E_FAIL; + + D3DTexture * pFontTexture = m_xprResource.GetTexture( "FontTexture" ); + const void * pFontData = m_xprResource.GetData( "FontData"); + + // Save a copy of the texture + m_pFontTexture = pFontTexture; + + // Check version of file (to make sure it matches up with the FontMaker tool) + const unsigned char * pData = static_cast(pFontData); + unsigned long dwFileVersion = reinterpret_cast(pData)->m_dwFileVersion; + + if( dwFileVersion == FONTFILEVERSION ) + { + m_fFontHeight = reinterpret_cast(pData)->m_fFontHeight; + m_fFontTopPadding = reinterpret_cast(pData)->m_fFontTopPadding; + m_fFontBottomPadding = reinterpret_cast(pData)->m_fFontBottomPadding; + m_fFontYAdvance = reinterpret_cast(pData)->m_fFontYAdvance; + + // Point to the translator string which immediately follows the 4 floats + m_cMaxGlyph = reinterpret_cast(pData)->m_cMaxGlyph; + + m_TranslatorTable = const_cast(reinterpret_cast(pData))->m_TranslatorTable; + + pData += CALCFONTFILEHEADERSIZE( m_cMaxGlyph + 1 ); + + // Read the glyph attributes from the file + m_dwNumGlyphs = reinterpret_cast(pData)->m_dwNumGlyphs; + m_Glyphs = reinterpret_cast(pData)->m_Glyphs; // Pointer + } + else + { + SSNES_ERR( "Incorrect version number on font file.\n" ); + return E_FAIL; + } + + // Create the vertex and pixel shaders for rendering the font + if( FAILED( CreateFontShaders() ) ) + { + SSNES_ERR( "Could not create font shaders.\n" ); + return E_FAIL; + } + + xdk360_video_t *vid = (xdk360_video_t*)g_d3d; + D3DDevice *pd3dDevice = vid->xdk360_render_device; + + // Initialize the window + D3DDISPLAYMODE DisplayMode; + pd3dDevice->GetDisplayMode( 0, &DisplayMode ); + m_rcWindow.x1 = 0; + m_rcWindow.y1 = 0; + m_rcWindow.x2 = DisplayMode.Width; + m_rcWindow.y2 = DisplayMode.Height; + + // Determine whether we should save/restore state + m_bSaveState = TRUE; + + return S_OK; +} + +//-------------------------------------------------------------------------------------- +// Name: Destroy() +// Desc: Destroy the font object +//-------------------------------------------------------------------------------------- +void XdkFont::Destroy() +{ + m_pFontTexture = NULL; + m_dwNumGlyphs = 0L; + m_Glyphs = NULL; + m_cMaxGlyph = 0; + m_TranslatorTable = NULL; + m_dwNestedBeginCount = 0L; + + // Safely release shaders + ReleaseFontShaders(); + + if( m_xprResource.m_bInitialized) + m_xprResource.Destroy(); +} + + +//-------------------------------------------------------------------------------------- +// Name: SetWindow() +// Desc: Sets the and the bounds rect for drawing text and resets the cursor position +//-------------------------------------------------------------------------------------- +void XdkFont::SetWindow(const D3DRECT &rcWindow ) +{ + m_rcWindow.x1 = rcWindow.x1; + m_rcWindow.y1 = rcWindow.y1; + m_rcWindow.x2 = rcWindow.x2; + m_rcWindow.y2 = rcWindow.y2; + + m_fCursorX = 0.0f; + m_fCursorY = 0.0f; +} + + +//-------------------------------------------------------------------------------------- +// Name: SetWindow() +// Desc: Sets the and the bounds rect for drawing text and resets the cursor position +//-------------------------------------------------------------------------------------- +void XdkFont::SetWindow( long x1, long y1, long x2, long y2 ) +{ + m_rcWindow.x1 = x1; + m_rcWindow.y1 = y1; + m_rcWindow.x2 = x2; + m_rcWindow.y2 = y2; + + m_fCursorX = 0.0f; + m_fCursorY = 0.0f; +} + +//-------------------------------------------------------------------------------------- +// Name: GetWindow() +// Desc: Gets the current bounds rect for drawing +//-------------------------------------------------------------------------------------- +void XdkFont::GetWindow( D3DRECT &rcWindow ) const +{ + rcWindow = m_rcWindow; // NOTE: This is a structure copy +} + +//-------------------------------------------------------------------------------------- +// Name: SetCursorPosition() +// Desc: Sets the cursor position for drawing text +//-------------------------------------------------------------------------------------- +void XdkFont::SetCursorPosition( float fCursorX, float fCursorY ) +{ + m_fCursorX = floorf( fCursorX ); + m_fCursorY = floorf( fCursorY ); +} + +//-------------------------------------------------------------------------------------- +// Name: GetTextExtent() +// Desc: Get the dimensions of a text string +//-------------------------------------------------------------------------------------- + +void XdkFont::GetTextExtent( const wchar_t * strText, float * pWidth, + float * pHeight, int bFirstLineOnly ) const +{ + // Set default text extent in output parameters + int iWidth = 0; + float fHeight = 0.0f; + + if( strText ) + { + // Initialize counters that keep track of text extent + int ix = 0; + float fy = m_fFontHeight; // One character high to start + if( fy > fHeight ) + fHeight = fy; + + // Loop through each character and update text extent + unsigned long letter; + while( (letter = *strText) != 0 ) + { + ++strText; + + // Handle newline character + if( letter == L'\n' ) + { + if( bFirstLineOnly ) + break; + ix = 0; + fy += m_fFontYAdvance; + // since the height has changed, test against the height extent + if( fy > fHeight ) + fHeight = fy; + } + + // Handle carriage return characters by ignoring them. This helps when + // displaying text from a file. + if( letter == L'\r' ) + continue; + + // Translate unprintable characters + const GLYPH_ATTR* pGlyph; + + if( letter > m_cMaxGlyph ) + letter = 0; // Out of bounds? + else + letter = m_TranslatorTable[letter]; // Remap ASCII to glyph + + pGlyph = &m_Glyphs[letter]; // Get the requested glyph + + // Get text extent for this character's glyph + ix += pGlyph->wOffset; + ix += pGlyph->wAdvance; + + // Since the x widened, test against the x extent + + if( ix > iWidth ) + iWidth = ix; + } + } + + // Convert the width to a float here, load/hit/store. :( + float fWidth = static_cast(iWidth); // Delay the use if fWidth to reduce LHS pain + // Apply the scale factor to the result + fHeight *= m_fYScaleFactor; + // Store the final results + *pHeight = fHeight; + + fWidth *= m_fXScaleFactor; + *pWidth = fWidth; +} + +//-------------------------------------------------------------------------------------- +// Name: GetTextWidth() +// Desc: Returns the width in pixels of a text string +//-------------------------------------------------------------------------------------- +float XdkFont::GetTextWidth( const wchar_t * strText ) const +{ + float fTextWidth, fTextHeight; + GetTextExtent( strText, &fTextWidth, &fTextHeight ); + return fTextWidth; +} + + +//-------------------------------------------------------------------------------------- +// Name: Begin() +// Desc: Prepares the font vertex buffers for rendering. +//-------------------------------------------------------------------------------------- +VOID XdkFont::Begin() +{ + PIXBeginNamedEvent( 0, "Text Rendering" ); + + // Set state on the first call + if( m_dwNestedBeginCount == 0 ) + { + // Cache the global pointer into a register + xdk360_video_t *vid = (xdk360_video_t*)g_d3d; + D3DDevice *pD3dDevice = vid->xdk360_render_device; + + // Save state + if( m_bSaveState ) + { + // Note, we are not saving the texture, vertex, or pixel shader, + // since it's not worth the performance. We're more interested + // in saving state that would cause hard to find problems. + pD3dDevice->GetRenderState( D3DRS_ALPHABLENDENABLE, + &m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHABLENDENABLE ] ); + pD3dDevice->GetRenderState( D3DRS_SRCBLEND, &m_dwSavedState[ SAVEDSTATE_D3DRS_SRCBLEND ] ); + pD3dDevice->GetRenderState( D3DRS_DESTBLEND, &m_dwSavedState[ SAVEDSTATE_D3DRS_DESTBLEND ] ); + pD3dDevice->GetRenderState( D3DRS_BLENDOP, &m_dwSavedState[ SAVEDSTATE_D3DRS_BLENDOP ] ); + pD3dDevice->GetRenderState( D3DRS_ALPHATESTENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHATESTENABLE ] ); + pD3dDevice->GetRenderState( D3DRS_ALPHAREF, &m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAREF ] ); + pD3dDevice->GetRenderState( D3DRS_ALPHAFUNC, &m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAFUNC ] ); + pD3dDevice->GetRenderState( D3DRS_FILLMODE, &m_dwSavedState[ SAVEDSTATE_D3DRS_FILLMODE ] ); + pD3dDevice->GetRenderState( D3DRS_CULLMODE, &m_dwSavedState[ SAVEDSTATE_D3DRS_CULLMODE ] ); + pD3dDevice->GetRenderState( D3DRS_ZENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_ZENABLE ] ); + pD3dDevice->GetRenderState( D3DRS_STENCILENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_STENCILENABLE ] ); + pD3dDevice->GetRenderState( D3DRS_VIEWPORTENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_VIEWPORTENABLE ] ); + pD3dDevice->GetSamplerState( 0, D3DSAMP_MINFILTER, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_MINFILTER ] ); + pD3dDevice->GetSamplerState( 0, D3DSAMP_MAGFILTER, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_MAGFILTER ] ); + pD3dDevice->GetSamplerState( 0, D3DSAMP_ADDRESSU, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_ADDRESSU ] ); + pD3dDevice->GetSamplerState( 0, D3DSAMP_ADDRESSV, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_ADDRESSV ] ); + } + + // Set the texture scaling factor as a vertex shader constant + D3DSURFACE_DESC TextureDesc; + m_pFontTexture->GetLevelDesc( 0, &TextureDesc ); // Get the description + + // Set render state + pD3dDevice->SetTexture( 0, m_pFontTexture ); + + // Read the TextureDesc here to ensure no load/hit/store from GetLevelDesc() + float vTexScale[4]; + vTexScale[0] = 1.0f / TextureDesc.Width; // LHS due to int->float conversion + vTexScale[1] = 1.0f / TextureDesc.Height; + vTexScale[2] = 0.0f; + vTexScale[3] = 0.0f; + + pD3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); + pD3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + pD3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); + pD3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); + pD3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); + pD3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 ); + pD3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL ); + pD3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); + pD3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); + pD3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); + pD3dDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE ); + pD3dDevice->SetRenderState( D3DRS_VIEWPORTENABLE, FALSE ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP ); + + pD3dDevice->SetVertexDeclaration( s_AtgFontLocals.m_pFontVertexDecl ); + pD3dDevice->SetVertexShader( s_AtgFontLocals.m_pFontVertexShader ); + pD3dDevice->SetPixelShader( s_AtgFontLocals.m_pFontPixelShader ); + + // Set the texture scaling factor as a vertex shader constant + // Call here to avoid load hit store from writing to vTexScale above + pD3dDevice->SetVertexShaderConstantF( 2, vTexScale, 1 ); + } + + // Keep track of the nested begin/end calls. + m_dwNestedBeginCount++; +} + + +//-------------------------------------------------------------------------------------- +// Name: DrawText() +// Desc: Draws text as textured polygons +//-------------------------------------------------------------------------------------- +VOID XdkFont::DrawText( unsigned long dwColor, const wchar_t * strText, + unsigned long dwFlags, float fMaxPixelWidth ) +{ + DrawText( m_fCursorX, m_fCursorY, dwColor, strText, dwFlags, fMaxPixelWidth ); +} + + +//-------------------------------------------------------------------------------------- +// Name: DrawText() +// Desc: Draws text as textured polygons +// TODO: This function should use the Begin/SetVertexData/End() API when it +// becomes available. +//-------------------------------------------------------------------------------------- +VOID XdkFont::DrawText( float fOriginX, float fOriginY, unsigned long dwColor, + const wchar_t * strText, unsigned long dwFlags, float fMaxPixelWidth ) +{ + if( strText == NULL ) + return; + if( L'\0' == strText[0] ) + return; + + xdk360_video_t *vid = (xdk360_video_t*)g_d3d; + D3DDevice *pd3dDevice = vid->xdk360_render_device; + + // Create a PIX user-defined event that encapsulates all of the text draw calls. + // This makes DrawText calls easier to recognize in PIX captures, and it makes + // them take up fewer entries in the event list. + PIXBeginNamedEvent( dwColor, "DrawText: %S", strText ); + + // Set the color as a vertex shader constant + float vColor[4]; + vColor[0] = ( ( dwColor & 0x00ff0000 ) >> 16L ) / 255.0F; + vColor[1] = ( ( dwColor & 0x0000ff00 ) >> 8L ) / 255.0F; + vColor[2] = ( ( dwColor & 0x000000ff ) >> 0L ) / 255.0F; + vColor[3] = ( ( dwColor & 0xff000000 ) >> 24L ) / 255.0F; + + // Set up stuff to prepare for drawing text + Begin(); + + // Perform the actual storing of the color constant here to prevent + // a load-hit-store by inserting work between the store and the use of + // the vColor array. + pd3dDevice->SetVertexShaderConstantF( 1, vColor, 1 ); + + // Set the starting screen position + if( ( fOriginX < 0.0f ) || ( ( dwFlags & FONT_RIGHT ) && ( fOriginX <= 0.0f ) ) ) + fOriginX += ( m_rcWindow.x2 - m_rcWindow.x1 ); + if( fOriginY < 0.0f ) + fOriginY += ( m_rcWindow.y2 - m_rcWindow.y1 ); + + m_fCursorX = floorf( fOriginX ); + m_fCursorY = floorf( fOriginY ); + + // Adjust for padding + fOriginY -= m_fFontTopPadding; + + float fEllipsesPixelWidth = m_fXScaleFactor * 3.0f * ( m_Glyphs[m_TranslatorTable[L'.']].wOffset + + m_Glyphs[m_TranslatorTable[L'.']].wAdvance ); + + if( dwFlags & FONT_TRUNCATED ) + { + // Check if we will really need to truncate the string + if( fMaxPixelWidth <= 0.0f ) + dwFlags &= ( ~FONT_TRUNCATED ); + else + { + float w, h; + GetTextExtent( strText, &w, &h, TRUE ); + + // If not, then clear the flag + if( w <= fMaxPixelWidth ) + dwFlags &= ( ~FONT_TRUNCATED ); + } + } + + // If vertically centered, offset the starting m_fCursorY value + if( dwFlags & FONT_CENTER_Y ) + { + float w, h; + GetTextExtent( strText, &w, &h ); + m_fCursorY = floorf( m_fCursorY - (h * 0.5f) ); + } + + // Add window offsets + float Winx = static_cast(m_rcWindow.x1); + float Winy = static_cast(m_rcWindow.y1); + fOriginX += Winx; + fOriginY += Winy; + m_fCursorX += Winx; + m_fCursorY += Winy; + + // Set a flag so we can determine initial justification effects + BOOL bStartingNewLine = TRUE; + + unsigned long dwNumEllipsesToDraw = 0; + + // Begin drawing the vertices + + // Declared as volatile to force writing in ascending + // address order. It prevents out of sequence writing in write combined + // memory. + + volatile float * pVertex; + + unsigned long dwNumChars = wcslen( strText ) + ( dwFlags & FONT_TRUNCATED ? 3 : 0 ); + HRESULT hr = pd3dDevice->BeginVertices( D3DPT_QUADLIST, 4 * dwNumChars, sizeof( XMFLOAT4 ) , + ( VOID** )&pVertex ); + // The ring buffer may run out of space when tiling, doing z-prepasses, + // or using BeginCommandBuffer. If so, make the buffer larger. + if( FAILED( hr ) ) + SSNES_ERR( "Ring buffer out of memory.\n" ); + + bStartingNewLine = TRUE; + + // Draw four vertices for each glyph + while( *strText ) + { + wchar_t letter; + + if( dwNumEllipsesToDraw ) + letter = L'.'; + else + { + // If starting text on a new line, determine justification effects + if( bStartingNewLine ) + { + if( dwFlags & ( FONT_RIGHT | FONT_CENTER_X ) ) + { + // Get the extent of this line + float w, h; + GetTextExtent( strText, &w, &h, TRUE ); + + // Offset this line's starting m_fCursorX value + if( dwFlags & FONT_RIGHT ) + m_fCursorX = floorf( fOriginX - w ); + if( dwFlags & FONT_CENTER_X ) + m_fCursorX = floorf( fOriginX - w * 0.5f ); + } + bStartingNewLine = FALSE; + } + + // Get the current letter in the string + letter = *strText++; + + // Handle the newline character + if( letter == L'\n' ) + { + m_fCursorX = fOriginX; + m_fCursorY += m_fFontYAdvance * m_fYScaleFactor; + bStartingNewLine = TRUE; + continue; + } + + // Handle carriage return characters by ignoring them. This helps when + // displaying text from a file. + if( letter == L'\r' ) + continue; + } + + // Translate unprintable characters + const GLYPH_ATTR * pGlyph = &m_Glyphs[ ( letter <= m_cMaxGlyph ) ? m_TranslatorTable[letter] : 0 ]; + + float fOffset = m_fXScaleFactor * (float)pGlyph->wOffset; + float fAdvance = m_fXScaleFactor * (float)pGlyph->wAdvance; + float fWidth = m_fXScaleFactor * (float)pGlyph->wWidth; + float fHeight = m_fYScaleFactor * m_fFontHeight; + + if( 0 == dwNumEllipsesToDraw ) + { + if( dwFlags & FONT_TRUNCATED ) + { + // Check if we will be exceeded the max allowed width + if( m_fCursorX + fOffset + fWidth + fEllipsesPixelWidth + m_fSlantFactor > fOriginX + fMaxPixelWidth ) + { + // Yup, draw the three ellipses dots instead + dwNumEllipsesToDraw = 3; + continue; + } + } + } + + // Setup the screen coordinates + m_fCursorX += fOffset; + float X4 = m_fCursorX; + float X1 = X4 + m_fSlantFactor; + float X3 = X4 + fWidth; + float X2 = X1 + fWidth; + float Y1 = m_fCursorY; + float Y3 = Y1 + fHeight; + float Y2 = Y1; + float Y4 = Y3; + + // Rotate the points by the rotation factor + if( m_bRotate ) + { + RotatePoint( &X1, &Y1, fOriginX, fOriginY ); + RotatePoint( &X2, &Y2, fOriginX, fOriginY ); + RotatePoint( &X3, &Y3, fOriginX, fOriginY ); + RotatePoint( &X4, &Y4, fOriginX, fOriginY ); + } + + m_fCursorX += fAdvance; + + // Select the RGBA channel that the compressed glyph is stored in + // Takes a 4 bit per pixel ARGB value and expand it to an 8 bit per pixel ARGB value + + unsigned long dwChannelSelector = pGlyph->wMask; // Convert to 32 bit + // Perform the conversion without branching + + // Splat the 4 bit per pixels from 0x1234 to 0x01020304 + dwChannelSelector = ((dwChannelSelector&0xF000)<<(24-12))|((dwChannelSelector&0xF00)<<(16-8))| + ((dwChannelSelector&0xF0)<<(8-4))|(dwChannelSelector&0xF); + + // Perform a vectorized multiply to make 0x01020304 into 0x11223344 + dwChannelSelector *= 0x11; + + // Add the vertices to draw this glyph + + unsigned long tu1 = pGlyph->tu1; // Convert shorts to 32 bit longs for in register merging + unsigned long tv1 = pGlyph->tv1; + unsigned long tu2 = pGlyph->tu2; + unsigned long tv2 = pGlyph->tv2; + + // NOTE: The vertexs are 2 floats for the screen coordinates, + // followed by two USHORTS for the u/vs of the character, + // terminated with the ARGB 32 bit color. + // This makes for 16 bytes per vertex data (Easier to read) + // Second NOTE: The uvs are merged and written using a DWORD due + // to the write combining hardware being only able to handle 32, + // 64 and 128 writes. Never store to write combined memory with + // 8 or 16 bit instructions. You've been warned. + + pVertex[0] = X1; + pVertex[1] = Y1; + reinterpret_cast(pVertex)[2] = (tu1<<16)|tv1; // Merged using big endian rules + reinterpret_cast(pVertex)[3] = dwChannelSelector; + pVertex[4] = X2; + pVertex[5] = Y2; + reinterpret_cast(pVertex)[6] = (tu2<<16)|tv1; // Merged using big endian rules + reinterpret_cast(pVertex)[7] = dwChannelSelector; + pVertex[8] = X3; + pVertex[9] = Y3; + reinterpret_cast(pVertex)[10] = (tu2<<16)|tv2; // Merged using big endian rules + reinterpret_cast(pVertex)[11] = dwChannelSelector; + pVertex[12] = X4; + pVertex[13] = Y4; + reinterpret_cast(pVertex)[14] = (tu1<<16)|tv2; // Merged using big endian rules + reinterpret_cast(pVertex)[15] = dwChannelSelector; + pVertex+=16; + + // If drawing ellipses, exit when they're all drawn + if( dwNumEllipsesToDraw ) + { + if( --dwNumEllipsesToDraw == 0 ) + break; + } + + dwNumChars--; + } + + // Since we allocated vertex data space based on the string length, we now need to + // add some dummy verts for any skipped characters (like newlines, etc.) + while( dwNumChars ) + { + pVertex[0] = 0; + pVertex[1] = 0; + pVertex[2] = 0; + pVertex[3] = 0; + pVertex[4] = 0; + pVertex[5] = 0; + pVertex[6] = 0; + pVertex[7] = 0; + pVertex[8] = 0; + pVertex[9] = 0; + pVertex[10] = 0; + pVertex[11] = 0; + pVertex[12] = 0; + pVertex[13] = 0; + pVertex[14] = 0; + pVertex[15] = 0; + pVertex+=16; + dwNumChars--; + } + + // Stop drawing vertices + pd3dDevice->EndVertices(); + + // Undo window offsets + m_fCursorX -= Winx; + m_fCursorY -= Winy; + + // Call End() to complete the begin/end pair for drawing text + End(); + + // Close off the user-defined event opened with PIXBeginNamedEvent. + PIXEndNamedEvent(); +} + + +//-------------------------------------------------------------------------------------- +// Name: End() +// Desc: Paired call that restores state set in the Begin() call. +//-------------------------------------------------------------------------------------- +VOID XdkFont::End() +{ + if( --m_dwNestedBeginCount > 0 ) + { + PIXEndNamedEvent(); + return; + } + + // Restore state + if( m_bSaveState ) + { + // Cache the global pointer into a register + xdk360_video_t *vid = (xdk360_video_t*)g_d3d; + D3DDevice *pD3dDevice = vid->xdk360_render_device; + + pD3dDevice->SetTexture( 0, NULL ); + pD3dDevice->SetVertexDeclaration( NULL ); + pD3dDevice->SetVertexShader( NULL ); + pD3dDevice->SetPixelShader( NULL ); + pD3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHABLENDENABLE ] ); + pD3dDevice->SetRenderState( D3DRS_SRCBLEND, m_dwSavedState[ SAVEDSTATE_D3DRS_SRCBLEND ] ); + pD3dDevice->SetRenderState( D3DRS_DESTBLEND, m_dwSavedState[ SAVEDSTATE_D3DRS_DESTBLEND ] ); + pD3dDevice->SetRenderState( D3DRS_BLENDOP, m_dwSavedState[ SAVEDSTATE_D3DRS_BLENDOP ] ); + pD3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHATESTENABLE ] ); + pD3dDevice->SetRenderState( D3DRS_ALPHAREF, m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAREF ] ); + pD3dDevice->SetRenderState( D3DRS_ALPHAFUNC, m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAFUNC ] ); + pD3dDevice->SetRenderState( D3DRS_FILLMODE, m_dwSavedState[ SAVEDSTATE_D3DRS_FILLMODE ] ); + pD3dDevice->SetRenderState( D3DRS_CULLMODE, m_dwSavedState[ SAVEDSTATE_D3DRS_CULLMODE ] ); + pD3dDevice->SetRenderState( D3DRS_ZENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_ZENABLE ] ); + pD3dDevice->SetRenderState( D3DRS_STENCILENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_STENCILENABLE ] ); + pD3dDevice->SetRenderState( D3DRS_VIEWPORTENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_VIEWPORTENABLE ] ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, m_dwSavedState[ SAVEDSTATE_D3DSAMP_MINFILTER ] ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, m_dwSavedState[ SAVEDSTATE_D3DSAMP_MAGFILTER ] ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, m_dwSavedState[ SAVEDSTATE_D3DSAMP_ADDRESSU ] ); + pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, m_dwSavedState[ SAVEDSTATE_D3DSAMP_ADDRESSV ] ); + } + + PIXEndNamedEvent(); +} + +//-------------------------------------------------------------------------------------- +// Name: RotatePoint() +// Desc: Rotate a 2D point around the origin +//------------------------------------------------------------------------------------- +void XdkFont::RotatePoint( float * X, float * Y, double OriginX, double OriginY ) const +{ + double dTempX = *X - OriginX; + double dTempY = *Y - OriginY; + double dXprime = OriginX + ( m_dRotCos * dTempX - m_dRotSin * dTempY ); + double dYprime = OriginY + ( m_dRotSin * dTempX + m_dRotCos * dTempY ); + + *X = static_cast( dXprime ); + *Y = static_cast( dYprime ); +} \ No newline at end of file diff --git a/360/xdk360_video_debugfonts.h b/360/xdk360_video_debugfonts.h new file mode 100644 index 0000000000..3be4d62f68 --- /dev/null +++ b/360/xdk360_video_debugfonts.h @@ -0,0 +1,134 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#ifndef _SSNES360_DEBUG_FONTS_H +#define _SSNES360_DEBUG_FONTS_H + +#include "xdk360_video_resources.h" + +typedef struct GLYPH_ATTR +{ + unsigned short tu1, tv1, tu2, tv2; // Texture coordinates for the image + short wOffset; // Pixel offset for glyph start + short wWidth; // Pixel width of the glyph + short wAdvance; // Pixels to advance after the glyph + unsigned short wMask; // Channel mask +} GLYPH_ATTR; + +#define FONT_LEFT 0x00000000 +#define FONT_RIGHT 0x00000001 +#define FONT_CENTER_X 0x00000002 +#define FONT_CENTER_Y 0x00000004 +#define FONT_TRUNCATED 0x00000008 + +enum SavedStates +{ + SAVEDSTATE_D3DRS_ALPHABLENDENABLE, + SAVEDSTATE_D3DRS_SRCBLEND, + SAVEDSTATE_D3DRS_DESTBLEND, + SAVEDSTATE_D3DRS_BLENDOP, + SAVEDSTATE_D3DRS_ALPHATESTENABLE, + SAVEDSTATE_D3DRS_ALPHAREF, + SAVEDSTATE_D3DRS_ALPHAFUNC, + SAVEDSTATE_D3DRS_FILLMODE, + SAVEDSTATE_D3DRS_CULLMODE, + SAVEDSTATE_D3DRS_ZENABLE, + SAVEDSTATE_D3DRS_STENCILENABLE, + SAVEDSTATE_D3DRS_VIEWPORTENABLE, + SAVEDSTATE_D3DSAMP_MINFILTER, + SAVEDSTATE_D3DSAMP_MAGFILTER, + SAVEDSTATE_D3DSAMP_ADDRESSU, + SAVEDSTATE_D3DSAMP_ADDRESSV, + + SAVEDSTATE_COUNT +}; + +class XdkFont +{ +public: + PackedResource m_xprResource; + + // Font vertical dimensions taken from the font file + float m_fFontHeight; // Height of the font strike in pixels + float m_fFontTopPadding; // Padding above the strike zone + float m_fFontBottomPadding; // Padding below the strike zone + float m_fFontYAdvance; // Number of pixels to move the cursor for a line feed + + float m_fXScaleFactor; // Scaling constants + float m_fYScaleFactor; + float m_fSlantFactor; // For italics + double m_dRotCos; // Precalculated sine and cosine for italic like rotation + double m_dRotSin; + + D3DRECT m_rcWindow; // Bounds rect if the text window, modify via accessors only! + float m_fCursorX; // Current text cursor + float m_fCursorY; + + // Translator table for supporting unicode ranges + unsigned long m_cMaxGlyph; // Number of entries in the translator table + wchar_t * m_TranslatorTable; // ASCII to glyph lookup table + + // Glyph data for the font + unsigned long m_dwNumGlyphs; // Number of valid glyphs + const GLYPH_ATTR* m_Glyphs; // Array of glyphs + + // D3D rendering objects + D3DTexture* m_pFontTexture; + + // Saved state for rendering (if not using a pure device) + unsigned long m_dwSavedState[ SAVEDSTATE_COUNT ]; + unsigned long m_dwNestedBeginCount; + int m_bSaveState; + + int m_bRotate; +public: + XdkFont(); + ~XdkFont(); + + // Functions to create and destroy the internal objects + HRESULT Create( const char * strFontFileName ); + void Destroy(); + + // Returns the dimensions of a text string + void GetTextExtent( const wchar_t * strText, float * pWidth, + float * pHeight, int bFirstLineOnly=FALSE ) const; + float GetTextWidth( const wchar_t * strText ) const; + + void SetWindow(const D3DRECT &rcWindow ); + void SetWindow( long x1, long y1, long x2, long y2 ); + void GetWindow(D3DRECT &rcWindow) const; + void SetCursorPosition( float fCursorX, float fCursorY ); + + // Public calls to render text. Callers can simply call DrawText(), but for + // performance, they should batch multiple calls together, bracketed by calls to + // Begin() and End(). + void Begin(); + void DrawText( unsigned long dwColor, const wchar_t * strText, unsigned long dwFlags=0L, + float fMaxPixelWidth = 0.0f ); + void DrawText( float sx, float sy, unsigned long dwColor, const wchar_t * strText, + unsigned long dwFlags=0L, float fMaxPixelWidth = 0.0f ); + void End(); + +private: + // Internal helper functions + HRESULT CreateFontShaders(); + void ReleaseFontShaders(); + void RotatePoint( float * X, float * Y, double OriginX, double OriginY ) const; +}; + +#endif \ No newline at end of file diff --git a/360/xdk360_video_resources.cpp b/360/xdk360_video_resources.cpp new file mode 100644 index 0000000000..356f78391c --- /dev/null +++ b/360/xdk360_video_resources.cpp @@ -0,0 +1,211 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#include +#include +#include "xdk360_video.h" +#include "xdk360_video_resources.h" +#include "../general.h" + +//-------------------------------------------------------------------------------------- +// Magic values to identify XPR files +//-------------------------------------------------------------------------------------- +struct XPR_HEADER +{ + unsigned long dwMagic; + unsigned long dwHeaderSize; + unsigned long dwDataSize; +}; + +#define XPR2_MAGIC_VALUE (0x58505232) +#define eXALLOCAllocatorId_AtgResource eXALLOCAllocatorId_GameMax + +//-------------------------------------------------------------------------------------- +// Name: PackedResource +//-------------------------------------------------------------------------------------- +PackedResource::PackedResource() +{ + m_pSysMemData = NULL; + m_dwSysMemDataSize = 0L; + m_pVidMemData = NULL; + m_dwVidMemDataSize = 0L; + m_pResourceTags = NULL; + m_dwNumResourceTags = 0L; + m_bInitialized = FALSE; +} + + +//-------------------------------------------------------------------------------------- +// Name: PackedResource +//-------------------------------------------------------------------------------------- +PackedResource::~PackedResource() +{ + Destroy(); +} + +//-------------------------------------------------------------------------------------- +// Name: GetData +// Desc: Loads all the texture resources from the given XPR. +//-------------------------------------------------------------------------------------- +void * PackedResource::GetData( const char * strName ) const +{ + if( m_pResourceTags == NULL || strName == NULL ) + return NULL; + + for( unsigned long i = 0; i < m_dwNumResourceTags; i++ ) + { + if( !_stricmp( strName, m_pResourceTags[i].strName ) ) + return &m_pSysMemData[m_pResourceTags[i].dwOffset]; + } + + return NULL; +} + +//-------------------------------------------------------------------------------------- +// Name: Create +// Desc: Loads all the texture resources from the given XPR. +//-------------------------------------------------------------------------------------- +HRESULT PackedResource::Create( const char * strFilename ) +{ + // Open the file + unsigned long dwNumBytesRead; + HANDLE hFile = CreateFile( strFilename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL ); + if( hFile == INVALID_HANDLE_VALUE ) + { + SSNES_ERR( "File <%s> not found.\n", strFilename ); + return E_FAIL; + } + + // Read in and verify the XPR magic header + XPR_HEADER xprh; + if( !ReadFile( hFile, &xprh, sizeof( XPR_HEADER ), &dwNumBytesRead, NULL ) ) + { + SSNES_ERR( "Error reading XPR header in file <%s>.\n", strFilename ); + CloseHandle( hFile ); + return E_FAIL; + } + + if( xprh.dwMagic != XPR2_MAGIC_VALUE ) + { + SSNES_ERR( "Invalid Xbox Packed Resource (.xpr) file: Magic = 0x%08lx.\n", xprh.dwMagic ); + CloseHandle( hFile ); + return E_FAIL; + } + + // Compute memory requirements + m_dwSysMemDataSize = xprh.dwHeaderSize; + m_dwVidMemDataSize = xprh.dwDataSize; + + // Allocate memory + m_pSysMemData = new BYTE[m_dwSysMemDataSize]; + if( m_pSysMemData == NULL ) + { + SSNES_ERR( "Could not allocate system memory.\n" ); + m_dwSysMemDataSize = 0; + return E_FAIL; + } + m_pVidMemData = ( BYTE* )XMemAlloc( m_dwVidMemDataSize, MAKE_XALLOC_ATTRIBUTES( 0, 0, 0, 0, eXALLOCAllocatorId_AtgResource, + XALLOC_PHYSICAL_ALIGNMENT_4K, XALLOC_MEMPROTECT_WRITECOMBINE, 0, XALLOC_MEMTYPE_PHYSICAL ) ); + + if( m_pVidMemData == NULL ) + { + SSNES_ERR( "Could not allocate physical memory.\n" ); + m_dwSysMemDataSize = 0; + m_dwVidMemDataSize = 0; + delete[] m_pSysMemData; + m_pSysMemData = NULL; + return E_FAIL; + } + + // Read in the data from the file + if( !ReadFile( hFile, m_pSysMemData, m_dwSysMemDataSize, &dwNumBytesRead, NULL ) || + !ReadFile( hFile, m_pVidMemData, m_dwVidMemDataSize, &dwNumBytesRead, NULL ) ) + { + SSNES_ERR( "Unable to read Xbox Packed Resource (.xpr) file.\n" ); + CloseHandle( hFile ); + return E_FAIL; + } + + // Done with the file + CloseHandle( hFile ); + + // Extract resource table from the header data + m_dwNumResourceTags = *( unsigned long * )( m_pSysMemData + 0 ); + m_pResourceTags = ( RESOURCE* )( m_pSysMemData + 4 ); + + // Patch up the resources + for( unsigned long i = 0; i < m_dwNumResourceTags; i++ ) + { + m_pResourceTags[i].strName = ( char * )( m_pSysMemData + ( unsigned long )m_pResourceTags[i].strName ); + + // Fixup the texture memory + if( ( m_pResourceTags[i].dwType & 0xffff0000 ) == ( RESOURCETYPE_TEXTURE & 0xffff0000 ) ) + { + D3DTexture* pTexture = ( D3DTexture* )&m_pSysMemData[m_pResourceTags[i].dwOffset]; + // Adjust Base address according to where memory was allocated + XGOffsetBaseTextureAddress( pTexture, m_pVidMemData, m_pVidMemData ); + + // Let PIX know the name of the texture + PIXSetTextureName(pTexture, m_pResourceTags[i].strName); + } + } + + m_bInitialized = TRUE; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +// Name: GetResourceTags +// Desc: Retrieves the resource tags +//-------------------------------------------------------------------------------------- +void PackedResource::GetResourceTags( unsigned long * pdwNumResourceTags, + RESOURCE** ppResourceTags ) const +{ + if( pdwNumResourceTags ) + ( *pdwNumResourceTags ) = m_dwNumResourceTags; + + if( ppResourceTags ) + ( *ppResourceTags ) = m_pResourceTags; +} + + +//-------------------------------------------------------------------------------------- +// Name: Destroy +// Desc: Cleans up the packed resource data +//-------------------------------------------------------------------------------------- +void PackedResource::Destroy() +{ + delete[] m_pSysMemData; + m_pSysMemData = NULL; + m_dwSysMemDataSize = 0L; + + if( m_pVidMemData != NULL ) + XMemFree( m_pVidMemData, MAKE_XALLOC_ATTRIBUTES( 0, 0, 0, 0, eXALLOCAllocatorId_AtgResource, + 0, 0, 0, XALLOC_MEMTYPE_PHYSICAL ) ); + + m_pVidMemData = NULL; + m_dwVidMemDataSize = 0L; + + m_pResourceTags = NULL; + m_dwNumResourceTags = 0L; + + m_bInitialized = FALSE; +} diff --git a/360/xdk360_video_resources.h b/360/xdk360_video_resources.h new file mode 100644 index 0000000000..25a3cffaa8 --- /dev/null +++ b/360/xdk360_video_resources.h @@ -0,0 +1,155 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#pragma once + +#ifndef SSNES360_RESOURCES_H +#define SSNES360_RESOURCES_H + +//-------------------------------------------------------------------------------------- +// Name tag for resources. An app may initialize this structure, and pass +// it to the resource's Create() function. From then on, the app may call +// GetResource() to retrieve a resource using an ascii name. +//-------------------------------------------------------------------------------------- +struct RESOURCE +{ + unsigned long dwType; + unsigned long dwOffset; + unsigned long dwSize; + char * strName; +}; + + +// Resource types +enum +{ + RESOURCETYPE_USERDATA = ( ( 'U' << 24 ) | ( 'S' << 16 ) | ( 'E' << 8 ) | ( 'R' ) ), + RESOURCETYPE_TEXTURE = ( ( 'T' << 24 ) | ( 'X' << 16 ) | ( '2' << 8 ) | ( 'D' ) ), + RESOURCETYPE_CUBEMAP = ( ( 'T' << 24 ) | ( 'X' << 16 ) | ( 'C' << 8 ) | ( 'M' ) ), + RESOURCETYPE_VOLUMETEXTURE = ( ( 'T' << 24 ) | ( 'X' << 16 ) | ( '3' << 8 ) | ( 'D' ) ), + RESOURCETYPE_VERTEXBUFFER = ( ( 'V' << 24 ) | ( 'B' << 16 ) | ( 'U' << 8 ) | ( 'F' ) ), + RESOURCETYPE_INDEXBUFFER = ( ( 'I' << 24 ) | ( 'B' << 16 ) | ( 'U' << 8 ) | ( 'F' ) ), + RESOURCETYPE_EOF = 0xffffffff +}; + + +//-------------------------------------------------------------------------------------- +// Name: PackedResource +//-------------------------------------------------------------------------------------- +class PackedResource +{ +protected: + unsigned char * m_pSysMemData; // Alloc'ed memory for resource headers etc. + unsigned long m_dwSysMemDataSize; + + unsigned char * m_pVidMemData; // Alloc'ed memory for resource data, etc. + unsigned long m_dwVidMemDataSize; + + RESOURCE* m_pResourceTags; // Tags to associate names with the resources + unsigned long m_dwNumResourceTags; // Number of resource tags +public: + int m_bInitialized; // Resource is fully initialized + // Loads the resources out of the specified bundle + HRESULT Create( const char * strFilename ); + + void Destroy(); + + // Retrieves the resource tags + void GetResourceTags( unsigned long * pdwNumResourceTags, + RESOURCE** ppResourceTags ) const; + + // Helper function to make sure a resource is registered + D3DResource* RegisterResource( D3DResource* pResource ) const + { + return pResource; + } + + // Functions to retrieve resources by their offset + void * GetData( unsigned long dwOffset ) const + { + return &m_pSysMemData[dwOffset]; + } + + D3DResource* GetResource( unsigned long dwOffset ) const + { + return RegisterResource( ( D3DResource* )GetData( dwOffset ) ); + } + + D3DTexture* GetTexture( unsigned long dwOffset ) const + { + return ( D3DTexture* )GetResource( dwOffset ); + } + + D3DArrayTexture* GetArrayTexture( unsigned long dwOffset ) const + { + return ( D3DArrayTexture* )GetResource( dwOffset ); + } + + D3DCubeTexture* GetCubemap( unsigned long dwOffset ) const + { + return ( D3DCubeTexture* )GetResource( dwOffset ); + } + + D3DVolumeTexture* GetVolumeTexture( unsigned long dwOffset ) const + { + return ( D3DVolumeTexture* )GetResource( dwOffset ); + } + + D3DVertexBuffer* GetVertexBuffer( unsigned long dwOffset ) const + { + return ( D3DVertexBuffer* )GetResource( dwOffset ); + } + + // Functions to retrieve resources by their name + void * GetData( const char * strName ) const; + + D3DResource* GetResource( const char * strName ) const + { + return RegisterResource( ( D3DResource* )GetData( strName ) ); + } + + D3DTexture* GetTexture( const char * strName ) const + { + return ( D3DTexture* )GetResource( strName ); + } + + D3DArrayTexture* GetArrayTexture( const char * strName ) const + { + return ( D3DArrayTexture* )GetResource( strName ); + } + + D3DCubeTexture* GetCubemap( const char * strName ) const + { + return ( D3DCubeTexture* )GetResource( strName ); + } + + D3DVolumeTexture* GetVolumeTexture( const char * strName ) const + { + return ( D3DVolumeTexture* )GetResource( strName ); + } + + D3DVertexBuffer* GetVertexBuffer( const char * strName ) const + { + return ( D3DVertexBuffer* )GetResource( strName ); + } + + PackedResource(); + ~PackedResource(); +}; + +#endif diff --git a/msvc-360/SSNES-360/SSNES-360.vcxproj b/msvc-360/SSNES-360/SSNES-360.vcxproj index cdfebe96ed..8f6374db83 100644 --- a/msvc-360/SSNES-360/SSNES-360.vcxproj +++ b/msvc-360/SSNES-360/SSNES-360.vcxproj @@ -270,6 +270,9 @@ + + + @@ -460,6 +463,23 @@ $(OutDir)media\b.png;%(Outputs) + + + Document + Bundler %(FullPath) /o $(OutDir)media\Arial_12.xpr + Bundler %(FullPath) /o $(OutDir)media\Arial_12.xpr + Bundler %(FullPath) /o $(OutDir)media\Arial_12.xpr + Bundler %(FullPath) /o $(OutDir)media\Arial_12.xpr + Bundler %(FullPath) /o $(OutDir)media\Arial_12.xpr + Bundler %(FullPath) /o $(OutDir)media\Arial_12.xpr + $(OutDir)media\Arial_12.xpr;%(Outputs) + $(OutDir)media\Arial_12.xpr;%(Outputs) + $(OutDir)media\Arial_12.xpr;%(Outputs) + $(OutDir)media\Arial_12.xpr;%(Outputs) + $(OutDir)media\Arial_12.xpr;%(Outputs) + $(OutDir)media\Arial_12.xpr;%(Outputs) + + diff --git a/msvc-360/SSNES-360/SSNES-360.vcxproj.filters b/msvc-360/SSNES-360/SSNES-360.vcxproj.filters index 36ee81b2d7..015f87c201 100644 --- a/msvc-360/SSNES-360/SSNES-360.vcxproj.filters +++ b/msvc-360/SSNES-360/SSNES-360.vcxproj.filters @@ -131,6 +131,15 @@ Source Files\console + + Source Files\360 + + + Source Files\360 + + + Source Files\360 + @@ -246,5 +255,8 @@ Source Files\media + + Source Files\media + \ No newline at end of file