<commit_before>#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

namespace Papaya
{

internal uint32 AllocateEmptyTexture(int32 Width, int32 Height)
{
    uint32 Tex;
    glGenTextures(1, &Tex);
    glBindTexture(GL_TEXTURE_2D, Tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    return Tex;
}

internal uint32 LoadAndBindImage(char* Path)
{
    uint8* Image;
    int32 ImageWidth, ImageHeight, ComponentsPerPixel;
    Image = stbi_load(Path, &ImageWidth, &ImageHeight, &ComponentsPerPixel, 0);

    // Create texture
    GLuint Id_GLuint;
    glGenTextures(1, &Id_GLuint);
    glBindTexture(GL_TEXTURE_2D, Id_GLuint);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ImageWidth, ImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, Image);

    // Store our identifier
    free(Image);
    return (uint32)Id_GLuint;
}

internal void InitMesh(MeshInfo& Mesh, ShaderInfo Shader, Vec2 Pos, Vec2 Size, GLenum Usage)
{
    glGenBuffers(1, &Mesh.VboHandle);
    glBindBuffer(GL_ARRAY_BUFFER, Mesh.VboHandle);
    glGenVertexArrays(1, &Mesh.VaoHandle);
    glBindVertexArray(Mesh.VaoHandle);

    glEnableVertexAttribArray(Shader.Attributes[0]); // Position attribute
    glEnableVertexAttribArray(Shader.Attributes[1]); // UV attribute
    glEnableVertexAttribArray(Shader.Attributes[2]); // Color attribute

#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
    glVertexAttribPointer(Shader.Attributes[0], 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos));   // Position attribute
    glVertexAttribPointer(Shader.Attributes[1], 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv));    // UV attribute
    glVertexAttribPointer(Shader.Attributes[2], 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); // Color attribute
#undef OFFSETOF

    ImDrawVert Verts[6];
    Verts[0].pos = Vec2(Pos.x, Pos.y);                   Verts[0].uv = Vec2(0.0f, 1.0f); Verts[0].col = 0xffffffff;
    Verts[1].pos = Vec2(Size.x + Pos.x, Pos.y);          Verts[1].uv = Vec2(1.0f, 1.0f); Verts[1].col = 0xffffffff;
    Verts[2].pos = Vec2(Size.x + Pos.x, Size.y + Pos.y); Verts[2].uv = Vec2(1.0f, 0.0f); Verts[2].col = 0xffffffff;
    Verts[3].pos = Vec2(Pos.x, Pos.y);                   Verts[3].uv = Vec2(0.0f, 1.0f); Verts[3].col = 0xffffffff;
    Verts[4].pos = Vec2(Size.x + Pos.x, Size.y + Pos.y); Verts[4].uv = Vec2(1.0f, 0.0f); Verts[4].col = 0xffffffff;
    Verts[5].pos = Vec2(Pos.x, Size.y + Pos.y);          Verts[5].uv = Vec2(0.0f, 0.0f); Verts[5].col = 0xffffffff;
    glBufferData(GL_ARRAY_BUFFER, sizeof(Verts), Verts, Usage);
}

