Initial commit
This commit is contained in:
BIN
assets/music.wav
Normal file
BIN
assets/music.wav
Normal file
Binary file not shown.
2
assets/resources.rc
Normal file
2
assets/resources.rc
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
VIDEO GIF "video.gif"
|
||||||
|
AUDIO WAVE "music.wav"
|
||||||
BIN
assets/video.gif
Normal file
BIN
assets/video.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
26
meson.build
Normal file
26
meson.build
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
project('goku', 'c')
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
winmm = cc.find_library('winmm')
|
||||||
|
|
||||||
|
|
||||||
|
windows = import('windows')
|
||||||
|
|
||||||
|
resources = windows.compile_resources('assets/resources.rc')
|
||||||
|
|
||||||
|
executable(
|
||||||
|
'goku',
|
||||||
|
[
|
||||||
|
files(
|
||||||
|
'src/main.c',
|
||||||
|
'src/stb_image.c',
|
||||||
|
'gifdec/gifdec.c',
|
||||||
|
),
|
||||||
|
resources,
|
||||||
|
],
|
||||||
|
include_directories: ['.'],
|
||||||
|
dependencies: [
|
||||||
|
dependency('openmp'),
|
||||||
|
winmm,
|
||||||
|
],
|
||||||
|
)
|
||||||
237
src/main.c
Normal file
237
src/main.c
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void PrintLastError() {
|
||||||
|
DWORD errorCode = GetLastError(); // Get the last error code
|
||||||
|
if (errorCode == 0) {
|
||||||
|
printf("No error occurred.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LPVOID lpMsgBuf;
|
||||||
|
DWORD bufLen;
|
||||||
|
|
||||||
|
// Format the message
|
||||||
|
bufLen = FormatMessage(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL,
|
||||||
|
errorCode,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPSTR)&lpMsgBuf,
|
||||||
|
0, NULL);
|
||||||
|
|
||||||
|
// Print the error message
|
||||||
|
if (bufLen) {
|
||||||
|
printf("Error %d: %s", errorCode, (LPSTR)lpMsgBuf);
|
||||||
|
LocalFree(lpMsgBuf); // Free the buffer allocated by FormatMessage
|
||||||
|
} else {
|
||||||
|
printf("Failed to format message for error %d.\n", errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Enable console colors
|
||||||
|
system("color");
|
||||||
|
|
||||||
|
// Get %TEMP% path
|
||||||
|
char tempPathDir[MAX_PATH];
|
||||||
|
GetTempPath2(MAX_PATH, tempPathDir);
|
||||||
|
|
||||||
|
// Get temporary name
|
||||||
|
char resPath[MAX_PATH];
|
||||||
|
GetTempFileName(tempPathDir, TEXT("virus"), 0, resPath);
|
||||||
|
|
||||||
|
// Get the current module handle
|
||||||
|
HMODULE thisExe = GetModuleHandle(NULL);
|
||||||
|
|
||||||
|
// Find resource
|
||||||
|
HRSRC resHandle = FindResourceA(thisExe, "VIDEO", "GIF");
|
||||||
|
|
||||||
|
// Get video resource
|
||||||
|
HGLOBAL resDataHandle = LoadResource(thisExe, resHandle);
|
||||||
|
|
||||||
|
// Get resource size
|
||||||
|
DWORD resSize = SizeofResource(thisExe, resHandle);
|
||||||
|
|
||||||
|
// Load resource data
|
||||||
|
void* resData = LockResource(resDataHandle);
|
||||||
|
|
||||||
|
// Load GIF
|
||||||
|
int *gifDelays, gifWidth, gifHeight, gifLength, gifComp;
|
||||||
|
uint8_t* gif = stbi_load_gif_from_memory(resData, resSize, &gifDelays, &gifWidth, &gifHeight, &gifLength, &gifComp, 3);
|
||||||
|
if (!gif)
|
||||||
|
puts(stbi_failure_reason());
|
||||||
|
|
||||||
|
// Unload resource data
|
||||||
|
UnlockResource(resDataHandle);
|
||||||
|
|
||||||
|
// Get console handle
|
||||||
|
HANDLE cmd = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
|
// Get the handle to the desktop window
|
||||||
|
HWND desktop = GetDesktopWindow();
|
||||||
|
|
||||||
|
// Get the device context for the desktop
|
||||||
|
HDC desktopDC = GetDC(desktop);
|
||||||
|
|
||||||
|
// Get the screen width and height
|
||||||
|
int screenWidth = GetDeviceCaps(desktopDC, HORZRES);
|
||||||
|
int screenHeight = GetDeviceCaps(desktopDC, VERTRES);
|
||||||
|
|
||||||
|
// Release the device context
|
||||||
|
ReleaseDC(desktop, desktopDC);
|
||||||
|
|
||||||
|
// Prepare data
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
int start_time;
|
||||||
|
int end_time;
|
||||||
|
int delta;
|
||||||
|
int gifPos;
|
||||||
|
int stride;
|
||||||
|
int cmdWidth, cmdHeight;
|
||||||
|
int oldCmdWidth = 0;
|
||||||
|
int oldCmdHeight = 0;
|
||||||
|
bool full_render = true;
|
||||||
|
bool skipped;
|
||||||
|
int lastx, lasty;
|
||||||
|
uint8_t* frame;
|
||||||
|
uint8_t* displayBuf = malloc(screenWidth * screenHeight * 3); // Working frame data
|
||||||
|
uint8_t* screenBuf = malloc(screenWidth * screenHeight * 3); // Present frame data
|
||||||
|
char* renderBuf = malloc(screenWidth * screenHeight * 40); // Render frame data
|
||||||
|
char* renderBufCur;
|
||||||
|
const float fGifWidth = (float)gifWidth;
|
||||||
|
const float fGifHeight = (float)gifHeight;
|
||||||
|
|
||||||
|
// display and screen buffers are oversized, to avoid resizing at runtime.
|
||||||
|
// Screen resolution SHOULD be enough...
|
||||||
|
|
||||||
|
// Rewind gif and play music
|
||||||
|
main_start:
|
||||||
|
gifPos = 0;
|
||||||
|
PlaySound(TEXT("AUDIO"), thisExe, SND_RESOURCE|SND_LOOP|SND_ASYNC);
|
||||||
|
|
||||||
|
main_loop:
|
||||||
|
// Prepare delta
|
||||||
|
start_time = GetTickCount();
|
||||||
|
|
||||||
|
// Get Console Size
|
||||||
|
GetConsoleScreenBufferInfo(cmd, &csbi);
|
||||||
|
cmdWidth = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||||
|
cmdHeight = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||||
|
cmdHeight *= 2;
|
||||||
|
stride = cmdWidth * 3;
|
||||||
|
|
||||||
|
// If resized, do full render
|
||||||
|
if (cmdWidth != oldCmdWidth || cmdHeight != oldCmdHeight)
|
||||||
|
full_render = true;
|
||||||
|
oldCmdWidth = cmdWidth;
|
||||||
|
oldCmdHeight = cmdHeight;
|
||||||
|
|
||||||
|
// Select frame
|
||||||
|
frame = gif + (gifWidth * gifHeight * 3 * gifPos);
|
||||||
|
|
||||||
|
// Project frame to display buffer
|
||||||
|
int by;
|
||||||
|
for (by = 0; by < cmdHeight; by++)
|
||||||
|
{
|
||||||
|
int bx;
|
||||||
|
for (bx = 0; bx < cmdWidth; bx++)
|
||||||
|
{
|
||||||
|
int gx = (int)(fGifWidth / cmdWidth * bx + 0.5f);
|
||||||
|
int gy = (int)(fGifHeight / cmdHeight * by + 0.5f);
|
||||||
|
int displayOffset = (by * cmdWidth + bx) * 3;
|
||||||
|
int gifOffset = (gy * gifWidth + gx) * 3;
|
||||||
|
displayBuf[displayOffset + 0] = frame[gifOffset + 0];
|
||||||
|
displayBuf[displayOffset + 1] = frame[gifOffset + 1];
|
||||||
|
displayBuf[displayOffset + 2] = frame[gifOffset + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render to console
|
||||||
|
skipped = true;
|
||||||
|
renderBufCur = renderBuf;
|
||||||
|
lastx = -1;
|
||||||
|
lasty = -1;
|
||||||
|
for (int by = 0; by < cmdHeight; by+=2)
|
||||||
|
for (int bx = 0; bx < cmdWidth; bx++)
|
||||||
|
{
|
||||||
|
// Check if pixel needs rendering
|
||||||
|
bool render_needed = false;
|
||||||
|
|
||||||
|
int offset = (by * cmdWidth + bx) * 3;
|
||||||
|
uint8_t dRed = displayBuf[offset + 0];
|
||||||
|
uint8_t dGreen = displayBuf[offset + 1];
|
||||||
|
uint8_t dBlue = displayBuf[offset + 2];
|
||||||
|
uint8_t sRed = screenBuf[offset + 0];
|
||||||
|
uint8_t sGreen = screenBuf[offset + 1];
|
||||||
|
uint8_t sBlue = screenBuf[offset + 2];
|
||||||
|
uint8_t dRedNxt = displayBuf[offset + stride + 0];
|
||||||
|
uint8_t dGreenNxt = displayBuf[offset + stride + 1];
|
||||||
|
uint8_t dBlueNxt = displayBuf[offset + stride + 2];
|
||||||
|
uint8_t sRedNxt = screenBuf[offset + stride + 0];
|
||||||
|
uint8_t sGreenNxt = screenBuf[offset + stride + 1];
|
||||||
|
uint8_t sBlueNxt = screenBuf[offset + stride + 2];
|
||||||
|
|
||||||
|
if (full_render || dRed != sRed || dGreen != sGreen || dBlue != sBlue)
|
||||||
|
{
|
||||||
|
render_needed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If render not needed, skip
|
||||||
|
if (!render_needed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Move cursor to correct pos
|
||||||
|
if (bx != lastx+1 || by != lasty)
|
||||||
|
renderBufCur += sprintf(renderBufCur, "\x1B[%d;%dH", by>>1, bx+1);
|
||||||
|
|
||||||
|
// Render pixel
|
||||||
|
renderBufCur += sprintf(
|
||||||
|
renderBufCur,
|
||||||
|
"\x1B[38;2;%d;%d;%dm\x1B[48;2;%d;%d;%dm\xDF",
|
||||||
|
dRed,
|
||||||
|
dGreen,
|
||||||
|
dBlue,
|
||||||
|
dRedNxt,
|
||||||
|
dGreenNxt,
|
||||||
|
dBlueNxt
|
||||||
|
);
|
||||||
|
lastx = bx;
|
||||||
|
lasty = by;
|
||||||
|
}
|
||||||
|
*renderBufCur = '\0';
|
||||||
|
full_render = false;
|
||||||
|
|
||||||
|
// Swap buffers
|
||||||
|
void* tempBuf = displayBuf;
|
||||||
|
displayBuf = screenBuf;
|
||||||
|
screenBuf = tempBuf;
|
||||||
|
|
||||||
|
// Display rendered frame
|
||||||
|
printf("%s", renderBuf);
|
||||||
|
|
||||||
|
// Compute delta
|
||||||
|
end_time = GetTickCount();
|
||||||
|
delta = end_time - start_time;
|
||||||
|
|
||||||
|
// Sleep
|
||||||
|
int sleep_time = gifDelays[gifPos] - delta;
|
||||||
|
if (sleep_time > 0)
|
||||||
|
Sleep(sleep_time);
|
||||||
|
|
||||||
|
// Switch frame
|
||||||
|
if (++gifPos == gifLength)
|
||||||
|
goto main_start;
|
||||||
|
|
||||||
|
// Repeat
|
||||||
|
goto main_loop;
|
||||||
|
}
|
||||||
2
src/stb_image.c
Normal file
2
src/stb_image.c
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
7988
src/stb_image.h
Normal file
7988
src/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user