DECLARE_PALETTED(Pal4, Any24) { const uint8 *src = (const uint8 *)src0; uint8 *dst = (uint8 *)dst0; const uint8 *pal = (const uint8 *)pal0; src += (w-1) >> 1; dst += ((w-1) & ~1) * 3; srcpitch += (w+1) >> 1; dstpitch += ((w+1) & ~1) * 3; do { int wt = w; uint8 v = src[0] >> (((-wt) & 1)*4); const uint8 *pe; switch(wt & 1) { do { v = src[0]; case 0: pe = &pal[3*(v&15)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 4; case 1: pe = &pal[3*(v&15)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 4; dst -= 6; --src; } while((wt -= 2) > 0); } vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
DECLARE_PALETTED(Pal4, Any32) { const uint8 *src = (const uint8 *)src0; uint32 *dst = (uint32 *)dst0; const uint32 *pal = (const uint32 *)pal0; src += (w-1) >> 1; dst += ((w-1) & ~1); srcpitch += (w+1) >> 1; dstpitch += ((w+1) & ~1) * 4; do { int wt = w; uint8 v = src[0] >> (((-wt) & 1)*4); switch(wt & 1) { do { v = src[0]; case 0: dst[1] = pal[v&15]; v >>= 4; case 1: dst[0] = pal[v&15]; v >>= 4; dst -= 2; --src; } while((wt -= 2) > 0); } vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
DECLARE_PALETTED(Pal2, Any32) { const uint8 *src = (const uint8 *)src0; uint32 *dst = (uint32 *)dst0; const uint32 *pal = (const uint32 *)pal0; src += (w-1) >> 2; dst += (w-1) & ~3; srcpitch += (w+3) >> 2; dstpitch += ((w+3) & ~3) * 4; do { int wt = w; uint8 v = src[0] >> (((-wt) & 3)*2); switch(wt & 3) { do { v = src[0]; case 0: dst[3] = pal[v&3]; v >>= 2; case 3: dst[2] = pal[v&3]; v >>= 2; case 2: dst[1] = pal[v&3]; v >>= 2; case 1: dst[0] = pal[v&3]; v >>= 2; dst -= 4; --src; } while((wt -= 4) > 0); } vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
DECLARE_PALETTED(Pal2, Any24) { const uint8 *src = (const uint8 *)src0; uint8 *dst = (uint8 *)dst0; const uint8 *pal = (const uint8 *)pal0; src += (w-1) >> 2; dst += ((w-1) & ~3) * 3; srcpitch += (w+3) >> 2; dstpitch += ((w+3) & ~3) * 3; do { int wt = w; uint8 v = src[0] >> (((-wt) & 3)*2); const uint8 *pe; switch(wt & 3) { do { v = src[0]; case 0: pe = &pal[3*(v&3)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 2; case 3: pe = &pal[3*(v&3)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 2; case 2: pe = &pal[3*(v&3)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 2; case 1: pe = &pal[3*(v&3)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 2; dst -= 12; --src; } while((wt -= 4) > 0); } vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
DECLARE_PALETTED(Pal8, Any32) { const uint8 *src = (const uint8 *)src0; uint32 *dst = (uint32 *)dst0; const uint32 *pal = (const uint32 *)pal0; srcpitch -= w; dstpitch -= w*4; do { int wt = w; do { *dst++ = pal[*src++]; } while(--wt); vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
DECLARE_PALETTED(Pal1, Any24) { const uint8 *src = (const uint8 *)src0; uint8 *dst = (uint8 *)dst0; const uint8 *pal = (const uint8 *)pal0; src += (w-1) >> 3; dst += ((w-1) & ~7) * 3; srcpitch += (w+7) >> 3; dstpitch += ((w+7) & ~7) * 3; do { int wt = w; uint8 v = src[0] >> ((-wt) & 7); const uint8 *pe; switch(wt & 7) { do { v = src[0]; case 0: pe = &pal[3*(v&1)]; dst[7*3+0] = pe[0]; dst[7*3+1] = pe[1]; dst[7*3+2] = pe[2]; v >>= 1; case 7: pe = &pal[3*(v&1)]; dst[6*3+0] = pe[0]; dst[6*3+1] = pe[1]; dst[6*3+2] = pe[2]; v >>= 1; case 6: pe = &pal[3*(v&1)]; dst[5*3+0] = pe[0]; dst[5*3+1] = pe[1]; dst[5*3+2] = pe[2]; v >>= 1; case 5: pe = &pal[3*(v&1)]; dst[4*3+0] = pe[0]; dst[4*3+1] = pe[1]; dst[4*3+2] = pe[2]; v >>= 1; case 4: pe = &pal[3*(v&1)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 1; case 3: pe = &pal[3*(v&1)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 1; case 2: pe = &pal[3*(v&1)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 1; case 1: pe = &pal[3*(v&1)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 1; dst -= 24; --src; } while((wt -= 8) > 0); } vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
DECLARE_PALETTED(Pal1, Any16) { const uint8 *src = (const uint8 *)src0; uint16 *dst = (uint16 *)dst0; const uint16 *pal = (const uint16 *)pal0; src += (w-1) >> 3; dst += (w-1) & ~7; srcpitch += (w+7) >> 3; dstpitch += ((w+7) & ~7) * 2; do { int wt = w; uint8 v = src[0] >> ((-wt) & 7); switch(wt & 7) { do { v = src[0]; case 0: dst[7] = pal[v&1]; v >>= 1; case 7: dst[6] = pal[v&1]; v >>= 1; case 6: dst[5] = pal[v&1]; v >>= 1; case 5: dst[4] = pal[v&1]; v >>= 1; case 4: dst[3] = pal[v&1]; v >>= 1; case 3: dst[2] = pal[v&1]; v >>= 1; case 2: dst[1] = pal[v&1]; v >>= 1; case 1: dst[0] = pal[v&1]; v >>= 1; dst -= 8; --src; } while((wt -= 8) > 0); } vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
DECLARE_PALETTED(Pal8, Any24) { const uint8 *src = (const uint8 *)src0; uint8 *dst = (uint8 *)dst0; const uint8 *pal = (const uint8 *)pal0; srcpitch -= w; dstpitch -= w*3; do { int wt = w; do { const uint8 *pe = &pal[3**src++]; dst[0] = pe[0]; dst[1] = pe[1]; dst[2] = pe[2]; dst += 3; } while(--wt); vdptrstep(src, srcpitch); vdptrstep(dst, dstpitch); } while(--h); }
void VDCreateTestPal8Video(VDGUIHandle h) { CPUEnableExtensions(CPUCheckForExtensions()); try { tVDInputDrivers inputDrivers; std::vector<int> xlat; VDGetInputDrivers(inputDrivers, IVDInputDriver::kF_Video); const VDStringW filter(VDMakeInputDriverFileFilter(inputDrivers, xlat)); const VDFileDialogOption opt[]={ { VDFileDialogOption::kSelectedFilter }, 0 }; int optval[1]={0}; const VDStringW srcfile(VDGetLoadFileName('pl8s', h, L"Choose source file", filter.c_str(), NULL, opt, optval)); if (srcfile.empty()) return; IVDInputDriver *pDrv; int filtidx = xlat[optval[0] - 1]; if (filtidx < 0) pDrv = VDAutoselectInputDriverForFile(srcfile.c_str(), IVDInputDriver::kF_Video); else { tVDInputDrivers::iterator itDrv(inputDrivers.begin()); std::advance(itDrv, filtidx); pDrv = *itDrv; } vdrefptr<InputFile> pIF(pDrv->CreateInputFile(0)); pIF->Init(srcfile.c_str()); const VDStringW dstfile(VDGetSaveFileName('pl8d', h, L"Choose destination 8-bit file", L"Audio-video interleaved (*.avi)\0*.avi\0All files\0*.*", L"avi", NULL, NULL)); if (dstfile.empty()) return; vdrefptr<IVDVideoSource> pVS; pIF->GetVideoSource(0, ~pVS); IVDStreamSource *pVSS = pVS->asStream(); const VDPosition frames = pVSS->getLength(); if (!pVS->setTargetFormat(nsVDPixmap::kPixFormat_XRGB8888)) throw MyError("Cannot set decompression format to 32-bit."); vdautoptr<IVDMediaOutputAVIFile> pOut(VDCreateMediaOutputAVIFile()); IVDMediaOutputStream *pVSOut = pOut->createVideoStream(); const VDPixmap& pxsrc = pVS->getTargetFormat(); const uint32 rowbytes = (pxsrc.w+3) & ~3; AVIStreamHeader_fixed hdr; hdr.fccType = 'sdiv'; hdr.fccHandler = 0; hdr.dwFlags = 0; hdr.wPriority = 0; hdr.wLanguage = 0; hdr.dwScale = pVSS->getStreamInfo().dwScale; hdr.dwRate = pVSS->getStreamInfo().dwRate; hdr.dwStart = 0; hdr.dwLength = 0; hdr.dwInitialFrames = 0; hdr.dwSuggestedBufferSize = 0; hdr.dwQuality = -1; hdr.dwSampleSize = 0; hdr.rcFrame.left = 0; hdr.rcFrame.top = 0; hdr.rcFrame.right = (short)pxsrc.w; hdr.rcFrame.bottom = (short)pxsrc.h; pVSOut->setStreamInfo(hdr); vdstructex<BITMAPINFOHEADER> bih; bih.resize(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*252); bih->biSize = sizeof(BITMAPINFOHEADER); bih->biWidth = pxsrc.w; bih->biHeight = pxsrc.h; bih->biPlanes = 1; bih->biBitCount = 8; bih->biCompression = BI_RGB; bih->biSizeImage = rowbytes*pxsrc.h; bih->biXPelsPerMeter = 0; bih->biYPelsPerMeter = 0; bih->biClrUsed = 252; bih->biClrImportant = 252; RGBQUAD *pal = (RGBQUAD *)((char *)bih.data() + sizeof(BITMAPINFOHEADER)); for(int i=0; i<252; ++i) { pal[i].rgbRed = (BYTE)((i/42)*51); pal[i].rgbGreen = (BYTE)((((i/6)%7)*85)>>1); pal[i].rgbBlue = (BYTE)((i%6)*51); pal[i].rgbReserved = 0; } pVSOut->setFormat(bih.data(), bih.size()); pOut->init(dstfile.c_str()); ProgressDialog dlg((HWND)h, "Processing video stream", "Palettizing frames", (long)frames, true); vdblock<uint8> outbuf(rowbytes * pxsrc.h); const vdpixsize w = pxsrc.w; const vdpixsize h = pxsrc.h; try { for(uint32 frame=0; frame<frames; ++frame) { pVS->getFrame(frame); const uint8 *src = (const uint8 *)pxsrc.data; ptrdiff_t srcpitch = pxsrc.pitch; uint8 *dst = &outbuf[rowbytes * (pxsrc.h - 1)]; for(int y=0; y<h; ++y) { const uint8 *dr = ditherred[y & 15]; const uint8 *dg = dithergrn[y & 15]; const uint8 *db = ditherblu[y & 15]; for(int x=0; x<w; ++x) { const uint8 b = (uint8)((((src[0] * 1286)>>8) + dr[x&15]) >> 8); const uint8 g = (uint8)((((src[1] * 1543)>>8) + dg[x&15]) >> 8); const uint8 r = (uint8)((((src[2] * 1286)>>8) + db[x&15]) >> 8); src += 4; dst[x] = (uint8)(r*42 + g*6 + b); } vdptrstep(dst, -(ptrdiff_t)rowbytes); vdptrstep(src, srcpitch - w*4); } pVSOut->write(AVIOutputStream::kFlagKeyFrame, outbuf.data(), outbuf.size(), 1); dlg.advance(frame); dlg.check(); } } catch(const MyUserAbortError&) { } pVSOut->flush(); pOut->finalize(); } catch(const MyError& e) { e.post((HWND)h, g_szError); } }
void tool_fontextract(const vdfastvector<const char *>& args, const vdfastvector<const char *>& switches) { if (args.size() < 6) help_fontextract(); printf("Asuka: Extracting font: %s -> %s.\n", args[0], args[4]); int startChar; int endChar; if (1 != sscanf(args[2], "%d", &startChar) || 1 != sscanf(args[3], "%d", &endChar)) help_fontextract(); if (startChar < 0 || endChar > 0xFFFF || endChar <= startChar) { printf("Asuka: Invalid character range %d-%d\n", startChar, endChar); exit(10); } int fontsAdded = AddFontResourceEx(args[0], FR_NOT_ENUM | FR_PRIVATE, 0); if (!fontsAdded) { printf("Asuka: Unable to load font file: %s\n", args[0]); exit(10); } HFONT hfont = CreateFontA(10, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]); if (!hfont) { printf("Asuka: Unable to instantiate font: %s\n", args[1]); exit(10); } HDC hdc = CreateDC("DISPLAY", 0, 0, 0); HGDIOBJ hfontOld = SelectObject(hdc, hfont); MAT2 m = { {0,1},{0,0},{0,0},{0,1} }; union { OUTLINETEXTMETRICW m; char buf[2048]; } metrics; if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) { printf("Asuka: Unable to retrieve outline text metrics.\n"); exit(10); } SelectObject(hdc, hfontOld); DeleteObject(hfont); hfont = CreateFontA(metrics.m.otmEMSquare, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]); if (!hfont) { printf("Asuka: Unable to instantiate font: %s\n", args[1]); exit(10); } hfontOld = SelectObject(hdc, hfont); if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) { printf("Asuka: Unable to retrieve outline text metrics.\n"); exit(10); } FILE *f = fopen(args[4], "w"); if (!f) { printf("Asuka: Unable to open output file: %s\n", args[4]); exit(10); } std::vector<GlyphInfo> glyphs(endChar - startChar + 1); sint32 minX = 0x7FFFFFFF; sint32 minY = 0x7FFFFFFF; sint32 maxX = -0x7FFFFFFF - 1; sint32 maxY = -0x7FFFFFFF - 1; vdfastvector<sint32> points; vdfastvector<uint8> commands; for(int c=startChar; c<endChar; ++c) { GlyphInfo& info = glyphs[c - startChar]; info.mPointStart = points.size() >> 1; info.mCommandStart = commands.size(); GetCharABCWidthsFloatW(hdc, c, c, &info.mWidths); // encode glyph outline GLYPHMETRICS gm; if (GDI_ERROR == GetGlyphOutlineW(hdc, c, GGO_METRICS, &gm, 0, NULL, &m)) { printf("Asuka: Unable to obtain glyph metrics for char %d.\n", c); exit(20); } DWORD dwBytes = GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, 0, NULL, &m); if (dwBytes == 0xFFFFFFFF) { printf("Asuka: Unable to obtain glyph outline for char %d.\n", c); exit(20); } // GetGlyphOutline() doesn't like providing results for spaces. if (gm.gmBlackBoxX <= 0 || gm.gmBlackBoxY <= 0) continue; void *buf = malloc(dwBytes); GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, dwBytes, buf, &m); void *limit = (char *)buf + dwBytes; TTPOLYGONHEADER *pHdr = (TTPOLYGONHEADER *)buf; sint32 lastCode = 0; while(pHdr != limit) { VDASSERT(pHdr->dwType == TT_POLYGON_TYPE); sint32 x = *(const sint32 *)&pHdr->pfxStart.x; sint32 y = *(const sint32 *)&pHdr->pfxStart.y; if (minX > x) minX = x; if (minY > y) minY = y; if (maxX < x) maxX = x; if (maxY < y) maxY = y; points.push_back(x); points.push_back(y); TTPOLYCURVE *pCurve = (TTPOLYCURVE *)(pHdr + 1); TTPOLYCURVE *pCurveEnd = (TTPOLYCURVE *)((char *)pHdr + pHdr->cb); while(pCurve != pCurveEnd) { VDASSERT(pCurve->wType == TT_PRIM_QSPLINE || pCurve->wType == TT_PRIM_LINE); POINTFX *ppfx = pCurve->apfx; for(int i=0; i<pCurve->cpfx; ++i) { sint32 x = *(const sint32 *)&ppfx->x; sint32 y = *(const sint32 *)&ppfx->y; if (minX > x) minX = x; if (minY > y) minY = y; if (maxX < x) maxX = x; if (maxY < y) maxY = y; points.push_back(x); points.push_back(y); ++ppfx; } if (pCurve->wType == TT_PRIM_LINE) { if ((lastCode & 3) != 2) { if (lastCode) commands.push_back(lastCode); lastCode = 2 - 4; } for(int i=0; i<pCurve->cpfx; ++i) { if (lastCode >= 0x7C) { commands.push_back(lastCode); lastCode = 2 - 4; } lastCode += 4; } } else { VDASSERT(pCurve->wType == TT_PRIM_QSPLINE); VDASSERT(!(pCurve->cpfx % 2)); if ((lastCode & 3) != 3) { if (lastCode) commands.push_back(lastCode); lastCode = 3 - 4; } for(int i=0; i<pCurve->cpfx; i+=2) { if (lastCode >= 0x7C) { commands.push_back(lastCode); lastCode = 3 - 4; } lastCode += 4; } } pCurve = (TTPOLYCURVE *)ppfx; } if (lastCode) { commands.push_back(lastCode | 0x80); lastCode = 0; } vdptrstep(pHdr, pHdr->cb); } free(buf); } GlyphInfo& lastInfo = glyphs.back(); lastInfo.mPointStart = points.size() >> 1; lastInfo.mCommandStart = commands.size(); // write points fprintf(f, "// Created by Asuka from %s. DO NOT EDIT!\n\n", VDFileSplitPath(args[0])); fprintf(f, "const uint16 %s_FontPointArray[]={\n", args[5]); float scaleX = (maxX > minX) ? 1.0f / (maxX - minX) : 0.0f; float scaleY = (maxY > minY) ? 1.0f / (maxY - minY) : 0.0f; int pointElementCount = points.size(); for(int i=0; i<pointElementCount; i+=2) { uint8 x = VDClampedRoundFixedToUint8Fast((float)(points[i+0] - minX) * scaleX); uint8 y = VDClampedRoundFixedToUint8Fast((float)(points[i+1] - minY) * scaleY); uint16 pt = ((uint16)y << 8) + x; fprintf(f, "0x%04x,", pt); if ((i & 30) == 30) putc('\n', f); } if (pointElementCount & 30) putc('\n', f); fprintf(f, "};\n\n"); // write commands fprintf(f, "const uint8 %s_FontCommandArray[]={\n", args[5]); int commandElementCount = commands.size(); for(int i=0; i<commandElementCount; ++i) { fprintf(f, "0x%02x,", commands[i]); if ((i & 15) == 15) putc('\n', f); } if (commandElementCount & 15) putc('\n', f); fprintf(f, "};\n\n"); // glyph data structures fprintf(f, "const VDOutlineFontGlyphInfo %s_FontGlyphArray[]={\n", args[5]); for(int i=startChar; i<=endChar; ++i) { const GlyphInfo& info = glyphs[i - startChar]; fprintf(f, "{ %d, %d, %d, %d, %d },\n", info.mPointStart, info.mCommandStart, VDRoundToInt(info.mWidths.abcfA), VDRoundToInt(info.mWidths.abcfB), VDRoundToInt(info.mWidths.abcfC)); } fprintf(f, "};\n\n"); // top-level data structure fprintf(f, "const VDOutlineFontInfo %s_FontInfo={\n", args[5]); fprintf(f, "\t%s_FontPointArray,\n", args[5]); fprintf(f, "\t%s_FontCommandArray,\n", args[5]); fprintf(f, "\t%s_FontGlyphArray,\n", args[5]); fprintf(f, "\t%d, %d,\n", startChar, endChar); fprintf(f, "\t%d, %d, %d, %d,\t// bounds (16:16)\n", minX, minY, maxX, maxY); fprintf(f, "\t%d,\t// em square\n", metrics.m.otmEMSquare); fprintf(f, "\t%d,\t// ascent\n", metrics.m.otmAscent); fprintf(f, "\t%d,\t// descent\n", metrics.m.otmDescent); fprintf(f, "\t%d,\t// line gap\n", metrics.m.otmLineGap); fprintf(f, "};\n"); printf("Asuka: %d point bytes, %d command bytes, %d glyph info bytes.\n", (int)points.size(), (int)commands.size(), (endChar - startChar + 1) * 10); SelectObject(hdc, hfontOld); DeleteDC(hdc); DeleteObject(hfont); }