void VDVideoWindow::Resize() { if (mSourceWidth > 0 && mSourceHeight > 0) { int w, h; if (mbUseSourcePAR) { double ratio = 1.0; if (mSourcePAR > 0) ratio = mSourcePAR; w = VDRoundToInt(mSourceHeight * mSourceAspectRatio * ratio * mZoom); } else if (mAspectRatio < 0) { w = VDRoundToInt(mSourceHeight * mSourceAspectRatio * mFreeAspectRatio * mZoom); } else { if (mbAspectIsFrameBased) w = VDRoundToInt(mSourceHeight * mAspectRatio * mZoom); else w = VDRoundToInt(mSourceWidth * mAspectRatio * mZoom); } h = VDRoundToInt(mSourceHeight * mZoom); if (w < 1) w = 1; if (h < 1) h = 1; SetWindowPos(mhwnd, NULL, 0, 0, w+8, h+8, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE); } }
sint32 VDAudioOutputDirectSoundW32::GetPosition() { mMutex.Lock(); uint32 pos = VDRoundToInt(mDSStreamPlayPosition * mMillisecsPerByte); mMutex.Unlock(); return pos; }
void VDUISetListViewColumnsW32(HWND hwnd, const float *relwidths, int count) { // do some simple validation float sum = 0; for(int i=0; i<count; ++i) { float w = relwidths[i]; if (w < 0.0f || w > 1e+10f) return; sum += w; } if (sum > 0.0f) { RECT r; GetClientRect(hwnd, &r); for(int i=0; i<count; ++i) { float w = relwidths[i]; int iw = 0; if (w > 0.0f && sum > 0.0f) { iw = VDRoundToInt(r.right * (w / sum)); r.right -= iw; sum -= w; } ListView_SetColumnWidth(hwnd, i, iw); } } }
bool VDLoopThrottle::Delay() { float desiredRatio = mThrottleFactor; if (desiredRatio >= 1.0f) return true; if (desiredRatio <= 0.0f) { ::Sleep(100); return false; } uint32 total = mActiveTimeWindowSum + mWaitTimeWindowSum; if (total > 0) { float delta = mActiveTimeWindowSum - total * mThrottleFactor; mWaitTime += delta * (0.1f / 16.0f); } if (mWaitTime > 0) { int delayTime = VDRoundToInt(mWaitTime); if (delayTime > 1000) delayTime = 1000; BeginWait(); ::Sleep(delayTime); EndWait(); } return true; }
void JobCreateScript(JobScriptOutput& output, const DubOptions *opt, bool bIncludeEditList = true, bool bIncludeTextInfo = true) { char *mem= NULL; char buf[4096]; long l; int audioSourceMode = g_project->GetAudioSourceMode(); switch(audioSourceMode) { case kVDAudioSourceMode_External: { const VDStringA& encodedFileName = VDEncodeScriptString(VDStringW(g_szInputWAVFile)); const VDStringA& encodedDriverName = VDEncodeScriptString(VDTextWToU8(g_project->GetAudioSourceDriverName(), -1)); // check if we have options to write out const InputFileOptions *opts = g_project->GetAudioSourceOptions(); if (opts) { int l; char buf[256]; l = opts->write(buf, (sizeof buf)/7*3); if (l) { membase64(buf+l, (char *)buf, l); output.addf("VirtualDub.audio.SetSource(\"%s\", \"%s\", \"%s\");", encodedFileName.c_str(), encodedDriverName.c_str(), buf+l); break; } } // no options output.addf("VirtualDub.audio.SetSource(\"%s\", \"%s\");", encodedFileName.c_str(), encodedDriverName.c_str()); } break; default: if (audioSourceMode >= kVDAudioSourceMode_Source) { int index = audioSourceMode - kVDAudioSourceMode_Source; if (!index) output.addf("VirtualDub.audio.SetSource(1);"); else output.addf("VirtualDub.audio.SetSource(1,%d);", index); break; } // fall through case kVDAudioSourceMode_None: output.addf("VirtualDub.audio.SetSource(0);"); break; } output.addf("VirtualDub.audio.SetMode(%d);", opt->audio.mode); output.addf("VirtualDub.audio.SetInterleave(%d,%d,%d,%d,%d);", opt->audio.enabled, opt->audio.preload, opt->audio.interval, opt->audio.is_ms, opt->audio.offset); output.addf("VirtualDub.audio.SetClipMode(%d,%d);", opt->audio.fStartAudio, opt->audio.fEndAudio); output.addf("VirtualDub.audio.SetConversion(%d,%d,%d,0,%d);", opt->audio.new_rate, opt->audio.newPrecision, opt->audio.newChannels, opt->audio.fHighQuality); if (opt->audio.mVolume >= 0.0f) output.addf("VirtualDub.audio.SetVolume(%d);", VDRoundToInt(256.0f * opt->audio.mVolume)); else output.addf("VirtualDub.audio.SetVolume();"); if (g_ACompressionFormat) { if (g_ACompressionFormat->mExtraSize) { mem = (char *)allocmem(((g_ACompressionFormat->mExtraSize+2)/3)*4 + 1); if (!mem) throw MyMemoryError(); membase64(mem, (char *)(g_ACompressionFormat+1), g_ACompressionFormat->mExtraSize); output.addf("VirtualDub.audio.SetCompressionWithHint(%d,%d,%d,%d,%d,%d,%d,\"%s\",\"%s\");" ,g_ACompressionFormat->mTag ,g_ACompressionFormat->mSamplingRate ,g_ACompressionFormat->mChannels ,g_ACompressionFormat->mSampleBits ,g_ACompressionFormat->mDataRate ,g_ACompressionFormat->mBlockSize ,g_ACompressionFormat->mExtraSize ,mem ,VDEncodeScriptString(g_ACompressionFormatHint).c_str() ); freemem(mem); } else output.addf("VirtualDub.audio.SetCompressionWithHint(%d,%d,%d,%d,%d,%d,\"%s\");" ,g_ACompressionFormat->mTag ,g_ACompressionFormat->mSamplingRate ,g_ACompressionFormat->mChannels ,g_ACompressionFormat->mSampleBits ,g_ACompressionFormat->mDataRate ,g_ACompressionFormat->mBlockSize ,VDEncodeScriptString(g_ACompressionFormatHint).c_str() ); } else output.addf("VirtualDub.audio.SetCompression();"); output.addf("VirtualDub.audio.EnableFilterGraph(%d);", opt->audio.bUseAudioFilterGraph); output.addf("VirtualDub.video.SetInputFormat(%d);", opt->video.mInputFormat); output.addf("VirtualDub.video.SetOutputFormat(%d);", opt->video.mOutputFormat); output.addf("VirtualDub.video.SetMode(%d);", opt->video.mode); output.addf("VirtualDub.video.SetSmartRendering(%d);", opt->video.mbUseSmartRendering); output.addf("VirtualDub.video.SetPreserveEmptyFrames(%d);", opt->video.mbPreserveEmptyFrames); output.addf("VirtualDub.video.SetFrameRate2(%u,%u,%d);", opt->video.mFrameRateAdjustHi, opt->video.mFrameRateAdjustLo, opt->video.frameRateDecimation); if (opt->video.frameRateTargetLo) { output.addf("VirtualDub.video.SetTargetFrameRate(%u,%u);", opt->video.frameRateTargetHi, opt->video.frameRateTargetLo); } output.addf("VirtualDub.video.SetIVTC(0, 0, 0, 0);"); if ((g_Vcompression.dwFlags & ICMF_COMPVARS_VALID) && g_Vcompression.fccHandler) { output.addf("VirtualDub.video.SetCompression(0x%08lx,%d,%d,%d);", g_Vcompression.fccHandler, g_Vcompression.lKey, g_Vcompression.lQ, g_Vcompression.lDataRate); l = ICGetStateSize(g_Vcompression.hic); if (l>0) { mem = (char *)allocmem(l + ((l+2)/3)*4 + 1); if (!mem) throw MyMemoryError(); if (ICGetState(g_Vcompression.hic, mem, l)<0) { freemem(mem); // throw MyError("Bad state data returned from compressor"); // Fine then, be that way. Stupid Pinnacle DV200 driver. mem = NULL; } if (mem) { membase64(mem+l, mem, l); // urk... Windows Media 9 VCM uses a very large configuration struct (~7K pre-BASE64). sprintf(buf, "VirtualDub.video.SetCompData(%d,\"", l); VDStringA line(buf); line += (mem+l); line += "\");"; output.adds(line.c_str()); freemem(mem); } } } else output.addf("VirtualDub.video.SetCompression();"); output.addf("VirtualDub.video.filters.Clear();"); // Add video filters FilterInstance *fa = (FilterInstance *)g_listFA.tail.next, *fa_next; int iFilter = 0; while(fa_next = (FilterInstance *)fa->next) { output.addf("VirtualDub.video.filters.Add(\"%s\");", strCify(fa->GetName())); if (fa->IsCroppingEnabled()) { const vdrect32& cropInsets = fa->GetCropInsets(); output.addf("VirtualDub.video.filters.instance[%d].SetClipping(%d,%d,%d,%d%s);" , iFilter , cropInsets.left , cropInsets.top , cropInsets.right , cropInsets.bottom , fa->IsPreciseCroppingEnabled() ? "" : ",0" ); } VDStringA scriptStr; if (fa->GetScriptString(scriptStr)) output.addf("VirtualDub.video.filters.instance[%d].%s;", iFilter, scriptStr.c_str()); if (!fa->IsEnabled()) output.addf("VirtualDub.video.filters.instance[%d].SetEnabled(false);", iFilter); VDParameterCurve *pc = fa->GetAlphaParameterCurve(); if (pc) { output.addf("declare curve = VirtualDub.video.filters.instance[%d].AddOpacityCurve();", iFilter); const VDParameterCurve::PointList& pts = pc->Points(); for(VDParameterCurve::PointList::const_iterator it(pts.begin()), itEnd(pts.end()); it!=itEnd; ++it) { const VDParameterCurvePoint& pt = *it; output.addf("curve.AddPoint(%g, %g, %d);", pt.mX, pt.mY, pt.mbLinear); } } ++iFilter; fa = fa_next; } // Add audio filters { VDAudioFilterGraph::FilterList::const_iterator it(g_audioFilterGraph.mFilters.begin()), itEnd(g_audioFilterGraph.mFilters.end()); int connidx = 0; int srcfilt = 0; output.addf("VirtualDub.audio.filters.Clear();"); for(; it!=itEnd; ++it, ++srcfilt) { const VDAudioFilterGraph::FilterEntry& fe = *it; output.addf("VirtualDub.audio.filters.Add(\"%s\");", strCify(VDTextWToU8(fe.mFilterName).c_str())); for(unsigned i=0; i<fe.mInputPins; ++i) { const VDAudioFilterGraph::FilterConnection& conn = g_audioFilterGraph.mConnections[connidx++]; output.addf("VirtualDub.audio.filters.Connect(%d, %d, %d, %d);", conn.filt, conn.pin, srcfilt, i); } VDPluginConfig::const_iterator itc(fe.mConfig.begin()), itcEnd(fe.mConfig.end()); for(; itc!=itcEnd; ++itc) { const unsigned idx = (*itc).first; const VDPluginConfigVariant& var = (*itc).second; switch(var.GetType()) { case VDPluginConfigVariant::kTypeU32: output.addf("VirtualDub.audio.filters.instance[%d].SetInt(%d, %d);", srcfilt, idx, var.GetU32()); break; case VDPluginConfigVariant::kTypeS32: output.addf("VirtualDub.audio.filters.instance[%d].SetInt(%d, %d);", srcfilt, idx, var.GetS32()); break; case VDPluginConfigVariant::kTypeU64: output.addf("VirtualDub.audio.filters.instance[%d].SetLong(%d, %I64d);", srcfilt, idx, var.GetU64()); break; case VDPluginConfigVariant::kTypeS64: output.addf("VirtualDub.audio.filters.instance[%d].SetLong(%d, %I64d);", srcfilt, idx, var.GetS64()); break; case VDPluginConfigVariant::kTypeDouble: output.addf("VirtualDub.audio.filters.instance[%d].SetDouble(%d, %g);", srcfilt, idx, var.GetDouble()); break; case VDPluginConfigVariant::kTypeAStr: output.addf("VirtualDub.audio.filters.instance[%d].SetString(%d, \"%s\");", srcfilt, idx, strCify(VDTextWToU8(VDTextAToW(var.GetAStr())).c_str())); break; case VDPluginConfigVariant::kTypeWStr: output.addf("VirtualDub.audio.filters.instance[%d].SetString(%d, \"%s\");", srcfilt, idx, strCify(VDTextWToU8(var.GetWStr(), -1).c_str())); break; case VDPluginConfigVariant::kTypeBlock: output.addf("VirtualDub.audio.filters.instance[%d].SetBlock(%d, %d, \"%s\");", srcfilt, idx, var.GetBlockLen(), VDEncodeBase64A(var.GetBlockPtr(), var.GetBlockLen()).c_str()); break; } } } } // Add subset information if (bIncludeEditList) { const FrameSubset& fs = g_project->GetTimeline().GetSubset(); output.addf("VirtualDub.subset.Clear();"); for(FrameSubset::const_iterator it(fs.begin()), itEnd(fs.end()); it!=itEnd; ++it) output.addf("VirtualDub.subset.Add%sRange(%I64d,%I64d);", it->bMask ? "Masked" : "", it->start, it->len); // Note that this must be AFTER the subset (we used to place it before, which was a bug). if (g_project->IsSelectionPresent()) { output.addf("VirtualDub.video.SetRangeFrames(%I64d,%I64d);", g_project->GetSelectionStartFrame(), g_project->GetSelectionEndFrame()); } else { output.addf("VirtualDub.video.SetRange();"); } } // Add text information if (bIncludeTextInfo) { typedef std::list<std::pair<uint32, VDStringA> > tTextInfo; const tTextInfo& textInfo = g_project->GetTextInfo(); output.addf("VirtualDub.project.ClearTextInfo();"); for(tTextInfo::const_iterator it(textInfo.begin()), itEnd(textInfo.end()); it!=itEnd; ++it) { char buf[5]={0}; memcpy(buf, &(*it).first, 4); output.addf("VirtualDub.project.AddTextInfo(\"%s\", \"%s\");", buf, VDEncodeScriptString((*it).second).c_str()); } } }
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); }
LRESULT VDVideoWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: { RECT rc; GetClientRect(mhwnd, &rc); } return TRUE; case WM_DESTROY: { volatile HWND hwnd = mhwnd; delete this; return DefWindowProc(hwnd, msg, wParam, lParam); } case WM_NCHITTEST: return mLastHitTest = HitTest((SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); case WM_NCCALCSIZE: if (wParam) return RecalcClientArea(*(NCCALCSIZE_PARAMS *)lParam); RecalcClientArea(*(RECT *)lParam); return 0; case WM_NCPAINT: NCPaint((HRGN)wParam); return 0; case WM_PAINT: { PAINTSTRUCT ps; if (HDC hdc = BeginPaint(mhwnd, &ps)) { NMHDR hdr; hdr.hwndFrom = mhwnd; hdr.idFrom = GetWindowLong(mhwnd, GWL_ID); hdr.code = VWN_REQUPDATE; SendMessage(GetParent(mhwnd), WM_NOTIFY, (WPARAM)hdr.idFrom, (LPARAM)&hdr); EndPaint(mhwnd, &ps); } } return 0; case WM_MOVE: break; case WM_SIZE: break; case WM_ENTERSIZEMOVE: mbResizing = true; break; case WM_EXITSIZEMOVE: mbResizing = false; break; case WM_WINDOWPOSCHANGING: if (mbResizing) { WINDOWPOS *pwp = ((WINDOWPOS *)lParam); pwp->flags |= SWP_NOZORDER; if (mAspectRatio > 0 || mbUseSourcePAR) { double ar = mbUseSourcePAR ? mSourcePAR > 0 ? mSourcePAR : 1.0 : mAspectRatio; if (!mbAspectIsFrameBased) ar *= (double)mSourceWidth / (double)mSourceHeight; bool bXMajor = pwp->cx > pwp->cy * ar; if (mLastHitTest == HTBOTTOM) bXMajor = false; else if (mLastHitTest == HTRIGHT) bXMajor = true; if (bXMajor) pwp->cy = VDRoundToInt(pwp->cx / ar); else pwp->cx = VDRoundToInt(pwp->cy * ar); } } break; case WM_WINDOWPOSCHANGED: { NMHDR hdr; RECT r; GetClientRect(mhwnd, &r); if (mSourceHeight > 0) { mZoom = (double)r.bottom / mSourceHeight; if (mAspectRatio < 0 && !mbUseSourcePAR) mFreeAspectRatio = r.right / (r.bottom * mSourceAspectRatio); } hdr.hwndFrom = mhwnd; hdr.idFrom = GetWindowLong(mhwnd, GWL_ID); hdr.code = VWN_RESIZED; if (mhwndChild) SetWindowPos(mhwndChild, NULL, 0, 0, r.right, r.bottom, SWP_NOZORDER); SendMessage(GetParent(mhwnd), WM_NOTIFY, (WPARAM)hdr.idFrom, (LPARAM)&hdr); } break; // explicitly pass this through to DefWindowProc for WM_SIZE and WM_MOVE case WM_CONTEXTMENU: OnContextMenu((sint16)LOWORD(lParam), (sint16)HIWORD(lParam)); break; case WM_COMMAND: OnCommand(LOWORD(wParam)); break; case WM_GETMINMAXINFO: { MINMAXINFO& mmi = *(MINMAXINFO *)lParam; DefWindowProc(mhwnd, msg, wParam, lParam); if (mmi.ptMinTrackSize.x < 9) mmi.ptMinTrackSize.x = 9; if (mmi.ptMinTrackSize.y < 9) mmi.ptMinTrackSize.y = 9; } return 0; } return DefWindowProc(mhwnd, msg, wParam, lParam); }