Created
August 10, 2023 18:52
-
-
Save diffstorm/e18c1a12bfb78eba55b1f0989a5a69d4 to your computer and use it in GitHub Desktop.
C++ code drawing a fractal tree into bitmap image on Linux X11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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