internal void PushUndo(PapayaMemory* Mem)
{
    if (Mem->Doc.Undo.Top == 0) // Buffer is empty
    {
        Mem->Doc.Undo.Base = (UndoData*)Mem->Doc.Undo.Start;
        Mem->Doc.Undo.Top = Mem->Doc.Undo.Start;
    }
    else if (Mem->Doc.Undo.Current->Next != 0) // Not empty and not at end. Reposition for overwrite.
    {
        Mem->Doc.Undo.Top = (int8*)Mem->Doc.Undo.Current + sizeof(UndoData) + 4 * Mem->Doc.Undo.Current->SizeX * Mem->Doc.Undo.Current->SizeY;
        Mem->Doc.Undo.Last = Mem->Doc.Undo.Current;
        Mem->Doc.Undo.Count = Mem->Doc.Undo.CurrentIndex + 1;
    }

    UndoData Data = {};
    Data.OpCode = PapayaUndoOp_Brush;
    Data.Prev = Mem->Doc.Undo.Last;
    Data.PosX = 0;
    Data.PosY = 0;
    Data.SizeX = Mem->Doc.Width;
    Data.SizeY = Mem->Doc.Height;

    uint64 BufSize = sizeof(UndoData) + 4 * Data.SizeX * Data.SizeY;
    void* Buf = malloc((size_t)BufSize);
    memcpy(Buf, &Data, sizeof(UndoData));
    glFinish();
    glBindTexture(GL_TEXTURE_2D, Mem->Doc.TextureID);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, (int8*)Buf + sizeof(UndoData)); 
    glFinish();

    uint64 BytesToRight = (int8*)Mem->Doc.Undo.Start + Mem->Doc.Undo.Size - (int8*)Mem->Doc.Undo.Top;
    if (BytesToRight < sizeof(UndoData)) // Not enough space for UndoData. Go to start.
    {
        // Reposition the base pointer
        while ((int8*)Mem->Doc.Undo.Base > (int8*)Mem->Doc.Undo.Top ||
               (int8*)Mem->Doc.Undo.Base < (int8*)Mem->Doc.Undo.Start + BufSize)
        {
            Mem->Doc.Undo.Base = Mem->Doc.Undo.Base->Next;
            Mem->Doc.Undo.Base->Prev = 0;
            Mem->Doc.Undo.Count--;
            Mem->Doc.Undo.CurrentIndex--;
        }

        Mem->Doc.Undo.Top = Mem->Doc.Undo.Start;
        memcpy(Mem->Doc.Undo.Top, Buf, (size_t)BufSize);

        if (Mem->Doc.Undo.Last) { Mem->Doc.Undo.Last->Next = (UndoData*)Mem->Doc.Undo.Top; }
        Mem->Doc.Undo.Last = (UndoData*)Mem->Doc.Undo.Top;
        Mem->Doc.Undo.Top = (int8*)Mem->Doc.Undo.Top + BufSize;
    }
    else if (BytesToRight < BufSize) // Enough space for UndoData, but not for image. Split image data.
    {
        // Reposition the base pointer
        while ((int8*)Mem->Doc.Undo.Base > (int8*)Mem->Doc.Undo.Top ||
               (int8*)Mem->Doc.Undo.Base < (int8*)Mem->Doc.Undo.Start + BufSize - BytesToRight)
        {
            Mem->Doc.Undo.Base = Mem->Doc.Undo.Base->Next;
            Mem->Doc.Undo.Base->Prev = 0;
            Mem->Doc.Undo.Count--;
            Mem->Doc.Undo.CurrentIndex--;
        }

        memcpy(Mem->Doc.Undo.Top, Buf, (size_t)BytesToRight);<commit_msg>Added wrap-around code for stack overwrites<commit_after>#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

namespace Papaya
{

internal uint32 AllocateEmptyTexture(int32 Width, int32 Height)
{
    uint32 Tex;
    glGenTextures(1, &Tex);
    glBindTexture(GL_TEXTURE_2D, Tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    return Tex;
}

internal uint32 LoadAndBindImage(char* Path)
{
    uint8* Image;
    int32 ImageWidth, ImageHeight, ComponentsPerPixel;
    Image = stbi_load(Path, &ImageWidth, &ImageHeight, &ComponentsPerPixel, 0);

    // Create texture
    GLuint Id_GLuint;
    glGenTextures(1, &Id_GLuint);
    glBindTexture(GL_TEXTURE_2D, Id_GLuint);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ImageWidth, ImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, Image);

    // Store our identifier
    free(Image);
    return (uint32)Id_GLuint;
}

internal void InitMesh(MeshInfo& Mesh, ShaderInfo Shader, Vec2 Pos, Vec2 Size, GLenum Usage)
{
    glGenBuffers(1, &Mesh.VboHandle);
    glBindBuffer(GL_ARRAY_BUFFER, Mesh.VboHandle);
    glGenVertexArrays(1, &Mesh.VaoHandle);
    glBindVertexArray(Mesh.VaoHandle);

    glEnableVertexAttribArray(Shader.Attributes[0]); // Position attribute
    glEnableVertexAttribArray(Shader.Attributes[1]); // UV attribute
    glEnableVertexAttribArray(Shader.Attributes[2]); // Color attribute

#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
    glVertexAttribPointer(Shader.Attributes[0], 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos));   // Position attribute
    glVertexAttribPointer(Shader.Attributes[1], 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv));    // UV attribute
    glVertexAttribPointer(Shader.Attributes[2], 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); // Color attribute
#undef OFFSETOF

    ImDrawVert Verts[6];
    Verts[0].pos = Vec2(Pos.x, Pos.y);                   Verts[0].uv = Vec2(0.0f, 1.0f); Verts[0].col = 0xffffffff;
    Verts[1].pos = Vec2(Size.x + Pos.x, Pos.y);          Verts[1].uv = Vec2(1.0f, 1.0f); Verts[1].col = 0xffffffff;
    Verts[2].pos = Vec2(Size.x + Pos.x, Size.y + Pos.y); Verts[2].uv = Vec2(1.0f, 0.0f); Verts[2].col = 0xffffffff;
    Verts[3].pos = Vec2(Pos.x, Pos.y);                   Verts[3].uv = Vec2(0.0f, 1.0f); Verts[3].col = 0xffffffff;
    Verts[4].pos = Vec2(Size.x + Pos.x, Size.y + Pos.y); Verts[4].uv = Vec2(1.0f, 0.0f); Verts[4].col = 0xffffffff;
    Verts[5].pos = Vec2(Pos.x, Size.y + Pos.y);          Verts[5].uv = Vec2(0.0f, 0.0f); Verts[5].col = 0xffffffff;
    glBufferData(GL_ARRAY_BUFFER, sizeof(Verts), Verts, Usage);
}

