mirror of
https://github.com/GMMan/DrawingSongHLE.git
synced 2025-12-17 01:16:11 +01:00
249 lines
7.9 KiB
C#
249 lines
7.9 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
|
|
public class MainController : MonoBehaviour
|
|
{
|
|
bool isMenu;
|
|
bool loaded;
|
|
Language cachedLanguage;
|
|
byte[] cachedBanner;
|
|
int menuTick;
|
|
float frameTimer;
|
|
float timePerFrame;
|
|
|
|
public ResourceManager resourceManager;
|
|
public AudioController audioController;
|
|
public AnimationDecoder animationDecoder;
|
|
public Framebuffer framebuffer;
|
|
|
|
public bool isPlaying { get; private set; }
|
|
public Language currentLanguage { get; private set; }
|
|
public int mainTick { get; private set; }
|
|
|
|
// Start is called before the first frame update
|
|
void Start()
|
|
{
|
|
timePerFrame = 1 / 60f;
|
|
ResetAll();
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
CheckAndLoadResources();
|
|
if (Input.GetKeyDown(KeyCode.LeftArrow))
|
|
{
|
|
if (currentLanguage == 0)
|
|
currentLanguage = (Language)((int)Language.Max - 1);
|
|
else
|
|
currentLanguage -= 1;
|
|
}
|
|
if (Input.GetKeyDown(KeyCode.RightArrow))
|
|
{
|
|
if (currentLanguage == Language.Max - 1)
|
|
currentLanguage = 0;
|
|
else
|
|
currentLanguage += 1;
|
|
}
|
|
if (Input.GetKeyDown(KeyCode.Return))
|
|
{
|
|
if (isMenu)
|
|
{
|
|
isMenu = false;
|
|
isPlaying = true;
|
|
}
|
|
}
|
|
if (Input.GetKeyDown(KeyCode.Escape))
|
|
{
|
|
if (!isMenu) isPlaying = !isPlaying;
|
|
}
|
|
if (Input.GetKeyDown(KeyCode.F5))
|
|
{
|
|
ResetAll();
|
|
}
|
|
|
|
frameTimer += Time.deltaTime;
|
|
//Debug.Log($"Time: dt = {Time.deltaTime}, ideal time per frame = {timePerFrame}");
|
|
bool shouldFlip = false;
|
|
while (frameTimer >= timePerFrame)
|
|
{
|
|
frameTimer -= timePerFrame;
|
|
Profiler.BeginSample("Main frame update");
|
|
animationDecoder.decodingActive = true;
|
|
FrameUpdate();
|
|
Profiler.EndSample();
|
|
shouldFlip = true;
|
|
}
|
|
if (shouldFlip) framebuffer.FrameUpdate();
|
|
}
|
|
|
|
private void FrameUpdate()
|
|
{
|
|
if (!loaded) return;
|
|
|
|
if (animationDecoder.framesDecoded == 0 || isPlaying && !isMenu)
|
|
{
|
|
if (animationDecoder.decodingActive)
|
|
{
|
|
Profiler.BeginSample("Animation decoder update");
|
|
animationDecoder.AnimUpdate();
|
|
Profiler.EndSample();
|
|
}
|
|
}
|
|
|
|
if (animationDecoder.framesDecoded == 0) return;
|
|
|
|
// Render to framebuffer
|
|
// First, create a buffer for the frame surrounding the animation area
|
|
const int SIDEBUF_WIDTH = 6;
|
|
const int SIDEBUF_HEIGHT = 6;
|
|
byte[] sideBuf = new byte[SIDEBUF_WIDTH * SIDEBUF_HEIGHT];
|
|
for (int y = 0; y < SIDEBUF_HEIGHT; ++y)
|
|
for (int x = 0; x < SIDEBUF_WIDTH; ++x)
|
|
{
|
|
sideBuf[(y + 2) % SIDEBUF_HEIGHT * SIDEBUF_WIDTH + ((x + 2) % SIDEBUF_WIDTH)] = animationDecoder.indexedPixels[y, x];
|
|
}
|
|
|
|
// Draw left and right frame and main anim area
|
|
for (int y = Config.animYPos; y < Config.animYPos + Config.ANIMATION_HEIGHT; ++y)
|
|
{
|
|
for (int x = 0; x < Config.animXPos; ++x)
|
|
{
|
|
framebuffer.SetPixel(x, y, Config.palette[sideBuf[y % SIDEBUF_HEIGHT * SIDEBUF_WIDTH + (x % SIDEBUF_WIDTH)]]);
|
|
}
|
|
for (int x = 0; x < Config.ANIMATION_WIDTH; ++x)
|
|
{
|
|
framebuffer.SetPixel(Config.animXPos + x, y, Config.palette[animationDecoder.indexedPixels[y - Config.animYPos, x]]);
|
|
}
|
|
for (int x = Config.animXPos + Config.ANIMATION_WIDTH; x < Config.FRAMEBUFFER_WIDTH; ++x)
|
|
{
|
|
framebuffer.SetPixel(x, y, Config.palette[sideBuf[y % SIDEBUF_HEIGHT * SIDEBUF_WIDTH + (x % SIDEBUF_WIDTH)]]);
|
|
}
|
|
}
|
|
|
|
// Draw top frame
|
|
for (int y = 0; y < Config.animYPos; ++y)
|
|
for (int x = 0; x < Config.FRAMEBUFFER_WIDTH; ++x)
|
|
{
|
|
framebuffer.SetPixel(x, y, Config.palette[sideBuf[y % SIDEBUF_HEIGHT * SIDEBUF_WIDTH + (x % SIDEBUF_WIDTH)]]);
|
|
}
|
|
|
|
// Clear bottom with black
|
|
for (int y = Config.animYPos + Config.FRAMEBUFFER_HEIGHT; y < Config.FRAMEBUFFER_HEIGHT; ++y)
|
|
for (int x = 0; x < Config.FRAMEBUFFER_WIDTH; ++x)
|
|
{
|
|
framebuffer.SetPixel(x, y, 0x0000);
|
|
}
|
|
|
|
if (cachedLanguage != currentLanguage || cachedBanner == null)
|
|
{
|
|
cachedLanguage = currentLanguage;
|
|
cachedBanner = resourceManager.GetLanguageBanner(currentLanguage);
|
|
}
|
|
|
|
if (isMenu || animationDecoder.framesDecoded < 8)
|
|
{
|
|
// Draw banner
|
|
int bannerYAdjust = Config.langBannerHeightAdjustments[(int)currentLanguage];
|
|
|
|
byte b = 0;
|
|
byte bitsRemaining = 0;
|
|
int i = 0;
|
|
for (int y = bannerYAdjust; y < Config.langBannerHeight - 2 * bannerYAdjust; ++y)
|
|
for (int x = 0; x < Config.ANIMATION_WIDTH; ++x)
|
|
{
|
|
if (bitsRemaining == 0)
|
|
{
|
|
b = cachedBanner[i++];
|
|
bitsRemaining = 8;
|
|
}
|
|
|
|
framebuffer.SetPixel(x + Config.animXPos, y + Config.langBannerYOffset, (b & 1) == 1 ? Config.langBannerFgColor : Config.langBannerBgColor);
|
|
b >>= 1;
|
|
--bitsRemaining;
|
|
}
|
|
}
|
|
|
|
if (isMenu)
|
|
{
|
|
if (menuTick % 0x40 < 0x30)
|
|
{
|
|
// Draw arrows and frame
|
|
DrawHorizontalTriangle(8, 60, 20, 18, Config.langBannerFgColor);
|
|
DrawHorizontalTriangle(312, 60, -20, 18, Config.langBannerFgColor);
|
|
DrawRectFrame(32, 27, 288, 93, Config.langBannerFgColor);
|
|
}
|
|
|
|
++menuTick;
|
|
}
|
|
}
|
|
|
|
void DrawHorizontalTriangle(int x, int y, int width, int height, ushort color)
|
|
{
|
|
if (width != 0 && height != 0)
|
|
{
|
|
int direction = width < 1 ? -1 : 1;
|
|
width *= direction;
|
|
int maxDist = 1;
|
|
int i = 0;
|
|
for (int xOff = 0; xOff < width; ++xOff)
|
|
{
|
|
for (int currDist = 0; currDist < maxDist; ++currDist)
|
|
{
|
|
framebuffer.SetPixel(x + xOff * direction, y + currDist, color);
|
|
if (currDist != 0)
|
|
{
|
|
framebuffer.SetPixel(x + xOff * direction, y - currDist, color);
|
|
}
|
|
}
|
|
|
|
i += height;
|
|
if (i >= width)
|
|
{
|
|
++maxDist;
|
|
i -= width;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawRectFrame(int left, int top, int right, int bottom, ushort color)
|
|
{
|
|
for (int x = left; x <= right; ++x)
|
|
{
|
|
framebuffer.SetPixel(x, top, color);
|
|
framebuffer.SetPixel(x, bottom, color);
|
|
}
|
|
// Note: original condition was top..bottom, but since we covered it with above,
|
|
// we can skip two rows
|
|
for (int y = top + 1; y < bottom; ++y)
|
|
{
|
|
framebuffer.SetPixel(left, y, color);
|
|
framebuffer.SetPixel(right, y, color);
|
|
}
|
|
}
|
|
|
|
void CheckAndLoadResources()
|
|
{
|
|
if (!loaded && resourceManager.isReady)
|
|
{
|
|
audioController.LoadResources();
|
|
animationDecoder.LoadResources();
|
|
loaded = true;
|
|
}
|
|
}
|
|
|
|
void ResetAll()
|
|
{
|
|
audioController.ResetController();
|
|
animationDecoder.ResetController();
|
|
loaded = false;
|
|
isPlaying = false;
|
|
isMenu = true;
|
|
menuTick = 0;
|
|
cachedBanner = null;
|
|
}
|
|
}
|