cpp

Graphics

04_Graphics⚙️
// Module 10: Expert Topics
// Lesson: Graphics Fundamentals (Console Rasterization)
// Build: g++ -std=c++17 01_graphics.cpp -o graphics_demo
// Description: Demonstrates a lightweight pixel buffer, drawing primitives, and animation timing.

#include <chrono>
#include <cmath>
#include <iostream>
#include <string>
#include <thread>
#include <vector>

using namespace std;

class Canvas
{
public:
    Canvas(int w, int h, char fill = ' ') : width_(w), height_(h), pixels_(w * h, fill) {}

    void clear(char fill = ' ')
    {
        fill_n(pixels_.begin(), pixels_.size(), fill);
    }

    void setPixel(int x, int y, char c)
    {
        if (x < 0 || y < 0 || x >= width_ || y >= height_)
        {
            return;
        }
        pixels_[y * width_ + x] = c;
    }

    void drawLine(int x0, int y0, int x1, int y1, char c)
    {
        int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
        int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
        int err = dx + dy;
        while (true)
        {
            setPixel(x0, y0, c);
            if (x0 == x1 && y0 == y1)
            {
                break;
            }
            int e2 = 2 * err;
            if (e2 >= dy)
            {
                err += dy;
                x0 += sx;
            }
            if (e2 <= dx)
            {
                err += dx;
                y0 += sy;
            }
        }
    }

    void drawCircle(int cx, int cy, int radius, char c)
    {
        for (int angle = 0; angle < 360; angle += 5)
        {
            double rad = angle * M_PI / 180.0;
            int x = static_cast<int>(cx + radius * cos(rad));
            int y = static_cast<int>(cy + radius * sin(rad));
            setPixel(x, y, c);
        }
    }

    void render() const
    {
        for (int y = 0; y < height_; ++y)
        {
            for (int x = 0; x < width_; ++x)
            {
                cout << pixels_[y * width_ + x];
            }
            cout << '\n';
        }
    }

    int width() const { return width_; }
    int height() const { return height_; }

private:
    int width_;
    int height_;
    vector<char> pixels_;
};

void printPart(const string &title)
{
    cout << "\n========== " << title << " ==========" << endl;
}

// PART 1: Drawing primitives.
void part1_primitives()
{
    printPart("PART 1: Static Drawing");
    Canvas canvas(40, 15);
    canvas.drawLine(0, 0, 39, 14, '/');
    canvas.drawLine(0, 14, 39, 0, '\\');
    canvas.drawCircle(20, 7, 6, '*');
    canvas.render();
}

// PART 2: Sprite blitting (simple bitmap copy).
void blitSprite(Canvas &canvas, int x, int y, const vector<string> &sprite)
{
    for (size_t row = 0; row < sprite.size(); ++row)
    {
        for (size_t col = 0; col < sprite[row].size(); ++col)
        {
            if (sprite[row][col] != ' ')
            {
                canvas.setPixel(static_cast<int>(x + col), static_cast<int>(y + row), sprite[row][col]);
            }
        }
    }
}

void part2_sprites()
{
    printPart("PART 2: Sprite Blitting");
    Canvas canvas(30, 10);
    vector<string> rocket = {
        "  ^  ",
        " /|\\ ",
        "/_|_\\",
        "  |  ",
        " / \",
    };
    blitSprite(canvas, 12, 2, rocket);
    canvas.render();
}

// PART 3: Basic animation loop.
void part3_animation()
{
    printPart("PART 3: Animation Loop");
    Canvas canvas(30, 10);
    for (int frame = 0; frame < 20; ++frame)
    {
        canvas.clear();
        int x = frame;
        int y = static_cast<int>(4 + 2 * sin(frame * 0.3));
        canvas.drawCircle(x, y, 2, '#');
        cout << "Frame " << setw(2) << frame << "\n";
        canvas.render();
        this_thread::sleep_for(chrono::milliseconds(120));
        cout << string(15, '\n');
    }
}

// PART 4: Discussion of real graphics stacks.
void part4_ecosystem()
{
    printPart("PART 4: Graphics Ecosystem Overview");
    cout << "- 2D: SDL2, SFML, Raylib offer windowing, input, textures." << endl;
    cout << "- 3D Low-level: OpenGL, Vulkan, Direct3D expose GPU pipelines." << endl;
    cout << "- High-level: Unreal, Unity, Godot wrap rendering + tooling." << endl;
    cout << "- Modern C++ engines use ECS (Entity Component System) and data-oriented design." << endl;
}

int main()
{
    part1_primitives();
    part2_sprites();
    part3_animation();
    part4_ecosystem();

    cout << "\nExercises:\n"
         << "1. Add Bresenham circles to avoid floating-point trig calls.\n"
         << "2. Implement double buffering to reduce flicker in the animation.\n"
         << "3. Extend Canvas to export PPM images for inspection.\n"
         << "4. Port the sprite system to SDL2 textures for real rendering.\n";
    return 0;
}
Graphics - C++ Tutorial | DeepML