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