Skip to content

Instantly share code, notes, and snippets.

@diffstorm
Created August 10, 2023 18:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save diffstorm/e18c1a12bfb78eba55b1f0989a5a69d4 to your computer and use it in GitHub Desktop.
Save diffstorm/e18c1a12bfb78eba55b1f0989a5a69d4 to your computer and use it in GitHub Desktop.
C++ code drawing a fractal tree into bitmap image on Linux X11
/*
Fractal tree generation/drawing excercise in C++ on Linux X11 with native bitmap format support
Author : Eray Ozturk | erayozturk1@gmail.com
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <string>
#include <iostream>
#include <cstring>
#include <cmath>
//--------------------------------------------------------------------------------------------------
using namespace std;
//--------------------------------------------------------------------------------------------------
const float PI = 3.1415926536f;
//--------------------------------------------------------------------------------------------------
class myBitmap
{
public:
myBitmap() : gc(0), pixmap(0) {}
~myBitmap()
{
XFreeGC(display, gc);
XFreePixmap(display, pixmap);
XCloseDisplay(display);
}
bool create(int w, int h)
{
display = XOpenDisplay(nullptr);
if (!display) return false;
int screen = DefaultScreen(display);
gc = XCreateGC(display, RootWindow(display, screen), 0, 0);
pixmap = XCreatePixmap(display, RootWindow(display, screen), w, h, DefaultDepth(display, screen));
width = w;
height = h;
return true;
}
void setPenColor(unsigned long clr)
{
XSetForeground(display, gc, clr);
}
void saveBitmap(string path)
{
XImage* image = XGetImage(display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
FILE* file = fopen(path.c_str(), "wb");
if (!file)
{
cerr << "Error: Could not create or open file for writing." << endl;
return;
}
// Bitmap file header
unsigned char fileheader[14] = { 'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0 };
unsigned int fileSize = 54 + 4 * width * height;
memcpy(fileheader + 2, &fileSize, sizeof(unsigned int));
fwrite(fileheader, sizeof(unsigned char), 14, file);
// Bitmap info header
unsigned char infoheader[40] = { 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
static_cast<unsigned char>(width), static_cast<unsigned char>(width >> 8), static_cast<unsigned char>(width >> 16), static_cast<unsigned char>(width >> 24),
static_cast<unsigned char>(height), static_cast<unsigned char>(height >> 8), static_cast<unsigned char>(height >> 16), static_cast<unsigned char>(height >> 24),
1, 0, 32, 0
};
fwrite(infoheader, sizeof(unsigned char), 40, file);
// Write image data (BGRA)
unsigned char* imgData = reinterpret_cast<unsigned char*>(image->data);
for (int y = height - 1; y >= 0; y--)
{
for (int x = 0; x < width; x++)
{
unsigned int pixel = XGetPixel(image, x, y);
unsigned char b = pixel & 0xFF;
unsigned char g = (pixel >> 8) & 0xFF;
unsigned char r = (pixel >> 16) & 0xFF;
unsigned char a = (pixel >> 24) & 0xFF;
unsigned char rgba[4] = { b, g, r, a };
fwrite(rgba, sizeof(unsigned char), 4, file);
}
}
fclose(file);
XDestroyImage(image);
}
Display* getDisplay() { return display; }
Pixmap getPixmap() { return pixmap; }
GC getGC() { return gc; }
int getWidth() { return width; }
int getHeight() { return height; }
private:
Display* display;
Pixmap pixmap;
GC gc;
int width, height;
};
//--------------------------------------------------------------------------------------------------
class vector2
{
public:
vector2() { x = y = 0; }
vector2(int a, int b) { x = a; y = b; }
void set(int a, int b) { x = a; y = b; }
void rotate(float angle_r)
{
float _x = static_cast<float>(x),
_y = static_cast<float>(y),
s = sinf(angle_r),
c = cosf(angle_r),
a = _x * c - _y * s,
b = _x * s + _y * c;
x = static_cast<int>(a);
y = static_cast<int>(b);
}
int x, y;
};
//--------------------------------------------------------------------------------------------------
class fractalTree
{
public:
fractalTree() { _ang = DegToRadian(24.0f); }
float DegToRadian(float degree) { return degree * (PI / 180.0f); }
void create(myBitmap* bmp)
{
_bmp = bmp;
float line_len = 130.0f;
vector2 sp(_bmp->getWidth() / 2, _bmp->getHeight() - 1);
XDrawLine(_bmp->getDisplay(), _bmp->getPixmap(), _bmp->getGC(), sp.x, sp.y, sp.x, sp.y - static_cast<int>(line_len));
sp.y -= static_cast<int>(line_len);
drawRL(&sp, line_len, 0, true);
drawRL(&sp, line_len, 0, false);
}
private:
void drawRL(vector2* sp, float line_len, float a, bool rg)
{
line_len *= 0.75f;
if (line_len < 2.0f) return;
vector2 r(0, static_cast<int>(line_len));
if (rg) a -= _ang;
else a += _ang;
r.rotate(a);
r.x += sp->x;
r.y = sp->y - r.y;
XDrawLine(_bmp->getDisplay(), _bmp->getPixmap(), _bmp->getGC(), sp->x, sp->y, r.x, r.y);
drawRL(&r, line_len, a, true);
drawRL(&r, line_len, a, false);
}
myBitmap* _bmp;
float _ang;
};
//--------------------------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
Display* display = XOpenDisplay(nullptr);
if (!display) return 1;
myBitmap bmp;
bmp.create(640, 512);
bmp.setPenColor(0xFFFF00); // Yellow color
fractalTree tree;
tree.create(&bmp);
XCopyArea(display, bmp.getPixmap(), DefaultRootWindow(display), bmp.getGC(), 0, 0, bmp.getWidth(), bmp.getHeight(), 0, 20);
bmp.saveBitmap("fractalTree.bmp");
XFlush(display);
XCloseDisplay(display);
return 0;
}
//--------------------------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment