0.03 33.33333333
0.07 14.28571429
0.08 12.5
0.09 11.11111111
0.003 333.3333333
0.004 250
0.005 200
0.006 166.6666667
1.83715E+14 seconds
5825579.068 years
Tuesday, July 14, 2009
Whorld Choir
According to my calculations, the plasmagon patch would take almost 6 million years to return to its starting position, and that's not counting the pinwheel global oscillator. Yikes! I guess I can see why there's no such thing as LCM for real numbers but it bothers me somehow.
Saturday, April 05, 2008
Whorld/GL: only the beginning
It seems that Whorld's drawing code can't be directly ported to OpenGL, because OpenGL doesn't even handle concave polygons, never mind self-overlapping polygons or shapes composed of Bezier curves. The good news is, it might be possible to use a combination of GDI and OpenGL. GDI provides a function called FlattenPath, which turns a path containing Bezier curves into a (very large) set of line segments. This flattened path could then be passed to the glu tessellation functions, which would turn the path into a set of simple polygons that could be rendered directly in OpenGL. It all sounds a bit Rube Goldberg, but it might be worth it to achieve transparency and the many other effects available in OpenGL. The GDI FlattenPath function seems to be very fast, at least compared to the actual rendering done by StrokeAndFillPath.
Wednesday, February 06, 2008
compensating frame rate
If you change the frame rate, and want your patches to look the same, you must compensate the following variables: Ring Growth, and Color Speed. If you double the frame rate, halve Ring Growth and Color Speed. Yes, the app should take care of this for you, but for the moment it doesn't.
Patches that depend on a particular relationship to the frame rate (e.g. the Seed of Life patch) will require further tweaking.
Note that changing the frame rate will change the relative speed of the cascading delete, and there's currently no way to compensate for it. Sorry!
Patches that depend on a particular relationship to the frame rate (e.g. the Seed of Life patch) will require further tweaking.
Note that changing the frame rate will change the relative speed of the cascading delete, and there's currently no way to compensate for it. Sorry!
Saturday, January 26, 2008
bezier benchmarks (categorized)
frames = 500
playlist: new curve alg bench.whl
patch: default
Master Offsets:
Star Factor = 1
Even Curve = .2
Odd Curve = .2
draw mode = line (or fill/outline)
NOTE: app should be MAXIMIZED at 1024 x 768
Dell / W2K
draw mode: lines only
back buffer: auto (video memory)
OnTimer = 0.054 (0.29%)
Draw = 18.992 (99.71%)
math = 0.600 (3.15%)
GDI = 18.393 (96.57%)
total = 19.047
secs@frame = 0.38 (26.25 FPS)
2nd pass: similar
Bad Box / XP
draw mode: lines only
back buffer: auto (video memory)
OnTimer = 0.008 (0.16%)
Draw = 4.854 (99.84%)
math = 0.263 (5.41%)
GDI = 4.590 (94.42%)
total = 4.862
secs@frame = 0.010 (102.84 FPS)
Bad Box / XP
draw mode: fill/outline
back buffer: auto (video memory)
OnTimer = 0.008 (0.05%)
Draw = 16.735 (99.95%)
math = 0.270 (1.61%)
GDI = 16.466 (98.34%)
total = 16.744
secs@frame = 0.033 (29.86 FPS)
2nd pass: similar
not too good!
Bad Box / XP
draw mode: fill/outline
back buffer: system memory
OnTimer = 0.016 (0.09%)
Draw = 17.916 (99.91%)
math = 0.276 (1.54%)
GDI = 17.639 (98.37%)
total = 17.931
secs@frame = 0.036 (27.88 FPS)
2nd pass: similar
system memory is not helping
Z Dell / XP
FPS: 25
draw mode: fill/outline
back buffer: auto (video memory)
OnTimer = 0.014 (0.06%)
Draw = 21.519 (99.94%)
math = 0.145 (0.67%)
GDI = 21.374 (99.26%)
total = 21.533
secs@frame = 0.043 (23.22 FPS)
7 FPS *SLOWER* than Bad Box with back buffer in video memory? just terrible
Z Dell / XP
FPS: 25
draw mode: fill/outline
back buffer: system memory
OnTimer = 0.017 (0.12%)
Draw = 14.446 (99.98%)
math = 0.146 (1.01%)
GDI = 14.300 (98.88%)
total = 14.463
secs@frame = 0.029 (34.57 FPS)
brand-new 2.66 GHz Dell is maximum 5 FPS faster than 3-year old Bad Box?
system memory *is* helping in this case, WTF?
playlist: new curve alg bench.whl
patch: default
Master Offsets:
Star Factor = 1
Even Curve = .2
Odd Curve = .2
draw mode = line (or fill/outline)
NOTE: app should be MAXIMIZED at 1024 x 768
Dell / W2K
draw mode: lines only
back buffer: auto (video memory)
OnTimer = 0.054 (0.29%)
Draw = 18.992 (99.71%)
math = 0.600 (3.15%)
GDI = 18.393 (96.57%)
total = 19.047
secs@frame = 0.38 (26.25 FPS)
2nd pass: similar
Bad Box / XP
draw mode: lines only
back buffer: auto (video memory)
OnTimer = 0.008 (0.16%)
Draw = 4.854 (99.84%)
math = 0.263 (5.41%)
GDI = 4.590 (94.42%)
total = 4.862
secs@frame = 0.010 (102.84 FPS)
Bad Box / XP
draw mode: fill/outline
back buffer: auto (video memory)
OnTimer = 0.008 (0.05%)
Draw = 16.735 (99.95%)
math = 0.270 (1.61%)
GDI = 16.466 (98.34%)
total = 16.744
secs@frame = 0.033 (29.86 FPS)
2nd pass: similar
not too good!
Bad Box / XP
draw mode: fill/outline
back buffer: system memory
OnTimer = 0.016 (0.09%)
Draw = 17.916 (99.91%)
math = 0.276 (1.54%)
GDI = 17.639 (98.37%)
total = 17.931
secs@frame = 0.036 (27.88 FPS)
2nd pass: similar
system memory is not helping
Z Dell / XP
FPS: 25
draw mode: fill/outline
back buffer: auto (video memory)
OnTimer = 0.014 (0.06%)
Draw = 21.519 (99.94%)
math = 0.145 (0.67%)
GDI = 21.374 (99.26%)
total = 21.533
secs@frame = 0.043 (23.22 FPS)
7 FPS *SLOWER* than Bad Box with back buffer in video memory? just terrible
Z Dell / XP
FPS: 25
draw mode: fill/outline
back buffer: system memory
OnTimer = 0.017 (0.12%)
Draw = 14.446 (99.98%)
math = 0.146 (1.01%)
GDI = 14.300 (98.88%)
total = 14.463
secs@frame = 0.029 (34.57 FPS)
brand-new 2.66 GHz Dell is maximum 5 FPS faster than 3-year old Bad Box?
system memory *is* helping in this case, WTF?
Friday, January 25, 2008
benchmarks for improved curve generation
In previous versions, curves were unstable (i.e. they would jitter) when star factor was negative. This occurred because the curve points were being computed from integer vertices. The new version computes the curve points from real vertices. Also, the curves points are now generated at the same time as the vertices, in a single loop, instead of in a second pass. This is more efficient, and eliminates the need for a second point array.
Comparing 1.6.06 and 1.7.03
Only the math portion of Draw is compared.
playlist: new curve alg bench.whl
patch: default
Master Offsets:
Star Factor = 1
Even Curve = .2
Odd Curve = .2
Benchmark includes code between
while (NextPos != NULL) {
and
rp.Delete = !RingVisible;
plus MakeCurves in 1.6.06
1000 frames
pass 1.6.06 1.7.03
---- ------- -------
#1 .001157 .000998
#2 .001161 .000995 (14% faster)
In summary, the Draw math takes less time in 1.7.03, despite having added some major new features (global parameters, curve shear). Presumably the speedup is due to a combination of better-optimized code and reduced memory usage. The global parameters aren't free, but their cost is minimal: 1.7.03 drops to around .000930 if m_GlobRing is removed from Draw.
Total time for Draw in 1.7.03: .025 in line mode, off the chart in fill mode
Same exact tests, but on the bad box:
pass 1.6.06 1.7.03
---- ------- -------
#1 .000654 .000468
#2 .000653 .000468 (28% faster)
Total time for Draw: .009 in line mode, .022 in fill mode
Comparing 1.6.06 and 1.7.03
Only the math portion of Draw is compared.
playlist: new curve alg bench.whl
patch: default
Master Offsets:
Star Factor = 1
Even Curve = .2
Odd Curve = .2
Benchmark includes code between
while (NextPos != NULL) {
and
rp.Delete = !RingVisible;
plus MakeCurves in 1.6.06
1000 frames
pass 1.6.06 1.7.03
---- ------- -------
#1 .001157 .000998
#2 .001161 .000995 (14% faster)
In summary, the Draw math takes less time in 1.7.03, despite having added some major new features (global parameters, curve shear). Presumably the speedup is due to a combination of better-optimized code and reduced memory usage. The global parameters aren't free, but their cost is minimal: 1.7.03 drops to around .000930 if m_GlobRing is removed from Draw.
Total time for Draw in 1.7.03: .025 in line mode, off the chart in fill mode
Same exact tests, but on the bad box:
pass 1.6.06 1.7.03
---- ------- -------
#1 .000654 .000468
#2 .000653 .000468 (28% faster)
Total time for Draw: .009 in line mode, .022 in fill mode
Monday, June 19, 2006
swarm
in AddRing:
NOTE that this feature requires the skew curve fix (see above), otherwise curves will be horribly distorted.
int swcnt; // number of vertices in swarm polygon
int swidx; // index of swarm polygon's current vertex
int swrad; // radius of swarm polygon, in pixels
double theta = (PI * 2) * (double(swidx) / swcnt); // can be better optimized
Ring.Shift.x += sin(theta) * swrad;
Ring.Shift.y += cos(theta) * swrad;
swidx++;
swidx %= swcnt; // can be better optimized
NOTE that this feature requires the skew curve fix (see above), otherwise curves will be horribly distorted.
skew curve fix
Skew distorts curved rings; to avoid this, MakeCurves must use the skewed origin.
wrong:
iorg = CPoint(round(org.x), round(org.y));
correct:
iorg = CPoint(round(xshift), round(yshift));
wrong:
iorg = CPoint(round(org.x), round(org.y));
correct:
iorg = CPoint(round(xshift), round(yshift));
Monday, June 05, 2006
maximize list control within playlist dialog
void CPlaylistDlg::OnHideControls()
{
m_HideControls ^= 1;
CWnd *wp = GetWindow(GW_CHILD);
while (wp != NULL) {
if (wp != &m_List)
wp->ShowWindow(m_HideControls ? SW_HIDE : SW_SHOW);
wp = wp->GetNextWindow();
}
PostMessage(WM_SIZE);
}
void CPlaylistDlg::OnSize(UINT nType, int cx, int cy)
{
CToolDlg::OnSize(nType, cx, cy);
if (m_HideControls) {
CRect r;
GetClientRect(r);
m_List.MoveWindow(r);
} else
m_Resize.OnSize();
}
void CPlaylistDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
CToolDlg::OnShowWindow(bShow, nStatus);
if (bShow && !m_HideControls)
m_Resize.OnSize();
}
Friday, June 02, 2006
MIDI support for video functions
Assuming MIDI ranges equal 5 (the default):
Note that a value of 127 disables video. If this is undesirable, set Video Select's MIDI range to 4.99 instead of 5.
Note that numpad zero sets the cycle length to "all" which is effectively 10.
Video Select
num MIDI Video
pad Values Clip
0 0..12 0
1 13..25 1
2 26..38 2
3 39..51 3
4 52..63 4
5 64..76 5
6 77..89 6
7 90..101 7
8 102..114 8
9 115..126 9
. 127 None
Note that a value of 127 disables video. If this is undesirable, set Video Select's MIDI range to 4.99 instead of 5.
Video Blending
num MIDI
pad Values Blending description ROP code GDI name
0 0..12 ~Src & Dst AND inverted source with destination DSna
1 13..25 ~Src | Dst OR inverted source with destination DSno MERGEPAINT
2 26..38 Src & ~Dst AND source with inverted destination SDna SRCERASE
3 39..51 Src & ~Dst OR source with inverted destination SDno
4 52..63 Src & Dst AND source with destination DSa SRCAND
5 64..76 Src | Dst OR source with destination DSo SRCPAINT
6 77..89 Src ^ Dst XOR source with destination DSx SRCINVERT
7 90..101 ~(Src & Dst) AND source with destination, invert result DSan
8 102..114 ~(Src | Dst) OR source with destination, invert result DSon NOTSRCERASE
9 115..127 ~(Src ^ Dst) XOR source with destination, invert result DSxn
Video Cycle Length
num MIDI Cycle
pad Values Length
1 0..12 1
2 13..25 2
3 26..38 3
4 39..51 4
5 52..63 5
6 64..76 6
7 77..89 7
8 90..101 8
9 102..114 9
0 115..127 10
Note that numpad zero sets the cycle length to "all" which is effectively 10.
Tuesday, May 16, 2006
pre-fetching video
bool CPlaylistDlg::PreFetchVideo()
{
CAviToBmp vid;
for (int i = 0; i < BANKS; i++) {
int count = m_Bank[i].GetSize();
for (int j = 0; j < count; j++) {
LPCSTR Path = m_Bank[i][j].m_Path;
if (IsVideo(Path)) {
if (!vid.Open(Path))
return(FALSE);
}
}
}
return(TRUE);
}
This takes approx. 10 seconds for all 340 clips. We can't pre-open the clips because AVIStreamGetFrameOpen won't open more than 75 AVI files simultaneously (it fails with no error message). Not sure why just opening and closing the clips helps. Something to do with disk caching? Not sure how *much* it helps either.
The 10 second delay can be avoided by doing the pre-fetch in a background thread. Note the CoInitialize! AviFileOpen fails without it. This gives me a bad feeling that VfW isn't thread-safe...
UINT CPlaylistDlg::PreFetchVideoThread(LPVOID pParam)
{
CoInitialize(0);
CPlaylistDlg *pd = (CPlaylistDlg *)pParam;
if (!pd->PreFetchVideo())
AfxMessageBox("Can't pre-fetch video");
CoUninitialize();
return(0);
}
in CPlaylistDlg::Cache:
AfxBeginThread(PreFetchVideoThread, this,
THREAD_PRIORITY_BELOW_NORMAL, 0, 0, 0);
The 75 clip limit is apparently NOT due to XVID, it occurs with Cinepack too.
Test to determine how much of Open delay is due to AVIStreamGetFrameOpen. Result for 100 Opens:
total avg min max
Open 4.915 .049 .007 .087
GetFr. 0.790 .008 .007 .009
A second run gave very similar results:
Open 3.119 .031 .007 .087
GetFr. 0.741 .007 .007 .009
Result: AVIStreamGetFrameOpen is less than 15% of the average, but more importantly, it has a static cost of ~8 milliseconds. This makes a reasonable case for trying the partial pre-open strategy (pre-open all clips but without doing AVIStreamGetFrameOpen, and then do AVIStreamGetFrameOpen when the clip is selected).
Wednesday, May 10, 2006
exporting a looped movie
Tried exporting a bidirectional movie (plays forward and then plays in reverse). It's smoother than just letting the video jump back to the beginning but there's still a visible transition when the rings change direction.
int PassFrames = m_RangeLast - m_RangeFirst + 1;
int TotalFrames = (PassFrames - 1) * 2;
pd.Create();
int j = m_RangeLast;
pd.SetRange(0, TotalFrames);
for (int i = 0; i < TotalFrames; i++) {
if (i >= PassFrames)
sm.Seek(--j);
sm.Read();
HBITMAP bm = View->MakeDIB(&OutFrameSize, &m_InFrameSize, GetScaleToFit());
bool retc = bta.AddFrame(bm);
DeleteObject(bm);
if (!m_DisplayOutput) // prevent view from painting
View->ValidateRect(NULL); // must revalidate before SetPos
pd.SetPos(i);
if (pd.Canceled())
return(IDCANCEL);
}
Lissajous
Tried it. It's too predictable and hugs the edge of the frame too much. Not so good! The random motion is better.
Tuesday, May 09, 2006
video mirroring quadrant selection
CSize FrmSz(m_Size);
CSize SrcSz(vp->GetFrameSize());
CPoint SrcPt;
if (m_st.Mirror) {
FrmSz.cx = (FrmSz.cx + 1) >> 1;
FrmSz.cy = (FrmSz.cy + 1) >> 1;
switch (Quadrant) {
case 0: // upper left
SrcPt = CPoint(0, SrcSz.cy - 1);
SrcSz.cx >>= 1;
SrcSz.cy >>= 1;
SrcSz.cy = -SrcSz.cy;
break;
case 1: // upper right
SrcPt = CPoint(SrcSz.cx - 1, SrcSz.cy - 1);
SrcSz.cx >>= 1;
SrcSz.cy >>= 1;
SrcSz.cx = -SrcSz.cx;
SrcSz.cy = -SrcSz.cy;
break;
case 2: // lower left
SrcPt = CPoint(0, 0);
SrcSz.cx >>= 1;
SrcSz.cy >>= 1;
break;
case 3: // lower right
SrcPt = CPoint(SrcSz.cx - 1, 0);
SrcSz.cx >>= 1;
SrcSz.cy >>= 1;
SrcSz.cx = -SrcSz.cx;
break;
}
} else {
SrcPt = CPoint(0, SrcSz.cy - 1);
SrcSz.cy = -SrcSz.cy;
}
HDC sdc;
vp->GetDC(&sdc);
StretchBlt(dc, 0, 0, FrmSz.cx, FrmSz.cy, sdc,
SrcPt.x, SrcPt.y, SrcSz.cx, SrcSz.cy, m_VideoList.GetROP());
vp->ReleaseDC(sdc);
Monday, April 24, 2006
more optimizations
In Draw:
replaced CRect::OffsetRect in Bounds calc with inline
replaced CRect::PtInPect in inner loop with inline (BIG difference)
only calculate iorg if making Curves
benchmarks:
hot rod, 1024 x 768, maximized (but not full screen)
default patch, fill & outline, speed = 20 "curve fill bench.whl"
total Draw time for 1000 frames at 25 FPS, in seconds
average ring count = 193
1.4.04 has a noticeably larger deviation: most of the samples cluster around 12.64 but every fourth sample or so clusters around 12.83. No idea why! Generally the results are encouraging however. If we go by the averages, 1.4.04 is 64 microseconds slower per frame, which translates to an extra 1.6 milliseconds per second at 25 FPS. If we go by the worst case, 1.4.04 is 210 microseconds slower per frame, i.e. an extra 5.25 milliseconds per second (half a percent). Neither difference is likely to be significant.
For non-fill case, 1.4.04 is FASTER! Awesome. Presumably inlining PtInRect in the innermost loop made the big difference, let's see.
Yup, CRect::PtInRect was bad stuff. Not sure whether it was the function call or inefficiency within PtInRect itself, or maybe both.
An interesting question: why is the difference worse with fill/outline? Almost all of the added code gets executed regardless of draw mode. The only exceptions are the Convex test to decide rp.Color vs. PrevColor, and the (Curve || PrevCurve) test. Surely these can't account for 64..210 microseconds per frame?
replaced CRect::OffsetRect in Bounds calc with inline
replaced CRect::PtInPect in inner loop with inline (BIG difference)
only calculate iorg if making Curves
benchmarks:
hot rod, 1024 x 768, maximized (but not full screen)
default patch, fill & outline, speed = 20 "curve fill bench.whl"
total Draw time for 1000 frames at 25 FPS, in seconds
average ring count = 193
v1.1.01 v1.4.04
---------------
12.643 12.831
12.630 12.641
12.629 12.639
12.629 12.830
12.638 12.651
12.633 12.638
12.637 12.833
12.636 12.645
12.630 12.840
12.643
12.633
12.671
12.644
12.639
AVG AVG
12.634 12.698
1.4.04 has a noticeably larger deviation: most of the samples cluster around 12.64 but every fourth sample or so clusters around 12.83. No idea why! Generally the results are encouraging however. If we go by the averages, 1.4.04 is 64 microseconds slower per frame, which translates to an extra 1.6 milliseconds per second at 25 FPS. If we go by the worst case, 1.4.04 is 210 microseconds slower per frame, i.e. an extra 5.25 milliseconds per second (half a percent). Neither difference is likely to be significant.
Same exact test but without fill (still on hot rod):
v1.1.01 v1.4.04
---------------
0.428 0.413
0.428 0.413
For non-fill case, 1.4.04 is FASTER! Awesome. Presumably inlining PtInRect in the innermost loop made the big difference, let's see.
1.4.04 no fill, using CRect::PtInRect:
0.447
0.448
Yup, CRect::PtInRect was bad stuff. Not sure whether it was the function call or inefficiency within PtInRect itself, or maybe both.
An interesting question: why is the difference worse with fill/outline? Almost all of the added code gets executed regardless of draw mode. The only exceptions are the Convex test to decide rp.Color vs. PrevColor, and the (Curve || PrevCurve) test. Surely these can't account for 64..210 microseconds per frame?
per-ring curve decision benchmarks
Bottom line: The per-ring version (1.4.03) is very slightly faster than 1.4.02. The data shows a consistent improvement of between 5 and 10 microseconds per frame. This is the opposite of the expected result. Perhaps moving the curvature test into the main loop allowed the compiler to better optimize the initial pass (for trail)? It could also be a change in cache behavior.
#include "benchmark.h"
float sum;
int cnt;
void CWhorldView::Draw(HDC dc)
{
CBenchmark b;
.
.
.
sum += b.Elapsed();
cnt++;
if (cnt == 1000) {
CString s;
s.Format("%d %f %f\n", cnt, sum, sum / cnt);
AfxMessageBox(s);
}
total time (sum) in seconds for 1000 frames
default patch
1.4.02 1.4.03
--------------
1.448 1.436
1.448 1.436
1.442 1.435
1.442 1.439
1.446 1.440
default patch, speed and canvas scale at max
1.4.02 1.4.03
--------------
5.400 5.390
5.396 5.390
help changes for 1.4
add Odd Curve and Even Curve to parameters (done)
move Canvas Scale and Hue Loop Length from Options/General to Master (done)
change ReadFromPatch to Patch Mode and expand as needed (done)
update keyboard accelerators (done)
move Canvas Scale and Hue Loop Length from Options/General to Master (done)
change ReadFromPatch to Patch Mode and expand as needed (done)
update keyboard accelerators (done)
Sunday, April 16, 2006
using multimedia timer instead of windows timer
We can't use a multimedia timer all the time (as was suggested on the MFC forum), because it significantly increases CPU useage, e.g. 75% vs. 33%. Windows task-switching overhead is the most likely culprit, especially since using a custom timer thread instead of a multimedia timer produces identical behavior.
We could use a multimedia timer only during non-client modal states, but there's still a visible glitch, due to the phase difference between the windows timer and the multimedia timer. The difference varies from 0 to 1 timer periods, and I can't see any obvious way to avoid it. It's better than doing nothing, but it may have other side effects, so the SendMessage technique shown above may still be the best shot.
We could use a multimedia timer only during non-client modal states, but there's still a visible glitch, due to the phase difference between the windows timer and the multimedia timer. The difference varies from 0 to 1 timer periods, and I can't see any obvious way to avoid it. It's better than doing nothing, but it may have other side effects, so the SendMessage technique shown above may still be the best shot.
Friday, April 14, 2006
corrupt Mirror, Origin, Drawmode in patches
The first cases appeared on 10/08/2005. Many of the "frosty" patches had it, and the corrupt data propagated from them to other patches, via hybridization. All patches were fixed today. I can't replicate the behavior nor can I find any obvious cause in the current code.
Tuesday, April 11, 2006
closing aux frame displays file save dialog
In CMainFrame::DetachView, must remove aux view from document.
GetDoc()->RemoveView(m_AuxView); // remove aux view from our document
prevent non-client clicks from pausing app
The following works, provided the "Show window contents while dragging" system property is unchecked. The only side effects are a) left-clicking on the menu bar moves the cursor to the center of the menu bar (strange, but not really a problem), and b) close happens on button down instead of button up.
void CPersistDlg::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
switch (nHitTest) {
case HTCLOSE:
SendMessage(WM_SYSCOMMAND, SC_CLOSE, 0);
break;
case HTCAPTION:
SendMessage(WM_SYSCOMMAND, SC_MOVE, 0);
break;
default:
CDialog::OnNcLButtonDown(nHitTest, point);
break;
}
}
void CPersistDlg::OnNcRButtonDown(UINT nHitTest, CPoint point)
{
switch (nHitTest) {
case HTCAPTION:
case HTSYSMENU:
SendMessage(WM_CONTEXTMENU, (LONG)m_hWnd, MAKELONG(point.x, point.y));
break;
default:
CDialog::OnNcRButtonDown(nHitTest, point);
break;
}
}
Subscribe to:
Posts (Atom)
