#include "fragmentShader.hpp"
#include <cstdlib>
#include <cstring>
#include <netlog.h>

namespace render::kernel
{

FragmentShader::FragmentShader(const char *path, ShaderPatcher *patcher)
{
    this->patcher = patcher;

    FILE *file = fopen(path, "rb");
    fseek(file, 0, SEEK_END);
    int size = ftell(file);
    fseek(file, 0, SEEK_SET);
    SceGxmProgram *buf = (SceGxmProgram *)malloc(size);
    fread(buf, 1, size, file);
    fclose(file);

    int error = sceGxmShaderPatcherRegisterProgram(this->patcher->GetPatcher(), buf, &this->id);
    // netlog("fragment register %d", error);
    // free(buf);

    this->program = sceGxmShaderPatcherGetProgramFromId(this->id);

    SceGxmBlendInfo info = {
        .colorFunc = SCE_GXM_BLEND_FUNC_ADD,
        .alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
        .colorSrc  = SCE_GXM_BLEND_FACTOR_SRC_ALPHA,
        .colorDst  = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
        .alphaSrc  = SCE_GXM_BLEND_FACTOR_SRC_ALPHA,
        .alphaDst  = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
    };

    info.colorMask = SCE_GXM_COLOR_MASK_ALL;

    sceGxmShaderPatcherCreateFragmentProgram(
        this->patcher->GetPatcher(), this->id,
        SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, SCE_GXM_MULTISAMPLE_NONE,
        &info, this->program, &this->fProgram);
}

FragmentShader::~FragmentShader()
{
}

const SceGxmProgramParameter *FragmentShader::GetParam(const char *name)
{
    return sceGxmProgramFindParameterByName(this->program, name);
}

unsigned int FragmentShader::GetParamIndex(const char *name)
{
    const SceGxmProgramParameter *param = this->GetParam(name);
    return sceGxmProgramParameterGetResourceIndex(param);
}

void FragmentShader::Bind(SceGxmContext *ctx)
{
    sceGxmSetFragmentProgram(ctx, this->fProgram);
}

void FragmentShader::SetDefaultUniform(SceGxmContext *context, const SceGxmProgramParameter *param, unsigned int count, const float *data)
{
    void *buffer;
    sceGxmReserveFragmentDefaultUniformBuffer(context, &buffer);
    sceGxmSetUniformDataF(buffer, param, 0, count, data);
}

} // namespace render::kernel