trunk/src/osd/sdl/sdlmain.c
r32113 | r32114 | |
73 | 73 | |
74 | 74 | #include "watchdog.h" |
75 | 75 | |
| 76 | #define DEFAULT_FONT_HEIGHT (200) |
| 77 | |
76 | 78 | //============================================================ |
77 | 79 | // OPTIONS |
78 | 80 | //============================================================ |
r32113 | r32114 | |
1141 | 1143 | } |
1142 | 1144 | #endif // not OSX |
1143 | 1145 | #else // not UNIX |
| 1146 | #ifdef SDLMAME_WIN32 |
| 1147 | |
| 1148 | //============================================================ |
| 1149 | // wstring_from_utf8 |
| 1150 | //============================================================ |
| 1151 | |
| 1152 | WCHAR *wstring_from_utf8(const char *utf8string) |
| 1153 | { |
| 1154 | int char_count; |
| 1155 | WCHAR *result; |
| 1156 | |
| 1157 | // convert MAME string (UTF-8) to UTF-16 |
| 1158 | char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0); |
| 1159 | result = (WCHAR *)osd_malloc_array(char_count * sizeof(*result)); |
| 1160 | if (result != NULL) |
| 1161 | MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count); |
| 1162 | |
| 1163 | return result; |
| 1164 | } |
| 1165 | |
| 1166 | |
| 1167 | //============================================================ |
| 1168 | // utf8_from_wstring |
| 1169 | //============================================================ |
| 1170 | |
| 1171 | char *utf8_from_wstring(const WCHAR *wstring) |
| 1172 | { |
| 1173 | int char_count; |
| 1174 | char *result; |
| 1175 | |
| 1176 | // convert UTF-16 to MAME string (UTF-8) |
| 1177 | char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL); |
| 1178 | result = (char *)osd_malloc_array(char_count * sizeof(*result)); |
| 1179 | if (result != NULL) |
| 1180 | WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL); |
| 1181 | |
| 1182 | return result; |
| 1183 | } |
| 1184 | |
| 1185 | osd_font sdl_osd_interface::font_open(const char *_name, int &height) |
| 1186 | { |
| 1187 | // accept qualifiers from the name |
| 1188 | astring name(_name); |
| 1189 | if (name == "default") name = "Tahoma"; |
| 1190 | bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); |
| 1191 | bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); |
| 1192 | |
| 1193 | // build a basic LOGFONT description of what we want |
| 1194 | LOGFONT logfont; |
| 1195 | logfont.lfHeight = DEFAULT_FONT_HEIGHT; |
| 1196 | logfont.lfWidth = 0; |
| 1197 | logfont.lfEscapement = 0; |
| 1198 | logfont.lfOrientation = 0; |
| 1199 | logfont.lfWeight = bold ? FW_BOLD : FW_MEDIUM; |
| 1200 | logfont.lfItalic = italic; |
| 1201 | logfont.lfUnderline = FALSE; |
| 1202 | logfont.lfStrikeOut = FALSE; |
| 1203 | logfont.lfCharSet = ANSI_CHARSET; |
| 1204 | logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; |
| 1205 | logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
| 1206 | logfont.lfQuality = NONANTIALIASED_QUALITY; |
| 1207 | logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
| 1208 | |
| 1209 | // copy in the face name |
| 1210 | TCHAR *face = wstring_from_utf8(name); |
| 1211 | wcsncpy(logfont.lfFaceName, face, sizeof(logfont.lfFaceName) / sizeof(TCHAR)); |
| 1212 | logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR)-1] = 0; |
| 1213 | osd_free(face); |
| 1214 | |
| 1215 | // create the font |
| 1216 | height = logfont.lfHeight; |
| 1217 | osd_font font = reinterpret_cast<osd_font>(CreateFontIndirect(&logfont)); |
| 1218 | if (font == NULL) |
| 1219 | return NULL; |
| 1220 | |
| 1221 | // select it into a temp DC and get the real font name |
| 1222 | HDC dummyDC = CreateCompatibleDC(NULL); |
| 1223 | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 1224 | TCHAR realname[100]; |
| 1225 | GetTextFace(dummyDC, ARRAY_LENGTH(realname), realname); |
| 1226 | SelectObject(dummyDC, oldfont); |
| 1227 | DeleteDC(dummyDC); |
| 1228 | |
| 1229 | // if it doesn't match our request, fail |
| 1230 | char *utf = utf8_from_wstring(realname); |
| 1231 | int result = core_stricmp(utf, name); |
| 1232 | osd_free(utf); |
| 1233 | |
| 1234 | // if we didn't match, nuke our font and fall back |
| 1235 | if (result != 0) |
| 1236 | { |
| 1237 | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 1238 | font = NULL; |
| 1239 | } |
| 1240 | return font; |
| 1241 | } |
| 1242 | |
| 1243 | |
1144 | 1244 | //------------------------------------------------- |
| 1245 | // font_close - release resources associated with |
| 1246 | // a given OSD font |
| 1247 | //------------------------------------------------- |
| 1248 | |
| 1249 | void sdl_osd_interface::font_close(osd_font font) |
| 1250 | { |
| 1251 | // delete the font ojbect |
| 1252 | if (font != NULL) |
| 1253 | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 1254 | } |
| 1255 | |
| 1256 | |
| 1257 | //------------------------------------------------- |
| 1258 | // font_get_bitmap - allocate and populate a |
| 1259 | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 1260 | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 1261 | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 1262 | // pixel of a black & white font |
| 1263 | //------------------------------------------------- |
| 1264 | |
| 1265 | bool sdl_osd_interface::font_get_bitmap(osd_font font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 1266 | { |
| 1267 | // create a dummy DC to work with |
| 1268 | HDC dummyDC = CreateCompatibleDC(NULL); |
| 1269 | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 1270 | |
| 1271 | // get the text metrics |
| 1272 | TEXTMETRIC metrics = { 0 }; |
| 1273 | GetTextMetrics(dummyDC, &metrics); |
| 1274 | |
| 1275 | // get the width of this character |
| 1276 | ABC abc; |
| 1277 | if (!GetCharABCWidths(dummyDC, chnum, chnum, &abc)) |
| 1278 | { |
| 1279 | abc.abcA = 0; |
| 1280 | abc.abcC = 0; |
| 1281 | GetCharWidth32(dummyDC, chnum, chnum, reinterpret_cast<LPINT>(&abc.abcB)); |
| 1282 | } |
| 1283 | width = abc.abcA + abc.abcB + abc.abcC; |
| 1284 | |
| 1285 | // determine desired bitmap size |
| 1286 | int bmwidth = (50 + abc.abcA + abc.abcB + abc.abcC + 50 + 31) & ~31; |
| 1287 | int bmheight = 50 + metrics.tmHeight + 50; |
| 1288 | |
| 1289 | // describe the bitmap we want |
| 1290 | BYTE bitmapinfodata[sizeof(BITMAPINFOHEADER)+2 * sizeof(RGBQUAD)] = { 0 }; |
| 1291 | BITMAPINFO &info = *reinterpret_cast<BITMAPINFO *>(bitmapinfodata); |
| 1292 | info.bmiHeader.biSize = sizeof(info.bmiHeader); |
| 1293 | info.bmiHeader.biWidth = bmwidth; |
| 1294 | info.bmiHeader.biHeight = -bmheight; |
| 1295 | info.bmiHeader.biPlanes = 1; |
| 1296 | info.bmiHeader.biBitCount = 1; |
| 1297 | info.bmiHeader.biCompression = BI_RGB; |
| 1298 | info.bmiHeader.biSizeImage = 0; |
| 1299 | info.bmiHeader.biXPelsPerMeter = GetDeviceCaps(dummyDC, HORZRES) / GetDeviceCaps(dummyDC, HORZSIZE); |
| 1300 | info.bmiHeader.biYPelsPerMeter = GetDeviceCaps(dummyDC, VERTRES) / GetDeviceCaps(dummyDC, VERTSIZE); |
| 1301 | info.bmiHeader.biClrUsed = 0; |
| 1302 | info.bmiHeader.biClrImportant = 0; |
| 1303 | RGBQUAD col1 = info.bmiColors[0]; |
| 1304 | RGBQUAD col2 = info.bmiColors[1]; |
| 1305 | col1.rgbBlue = col1.rgbGreen = col1.rgbRed = 0x00; |
| 1306 | col2.rgbBlue = col2.rgbGreen = col2.rgbRed = 0xff; |
| 1307 | |
| 1308 | // create a DIB to render to |
| 1309 | BYTE *bits; |
| 1310 | HBITMAP dib = CreateDIBSection(dummyDC, &info, DIB_RGB_COLORS, reinterpret_cast<VOID **>(&bits), NULL, 0); |
| 1311 | HGDIOBJ oldbitmap = SelectObject(dummyDC, dib); |
| 1312 | |
| 1313 | // clear the bitmap |
| 1314 | int rowbytes = bmwidth / 8; |
| 1315 | memset(bits, 0, rowbytes * bmheight); |
| 1316 | |
| 1317 | // now draw the character |
| 1318 | WCHAR tempchar = chnum; |
| 1319 | SetTextColor(dummyDC, RGB(0xff, 0xff, 0xff)); |
| 1320 | SetBkColor(dummyDC, RGB(0x00, 0x00, 0x00)); |
| 1321 | ExtTextOutW(dummyDC, 50 + abc.abcA, 50, ETO_OPAQUE, NULL, &tempchar, 1, NULL); |
| 1322 | |
| 1323 | // characters are expected to be full-height |
| 1324 | rectangle actbounds; |
| 1325 | actbounds.min_y = 50; |
| 1326 | actbounds.max_y = 50 + metrics.tmHeight - 1; |
| 1327 | |
| 1328 | // determine the actual left of the character |
| 1329 | for (actbounds.min_x = 0; actbounds.min_x < rowbytes; actbounds.min_x++) |
| 1330 | { |
| 1331 | BYTE *offs = bits + actbounds.min_x; |
| 1332 | UINT8 summary = 0; |
| 1333 | for (int y = 0; y < bmheight; y++) |
| 1334 | summary |= offs[y * rowbytes]; |
| 1335 | if (summary != 0) |
| 1336 | { |
| 1337 | actbounds.min_x *= 8; |
| 1338 | if (!(summary & 0x80)) actbounds.min_x++; |
| 1339 | if (!(summary & 0xc0)) actbounds.min_x++; |
| 1340 | if (!(summary & 0xe0)) actbounds.min_x++; |
| 1341 | if (!(summary & 0xf0)) actbounds.min_x++; |
| 1342 | if (!(summary & 0xf8)) actbounds.min_x++; |
| 1343 | if (!(summary & 0xfc)) actbounds.min_x++; |
| 1344 | if (!(summary & 0xfe)) actbounds.min_x++; |
| 1345 | break; |
| 1346 | } |
| 1347 | } |
| 1348 | |
| 1349 | // determine the actual right of the character |
| 1350 | for (actbounds.max_x = rowbytes - 1; actbounds.max_x >= 0; actbounds.max_x--) |
| 1351 | { |
| 1352 | BYTE *offs = bits + actbounds.max_x; |
| 1353 | UINT8 summary = 0; |
| 1354 | for (int y = 0; y < bmheight; y++) |
| 1355 | summary |= offs[y * rowbytes]; |
| 1356 | if (summary != 0) |
| 1357 | { |
| 1358 | actbounds.max_x *= 8; |
| 1359 | if (summary & 0x7f) actbounds.max_x++; |
| 1360 | if (summary & 0x3f) actbounds.max_x++; |
| 1361 | if (summary & 0x1f) actbounds.max_x++; |
| 1362 | if (summary & 0x0f) actbounds.max_x++; |
| 1363 | if (summary & 0x07) actbounds.max_x++; |
| 1364 | if (summary & 0x03) actbounds.max_x++; |
| 1365 | if (summary & 0x01) actbounds.max_x++; |
| 1366 | break; |
| 1367 | } |
| 1368 | } |
| 1369 | |
| 1370 | // allocate a new bitmap |
| 1371 | if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y) |
| 1372 | { |
| 1373 | bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y); |
| 1374 | |
| 1375 | // copy the bits into it |
| 1376 | for (int y = 0; y < bitmap.height(); y++) |
| 1377 | { |
| 1378 | UINT32 *dstrow = &bitmap.pix32(y); |
| 1379 | UINT8 *srcrow = &bits[(y + actbounds.min_y) * rowbytes]; |
| 1380 | for (int x = 0; x < bitmap.width(); x++) |
| 1381 | { |
| 1382 | int effx = x + actbounds.min_x; |
| 1383 | dstrow[x] = ((srcrow[effx / 8] << (effx % 8)) & 0x80) ? rgb_t(0xff, 0xff, 0xff, 0xff) : rgb_t(0x00, 0xff, 0xff, 0xff); |
| 1384 | } |
| 1385 | } |
| 1386 | |
| 1387 | // set the final offset values |
| 1388 | xoffs = actbounds.min_x - (50 + abc.abcA); |
| 1389 | yoffs = actbounds.max_y - (50 + metrics.tmAscent); |
| 1390 | } |
| 1391 | |
| 1392 | // de-select the font and release the DC |
| 1393 | SelectObject(dummyDC, oldbitmap); |
| 1394 | DeleteObject(dib); |
| 1395 | SelectObject(dummyDC, oldfont); |
| 1396 | DeleteDC(dummyDC); |
| 1397 | return bitmap.valid(); |
| 1398 | } |
| 1399 | |
| 1400 | #else |
| 1401 | |
| 1402 | //------------------------------------------------- |
1145 | 1403 | // font_open - attempt to "open" a handle to the |
1146 | 1404 | // font with the given name |
1147 | 1405 | //------------------------------------------------- |
r32113 | r32114 | |
1173 | 1431 | return false; |
1174 | 1432 | } |
1175 | 1433 | #endif |
| 1434 | #endif |