The official TMDC20 thread
category: general [glöplog]
Here's a feasibility study table for anyone who's thinking of making a table based rgb->text mode converter..
For those interested, the demos I've been making are using a 3x3x3 grid.Thats the smallest one I found that handles pipes and slashes and dashes.
3 levels of brightness doesn't seem a lot, but it really is 3 levels of local contrast, if you allow coloring.
3 levels of brightness doesn't seem a lot, but it really is 3 levels of local contrast, if you allow coloring.
wow, my account --it still exists; I could have sworn I found it removed at one point
Some days ago I accidentally discovered that GetTickCount() consistently has a resolution of 16ms, give or take a ms, at least on Windows 10. At first, I figured that this was a hidden vsync thing, but setting my refresh rate to 75hz didn't drop it down to 13ms. Does that mean it's simply the Windows kernel quantum length?
I made a little experiment (forgive my possibly ugly C code)
At 60hz, there's no visible tearing that I can see, yet it 'skips'; it's not smooth like I hoped.
I'm sure once I try it on my 75hz laptop it'll be even more stuttery.
Everywhere I search for vsync or tying a callback to vertical retrace, I find statements along the lines of "it's only possible in fullscreen." Clearly, that's not the case. You can do vsync in javascript now, within a not-fullscreen browser window.
So how do I find when vblank happens within Windows 5.0+, without violating the "no graphics acceleration" (which I assume means absolutely no GL/DX) rule? Not exactly specific to textmode, but still...
Some days ago I accidentally discovered that GetTickCount() consistently has a resolution of 16ms, give or take a ms, at least on Windows 10. At first, I figured that this was a hidden vsync thing, but setting my refresh rate to 75hz didn't drop it down to 13ms. Does that mean it's simply the Windows kernel quantum length?
I made a little experiment (forgive my possibly ugly C code)
At 60hz, there's no visible tearing that I can see, yet it 'skips'; it's not smooth like I hoped.
I'm sure once I try it on my 75hz laptop it'll be even more stuttery.
Everywhere I search for vsync or tying a callback to vertical retrace, I find statements along the lines of "it's only possible in fullscreen." Clearly, that's not the case. You can do vsync in javascript now, within a not-fullscreen browser window.
So how do I find when vblank happens within Windows 5.0+, without violating the "no graphics acceleration" (which I assume means absolutely no GL/DX) rule? Not exactly specific to textmode, but still...
Hmm, seems i never actually cared about any timing...
...this is the complete code for TextMode TVnoise by Tristar & Red Sector Inc.:
...this is the complete code for TextMode TVnoise by Tristar & Red Sector Inc.:
Code:
int form, color;
int charset[5] =
{
0xdb,
0xdc,
0xb1,
0xfe,
0xdf
};
int palette[2] =
{
0,
15
};
HANDLE wHnd; // Handle to write to the console.
HANDLE rHnd; // Handle to read from the console.
//°°°°°°°°°°°°°°°°°
//°°°°° MAIN
int main(int argc, char* argv[])
{
// Set up the handles for reading/writing:
wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
rHnd = GetStdHandle(STD_INPUT_HANDLE);
// Change the window title:
SetConsoleTitle("hArDy - TextMode TV Noise");
// Set up the required window size:
SMALL_RECT windowSize = {0, 0, 79, 49};
// Change the console window size:
SetConsoleWindowInfo(wHnd, TRUE, &windowSize);
// Create a COORD to hold the buffer size:
COORD bufferSize = {80, 50};
// Change the internal buffer size:
SetConsoleScreenBufferSize(wHnd, bufferSize);
// Set up the character buffer:
CHAR_INFO consoleBuffer[80*50];
// Set up the positions:
COORD charBufSize = {80,50};
COORD characterPos = {0,0};
SMALL_RECT writeArea = {0,0,79,49};
do
{
for (int y=0; y<50; ++y)
{
for (int x=0; x<80; ++x)
{
// float random = rand();
float random = 1.0f;
color = (int)random % 2;
form = (int)(random*999) % 5;
consoleBuffer[x+80*y].Char.AsciiChar = charset[form];
consoleBuffer[x+80*y].Attributes = palette[color];
}
}
// Write the characters:
WriteConsoleOutput(wHnd, consoleBuffer, charBufSize, characterPos, &writeArea);
} while (!GetAsyncKeyState(VK_ESCAPE) );
// Exit
return 0;
}
Quote:
Everywhere I search for vsync or tying a callback to vertical retrace, I find statements along the lines of "it's only possible in fullscreen." Clearly, that's not the case. You can do vsync in javascript now, within a not-fullscreen browser window.
Yeah, except that microsoft apparently hates textmode demos; vsync hasn't been possible in text mode since win95 or so. =)
Quote:
Yeah, except that microsoft apparently hates textmode demos; vsync hasn't been possible in text mode since win95 or so. =)
I don't need perfect vsync. In fact, upon more research, it looks like DWM in Windows 6.0+ (vista,7,8, 9 -0.9,10) pretty much takes care of that by triple buffering all the things.
To clarify:
I wish to 1) minimize, not necessarily eliminate, tears in Win XP/2000
2) minimize, not necessarily eliminate, dropped frames
And given it's possible to synchronize timing with the monitor across platforms in a freaking browser window I don't think that's an unreasonable request, even for windowed textmode :p
Further experimentation: I finally managed to try my initial code on my laptop. At 75hz, it drops no frames that I can tell, but I get anything but a smooth 5:4 pulldown for my 16ms interval. It's all sorts of janky.
Looks like the only way to get less than 16ms is to use "multimedia timers,"
So I gave a contrived hardcoded-to-13ms alteration a shot
Code:
//narrow bar
void nbar(CHAR_INFO buff[4000], int pos, int col)
{ if (pos < 0 || pos > 159) { return; }
col &=0xF;
if( pos & 1){ col <<= 4;}
const CHAR_INFO bar = {0xDD,col};
const CHAR_INFO black = { ' ', 0 };
for (int i = 0; i < 80; i++) { buff[i] = black; }
buff[pos >> 1] = bar;
CHAR_INFO* firstLine = buff;
for (CHAR_INFO* curLine = &buff[80]; curLine < &buff[80 * 49 + 1]; curLine += 80)
{ memcpy_s((void*)curLine, sizeof(CHAR_INFO) * 80, (void*)firstLine, sizeof(CHAR_INFO) * 80); }
}
VOID CALLBACK myCallBack(
_In_ PVOID lpParameter,
_In_ BOOLEAN TimerOrWaitFired
){ static SHORT pos = 0, yPos =0;
CONST HANDLE hdl = *(HANDLE*) lpParameter;
CHAR_INFO buff[80 * 50];
nbar(buff,pos,15);
pos = (pos + 1) % 160;
SMALL_RECT recv = { 0, 0, 79, 49 };
if(TryEnterCriticalSection(&ScreenBuffCriticalSection))
{ WriteConsoleOutput(hdl, buff, { 80, 50 }, { 0, 0 }, &recv);
LeaveCriticalSection(&ScreenBuffCriticalSection);
}
};
and
Code:
...
InitializeCriticalSectionAndSpinCount(&ScreenBuffCriticalSection,0x200);
...//critical section may be entirely unneeded, but I'm paranoid
TIMECAPS tc; UINT wTimerRes;
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
{ return -1;}
#define TARGET_RESOLUTION 13 // 13 ms test
wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
timeBeginPeriod(wTimerRes);
...
done = !CreateTimerQueueTimer(&timer,NULL,&myCallBack,(PVOID)&hdl,100, wTimerRes, WT_EXECUTEDEFAULT);
//esc key busywait goes here
It's definitely a lot smoother at 75hz; though it actually visibly tears every few seconds or so (I can tolerate that, though behavior under XP remains doubtful), but there are frequent dropped frames, likely due to the fact that (13ms)^-1 ~ 77hz.
In the unlikely case I produce just above BITS level compofiller before the deadline, I'd rather not hardcode it to a particular refresh rate. I want a (close enough to) vretrace callback.
Ed: is it just me or is Pouet's bbcode error checker complaining about buff[i] = black?
Code:
DWM_TIMING_INFO timing_info; timing_info.cbSize = sizeof(timing_info);
const HRESULT result = DwmGetCompositionTimingInfo(NULL,&timing_info);
...
cout << timing_info.qpcRefreshPeriod << " : qpcRefreshPeriod\n";
cout << timing_info.qpcVBlank << " : qpcVBlank\n";
LARGE_INTEGER freq;
const bool qpf_fail = QueryPerformanceFrequency(&freq); //grab QPC ticks per sec
ULONGLONG ullFreq = freq.QuadPart;
QPC_TIME qpcRefresh = timing_info.qpcRefreshPeriod;
double refreshFreq = ullFreq / timing_info.qpcRefreshPeriod;
cout << refreshFreq << " : hz"; //timing_info already has the integer ratio, this is a sanity check to see if qpcRefreshPeriod means what I think it means
const HANDLE hdl = GetStdHandle(STD_OUTPUT_HANDLE);
ULONGLONG max=0; long long diff;
while (!GetAsyncKeyState(VK_ESCAPE))
{ SetConsoleCursorPosition(hdl,{0,8}); //write over prior
const HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
LARGE_INTEGER curtime;
QueryPerformanceCounter(&curtime);
diff = timing_info.qpcVBlank - curtime.QuadPart; //time to next vblank in qpc ticks
if (abs(diff) > max){max = diff;} //for comparison to qpcRefreshPeriod, should approach but never touch
printf_s("%10lld until next vblank\n", diff);
printf_s("%10lld longest wait", max);
}
This looks extremely promising, as it behaves as expected. max(diff) does in fact approach qpcRefreshPeriod. Trouble is DWM is Vista+ only. Would an executable still run in XP if, upon checking the windows version to be XP, the codepath calling DwmGetCompositionTimingInfo is never touched? Or would the VS compiler set the minimum version of windows required for the outputed exe just by the existence of that function call?
I'm likely making this a far bigger deal than it actually is, maybe I shouldn't fuss with this anymore until I have some effects and animations carefully planned, mostly coded & benchmarked.
Quote:
I'm likely making this a far bigger deal than it actually is, maybe I shouldn't fuss with this anymore until I have some effects and animations carefully planned, mostly coded & benchmarked.
Quite probably yes, but on the other hand, sometimes it's the little things that really make a difference.
Quintix: I am glad you are asking these questions. I have never been clear on textmode vsync. I asked about it a while ago, and somebody told me not to worry about it, but I've never been 100% happy with that answer.
You can always load Dwm functions dynamically. Something like this (not tested) ---
Then you can call it as myDwmGetCompositionTimingInfo(hwnd, whatever). If you do not link with dwmapi.lib, you should be able to run fine even on platforms where dwm doesn't exist.
You can always load Dwm functions dynamically. Something like this (not tested) ---
Code:
HRESULT WINAPI (*myDwmGetCompositionTimingInfo)(HWND hwnd, DWM_TIMING_INFO *pTimingInfo) = NULL;
HINSTANCE dwm_dll = LoadLibrary("dwmapi.dll");
if(dwm_dll != NULL) myDwmGetCompositionTimingInfo = GetProcAddress(dwm_dll,"DwmGetCompositionTimingInfo");
Then you can call it as myDwmGetCompositionTimingInfo(hwnd, whatever). If you do not link with dwmapi.lib, you should be able to run fine even on platforms where dwm doesn't exist.
sol: in the past 'realtime converters' where not really welcome in the tmdc compo (atleast from what i got out of the jury comments). has that changed?
anyways here's some dithering converter for the sake of
anyways here's some dithering converter for the sake of
Quote:
sol: in the past 'realtime converters' where not really welcome in the tmdc compo (atleast from what i got out of the jury comments). has that changed?
I don't know what you're talking about =) basically all textmode demos do some kind of bitmap to ascii conversion. What was frowned upon is the fact that everybody kept using the exact same converters which got a bit boring.
Anyway, I haven't run TMDC since tmdc10..
ah i see :) must be my negative attitude
Quote:
You can always load Dwm functions dynamically. Something like this (not tested)
Note that you can also tell the linker to delay-load specific libraries. This way, the executable will still run if the specific dependency is not found, but it will crash when trying to call a function from that DLL. The nice thing is that you can keep your code unmodified, but use LoadLibrary + GetProcAddress to check if the DLL is present and contains the function you want to call. If you verified that, you can keep using the function as if you had linked it the "normal" way.
Thanks cxw & Saga
Back to more pertinent topics of massive lookup tables
I've spent the better part of the week trying to make the beginnings of one, the kinds of which I've yet to see used in a textmode demo. I doubt rapidly flipping between two characters every frame would count as "glitch mode" (or at least I hope it isn't).
But I'm still figuring where to go from here. Vague idea I'm clinging to is that jpeg happens to use 8x8 fixed marcoblocks. DCT coefficients may be plenty good enough for use as some sort of searchable hashmap. Isn't that how the original photomosaic tool of the late 90's worked?
Back to more pertinent topics of massive lookup tables
I've spent the better part of the week trying to make the beginnings of one, the kinds of which I've yet to see used in a textmode demo. I doubt rapidly flipping between two characters every frame would count as "glitch mode" (or at least I hope it isn't).
But I'm still figuring where to go from here. Vague idea I'm clinging to is that jpeg happens to use 8x8 fixed marcoblocks. DCT coefficients may be plenty good enough for use as some sort of searchable hashmap. Isn't that how the original photomosaic tool of the late 90's worked?
Quote:
I doubt rapidly flipping between two characters every frame would count as "glitch mode" (or at least I hope it isn't).
Well, it's not, but it looks painful. Also, a few TMDC's back someone did this and the youtube capture looks *awesome*, because it kills the flickering, but watching it "live" wasn't as much fun.
Quote:
But I'm still figuring where to go from here. Vague idea I'm clinging to is that jpeg happens to use 8x8 fixed marcoblocks. DCT coefficients may be plenty good enough for use as some sort of searchable hashmap. Isn't that how the original photomosaic tool of the late 90's worked?
Would love to see the results if you try this =)
Quote:
Well, it's not, but it looks painful. Also, a few TMDC's back someone did this and the youtube capture looks *awesome*, because it kills the flickering, but watching it "live" wasn't as much fun.
Also, it will be affected a lot by the output technology. CRT and projectors will probably induce headaches bit look right, while LCDs will smooth the thing out but maybe not at the same rate for each channel or following a straight curve, introducing weird colors, like peeks of green when mixing black and white. Worse thing is, it will be different from monitor to monitor.
That ring said, it could still be interesting, especially if you know the display setup won't change.
For those still waiting for the late, late invite, it's finally available!
For those wondering why it took so much time, just have a look at last's year's ;) And for anyone else wanting to do an ambitious invite in the fuure, I'd advise to first release a teaser or pre-inviteé At least it will cover the functional part, in case you miss your deadline :)
For those wondering why it took so much time, just have a look at last's year's ;) And for anyone else wanting to do an ambitious invite in the fuure, I'd advise to first release a teaser or pre-inviteé At least it will cover the functional part, in case you miss your deadline :)
Quote:
For those still waiting for the late, late invite, it's finally available!
Now that's downright demoralizingly good. Please do make a writeup of everything you did, I'd love to read it.
Maybe I should start a blog? but yeah, for a while now, I'v e been thinking about putting up "making of" material, like story boards and techniques, etc. :)
and I forgot saying
Thanks! ...but demoralizing was far from what I intended! :)
Quote:
Now that's downright demoralizingly good.
Thanks! ...but demoralizing was far from what I intended! :)
So yeah, uh, I have a progress bar done. So I'm not 100% sure I'll have the time to make the demo. We'll see. =)
Cut it closer than I feel comfortable, but got a demo done and submitted.
Yay, sol!
And I've... only discovered using timer queues is a bad idea, and have not progressed beyond that.
At least I've learned a thing or two, but otherwise, all I can say is that I'm so embarrassed.
And I've... only discovered using timer queues is a bad idea, and have not progressed beyond that.
At least I've learned a thing or two, but otherwise, all I can say is that I'm so embarrassed.
sol: YAY! \o/
4 Days left for everyone else to "make Textmode look good"...enough time to get sth decent done, get into the fun already...
...now or never, it may be the last TMDC ever! ;)
(-> extended deadline: 1 week extra until the 19th)
consider this a *bump*
4 Days left for everyone else to "make Textmode look good"...enough time to get sth decent done, get into the fun already...
...now or never, it may be the last TMDC ever! ;)
(-> extended deadline: 1 week extra until the 19th)
consider this a *bump*
BÄM!
Release submitted!
I am happy hardy again now! :)
Release submitted!
I am happy hardy again now! :)