internal void PushUndo(PapayaMemory* Mem)
{
    if (Mem->Doc.Undo.Top == 0) // Buffer is empty
    {
        Mem->Doc.Undo.Base = (UndoData*)Mem->Doc.Undo.Start;
        Mem->Doc.Undo.Top = Mem->Doc.Undo.Start;
    }
    else if (Mem->Doc.Undo.Current->Next != 0) // Not empty and not at end. Reposition for overwrite.
    {
        uint64 BytesToRight = (int8*)Mem->Doc.Undo.Start + Mem->Doc.Undo.Size - (int8*)Mem->Doc.Undo.Current;
        uint64 BlockSize = sizeof(UndoData) + 4 * Mem->Doc.Undo.Current->SizeX * Mem->Doc.Undo.Current->SizeY;
        if (BytesToRight >= BlockSize)
        {
            Mem->Doc.Undo.Top = (int8*)Mem->Doc.Undo.Current + BlockSize;
        }
        else
        {
            Mem->Doc.Undo.Top = (int8*)Mem->Doc.Undo.Start + BlockSize - BytesToRight;
        }
        Mem->Doc.Undo.Last = Mem->Doc.Undo.Current;
        Mem->Doc.Undo.Count = Mem->Doc.Undo.CurrentIndex + 1;
    }

    UndoData Data = {};
    Data.OpCode = PapayaUndoOp_Brush;
    Data.Prev = Mem->Doc.Undo.Last;
    Data.PosX = 0;
    Data.PosY = 0;
    Data.SizeX = Mem->Doc.Width;
    Data.SizeY = Mem->Doc.Height;

    uint64 BufSize = sizeof(UndoData) + 4 * Data.SizeX * Data.SizeY;
    void* Buf = malloc((size_t)BufSize);
    memcpy(Buf, &Data, sizeof(UndoData));
    glFinish();
    glBindTexture(GL_TEXTURE_2D, Mem->Doc.TextureID);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, (int8*)Buf + sizeof(UndoData)); 
    glFinish();

    uint64 BytesToRight = (int8*)Mem->Doc.Undo.Start + Mem->Doc.Undo.Size - (int8*)Mem->Doc.Undo.Top;
    if (BytesToRight < sizeof(UndoData)) // Not enough space for UndoData. Go to start.
    {
        // Reposition the base pointer
        while (((int8*)Mem->Doc.Undo.Base >= (int8*)Mem->Doc.Undo.Top ||
               (int8*)Mem->Doc.Undo.Base < (int8*)Mem->Doc.Undo.Start + BufSize) &&
               Mem->Doc.Undo.Count > 0)
        {
            Mem->Doc.Undo.Base = Mem->Doc.Undo.Base->Next;
            Mem->Doc.Undo.Base->Prev = 0;
            Mem->Doc.Undo.Count--;
            Mem->Doc.Undo.CurrentIndex--;
        }

        Mem->Doc.Undo.Top = Mem->Doc.Undo.Start;
        memcpy(Mem->Doc.Undo.Top, Buf, (size_t)BufSize);

        if (Mem->Doc.Undo.Last) { Mem->Doc.Undo.Last->Next = (UndoData*)Mem->Doc.Undo.Top; }
        Mem->Doc.Undo.Last = (UndoData*)Mem->Doc.Undo.Top;
        Mem->Doc.Undo.Top = (int8*)Mem->Doc.Undo.Top + BufSize;
    }
    else if (BytesToRight < BufSize) // Enough space for UndoData, but not for image. Split image data.
    {
        // Reposition the base pointer
        while (((int8*)Mem->Doc.Undo.Base >= (int8*)Mem->Doc.Undo.Top ||
               (int8*)Mem->Doc.Undo.Base < (int8*)Mem->Doc.Undo.Start + BufSize - BytesToRight) &&
               Mem->Doc.Undo.Count > 0)
        {
            Mem->Doc.Undo.Base = Mem->Doc.Undo.Base->Next;
            Mem->Doc.Undo.Base->Prev = 0;
            Mem->Doc.Undo.Count--;
            Mem->Doc.Undo.CurrentIndex--;
        }

        memcpy(Mem->Doc.Undo.Top, Buf, (size_t)BytesToRight);
{'fraction_non_alphanumeric': 0.15587509572024164, 'fraction_numerical': 0.024419297200714712, 'mean_word_length': 3.0954703832752615, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 12, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1250080', 'n_tokens_mistral': 4608, 'n_tokens_neox': 4399, 'n_words': 746}