How to get all pixel code that I draw on HWND? - c

I build some simple Direct2d program.
I draw something, and I need the pixel code of my HWND.
There are maybe 1920 * 1080 * 4 byte of pixel code of my Direct2d program,
But I don't know how to reach them.
So here is my code, and program screenshot, please anyone help me.
How to print HEX code of all of pixeldata?
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <d2d1.h>
#include <dwrite.h>
#include <iostream>
#include <ctime>
#include <atlconv.h>
#include <string>
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib")
ID2D1Factory* factory = NULL;
ID2D1HwndRenderTarget* target = NULL;
ID2D1SolidColorBrush* solid_brush;
IDWriteFactory* w_factory;
IDWriteTextFormat* w_format;
IDWriteTextLayout* w_layout;
using namespace std;
HWND hwnd;
int s_width = GetSystemMetrics(SM_CXSCREEN);
int s_height = GetSystemMetrics(SM_CYSCREEN);
clock_t start, endclock;
double result;
int fps = 0;
char fpsbuffer3[30];
char spectorbuffer[30];
void DrawString(string str, float fontSize, float x, float y, float r, float g, float b, float a)
{
RECT re;
GetClientRect(hwnd, &re);
FLOAT dpix, dpiy;
dpix = static_cast<float>(re.right - re.left);
dpiy = static_cast<float>(re.bottom - re.top);
USES_CONVERSION;
wstring bb(A2W(str.c_str()));
HRESULT res = w_factory->CreateTextLayout(bb.c_str(), bb.size(), w_format, 1920, 1080, &w_layout);
if (SUCCEEDED(res))
{
DWRITE_TEXT_RANGE range = { 0, str.length() };
w_layout->SetFontSize(fontSize, range);
solid_brush->SetColor(D2D1::ColorF(r, g, b, a));
target->DrawTextLayout(D2D1::Point2F(x, y), w_layout, solid_brush);
w_layout->Release();
w_layout = NULL;
}
}
void DrawBox(float x, float y, float width, float height, float thickness, float r, float g, float b, float a, bool filled)
{
solid_brush->SetColor(D2D1::ColorF(r, g, b, a));
if (filled) target->FillRectangle(D2D1::RectF(x, y, x + width, y + height), solid_brush);
else target->DrawRectangle(D2D1::RectF(x, y, x + width, y + height), solid_brush, thickness);
}
void DrawLine(float x1, float y1, float x2, float y2, float thickness, float r, float g, float b, float a) {
solid_brush->SetColor(D2D1::ColorF(r, g, b, a));
target->DrawLine(D2D1::Point2F(x1, y1), D2D1::Point2F(x2, y2), solid_brush, thickness);
}
void DrawCircle(float x, float y, float radius, float thickness, float r, float g, float b, float a, bool filled)
{
solid_brush->SetColor(D2D1::ColorF(r, g, b, a));
if (filled) target->FillEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius), solid_brush);
else target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius), solid_brush, thickness);
}
void DrawEllipse(float x, float y, float width, float height, float thickness, float r, float g, float b, float a, bool filled)
{
solid_brush->SetColor(D2D1::ColorF(r, g, b, a));
if (filled) target->FillEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), width, height), solid_brush);
else target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), width, height), solid_brush, thickness);
}
void Draw_Edge_String(string str, float fontSize, float x, float y, float r, float g, float b, float a)
{
DrawString(str, fontSize, x + 1, y, 0, 0, 0, 1);
DrawString(str, fontSize, x - 1, y, 0, 0, 0, 1);
DrawString(str, fontSize, x, y + 1, 0, 0, 0, 1);
DrawString(str, fontSize, x, y - 1, 0, 0, 0, 1);
DrawString(str, fontSize, x, y, r, g, b, a);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (iMessage) {
case WM_CREATE:
return 0;
//case WM_PAINT:
//return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
void render()
{
UpdateWindow(hwnd);
WINDOWINFO info;
ZeroMemory(&info, sizeof(info));
info.cbSize = sizeof(info);
D2D1_SIZE_U siz;
siz.height = s_height;//((info.rcClient.bottom) - (info.rcClient.top));
siz.width = s_width;//((info.rcClient.right) - (info.rcClient.left));
SetWindowPos(hwnd, NULL, 0, 0, s_width, s_height, SWP_SHOWWINDOW);
target->Resize(&siz);
target->BeginDraw();
target->Clear(D2D1::ColorF(1.0, 0, 0, 1.0));
DrawCircle(300, 300, 100, 1, 0, 1, 0, 1, 1);
endclock = clock();
result = (double)(endclock - start);
fps++;
if (result > 1000)
{
sprintf(fpsbuffer3, "Fps: %d", fps);
fps = 0;
start = endclock;
}
std::string a = string(fpsbuffer3);
DrawString(a, 20, siz.width - 100 + 2, 2, 0, 0, 0, 1);
DrawString(a, 20, siz.width - 100, 0, 1, 1, 1, 1);
//in here I want to print my pixel code. :(
target->EndDraw();
}
int main()
{
WNDCLASS wc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"classname";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
HWND hwnd = CreateWindow(L"classname", L"windowname", WS_POPUP, 0, 0, s_width, s_height, NULL, NULL, GetModuleHandle(NULL), NULL);
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);
HRESULT hr = factory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)),
D2D1::HwndRenderTargetProperties(hwnd, D2D1::SizeU(200, 200),
D2D1_PRESENT_OPTIONS_IMMEDIATELY), &target);
target->CreateSolidColorBrush(D2D1::ColorF(0.0f, 0.0f, 0.0f), &solid_brush);
target->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&w_factory));
hr = w_factory->CreateTextFormat(L"-2002", NULL, DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 15.0f, L"ko-KR", &w_format);
ShowWindow(hwnd, SW_SHOW);
MSG messages = { 0 };
start = clock();
while (messages.message != WM_QUIT) {
if (PeekMessage(&messages, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&messages);
DispatchMessage(&messages);
}
else {
render();
}
}
}

Related

Pixel to rect in win32api C

I'm creating an engine with primary operating system call. I can create a window and manipulate most of events. But I'm having trouble drawing images. I'm using stb_image to load the images, and it's doing well.
When I try to draw the images with points I keep seems it drawing point by point 'cause it is doing in executing time. I would like to know if there's a way to put those pixels into a rect and then draw onto screen.
Here is the functions I've already made:
Image functions:
typedef struct ImageTag ImageSet;
struct ImageTag {
B32U id;
B8 * path;
B32 w, h, bpp;
size_t size;
BO * data;
B32U image_id;
IMAGE_PUSH push;
IMAGE_FLIP flip;
IMAGE_MODE mode;
ImageSet * preview, *next;
STATUS (*load)(ImageSet * p);
STATUS (*next_first)(ImageSet ** p, ImageSet * n);
STATUS (*next_last)(ImageSet ** p, ImageSet * n);
ImageSet * (*search)(ImageSet * p, B32U id);
STATUS (*clone)(ImageSet ** p1, ImageSet * p2);
STATUS (*pixel_set)(ImageSet * i, B32 x, B32 y, PixelSet * p);
PixelSet (*pixel_get)(ImageSet * i, B32 x, B32 y);
BO (*zoom_fit)(ImageSet * p, B32 w, B32 h);
BO (*draw)(ImageSet * p, B32 x, B32 y);
BO (*draw_map)(B32 x, B32 y);
STATUS (*pop)(ImageSet * p);
STATUS (*destroy)(ImageSet * p);
};
static PixelSet image_of_pixel_get(ImageSet * i, B32 x, B32 y) {
PixelSet c = pixel_start();
if (!i)
return c;
c.r = ((B8U*) i->data)[i->bpp * (y * i->w + x) + 0];
c.g = ((B8U*) i->data)[i->bpp * (y * i->w + x) + 1];
c.b = ((B8U*) i->data)[i->bpp * (y * i->w + x) + 2];
c.a = i->bpp >= 4 ? ((B8U*) i->data)[i->bpp * (y * i->w + x) + 3] : 0xff;
return c;
}
BO static image_of_map_draw(B32 i, B32 j) {
if ((!gear || !gear->map || !gear->map->image)
|| ((i < 0 && i > gear->map->image->w - gear->w)
|| (j < 0 && j > gear->map->image->h - gear->h)))
return;
switch (gear->up->system) {
case SYSTEM_PRIMARY: {
#if defined WIN32 || WIN64 || WINDOWS_XP
B32 x, y;
for (y = 0; y < gear->h; y++) {
for (x = 0; x < gear->w; x++) {
PixelSet c =
pixel_rgba_start(
((B8U *) (gear->map->image->data))[gear->map->image->bpp
* ((j + y) * gear->map->image->w
+ (i + x)) + 0],
((B8U *) (gear->map->image->data))[gear->map->image->bpp
* ((j + y) * gear->map->image->w
+ (i + x)) + 1],
((B8U *) (gear->map->image->data))[gear->map->image->bpp
* ((j + y) * gear->map->image->w
+ (i + x)) + 2],
gear->map->image->bpp >= 4 ?
((B8U *) (gear->map->image->data))[gear->map->image->bpp
* ((j + y)
* gear->map->image->w
+ (i + x)) + 3] :
255);
windows_put_pixel(x, y, &c);
}
}
//printf("%i %i\n", i, j);
#endif
}
break;
case SYSTEM_ALLEGRO:
case SYSTEM_SDL:
break;
case SYSTEM_CONSOLE:
default:
break;
}
}
operating system functions:
#include <place/plugin/graphic/primary-of.h>
#if defined WIN32 || WIN64 || WINDOWS_XP
#include <place/machine.h>
#include <place/driver/opengl-of.h>
#include <place/plugin/graphic/windows-of.h>
#include <stdio.h>
extern MachineSet *gear;
LRESULT CALLBACK windows_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HBITMAP create_bitmap(HDC screen, void * data, B32 w, B32 h, B32 bpp) {
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = w;
bmih.biHeight = h;
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 10;
bmih.biYPelsPerMeter = 10;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
BITMAPINFO dbmi;
ZeroMemory(&dbmi, sizeof(dbmi));
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 255;
dbmi.bmiColors->rgbGreen = 255;
dbmi.bmiColors->rgbRed = 255;
dbmi.bmiColors->rgbReserved = 0;
HDC dc = CreateCompatibleDC(NULL);
HBITMAP image = CreateDIBSection(dc, &dbmi, DIB_RGB_COLORS, (void**) &data, NULL, 0);
return image;
}
LRESULT CALLBACK windows_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
if (gear->up->driver == GRAPHIC_PRIMARY) {
PAINTSTRUCT ps;
WINDOWS_PLUGIN(gear)->screen = BeginPaint(WINDOWS_PLUGIN(gear)->window, &ps);
int choice = 1;
switch (choice) {
case 0: {
// this is what I've tried unsuccessfully
HBITMAP bmp = create_bitmap(WINDOWS_PLUGIN(gear)->screen,
gear->map->image->data, gear->map->size->x,
gear->map->size->y, gear->map->image->bpp);
windows_draw(bmp, gear->map->size->x * 0.1,
gear->map->size->y * 0.1);
}
break;
case 1:{
// this is what I'm using
gear->map->image->draw_map(gear->map->pos->x,gear->map->pos->y);
}break;
}
EndPaint(WINDOWS_PLUGIN(gear)->window, &ps);
}
}
return 0;
// ...
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
WINDOWS_OF_CALL BO WINDOWS_OF_TYPE windows_put_pixel(B32 x, B32 y, PixelSet * c) {
SetPixel(WINDOWS_PLUGIN(gear)->screen, x, y, RGB(c->r, c->g, c->b));
}
WINDOWS_OF_CALL BO WINDOWS_OF_TYPE windows_draw(HBITMAP bmp, B32 w, B32 h) {
HDC hdcMem = CreateCompatibleDC(NULL);
BitBlt(WINDOWS_PLUGIN(gear)->screen, 0, 0, w, h, hdcMem, 0, 0, SRCCOPY);
DeleteDC(hdcMem);
}
#elif defined __linux__
// ...
#endif
I wanted to put those pixels onto a windows buffer before to draw it.
This is the video showing what's happening
https://youtu.be/Hhpm5459hoA

How do I draw multiple SDL_rects to the screen in sdl2?

So I have this function that takes a rect, RGB, alpha values and a char which determines if it will fill the rect or not.
void make_rect(SDL_Rect rect, SDL_Renderer * renderer, int r, int g, int b, int a, char flag)
{
SDL_SetRenderDrawColor(renderer, r, g, b, a);
if(drawmd == 'f')
{
SDL_RenderFillRect(renderer, &rect);
}
else if(drawmd == 'd')
{
SDL_RenderDrawRect(renderer, &rect);
}
SDL_RenderPresent(renderer);
}
I call the function twice with different rects:
rect_1:
SDL_Rect rect;
rect.x = 241;
rect.y = 389;
rect.w = 104;
rect.h = 69;
int r = 32;
int g = 186;
int b = 247;
int a = 255;
char dm = 'f'
make_rect(rect, renderer, r, g, b, a, dm);
and the same with different values and names not listed here.
All of these variables are within bounds and I don't get a compilation error it only draws one of the rects.

How do I draw a Pixmap with GTK?

Using GTK3, I have been trying to draw a Pixmap from a memory buffer. I have just created a memory buffer, and filled it with alternating rows of colours in the 32-bit RGBA format. I have been trying the following function:
gdk_pixbuf_new_from_data(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data)
Using this, I have been able to wrap the memory buffer into a GdkPixbuf*, however when I attempt to draw the pixbuf to screen with Cairo, the image seems to be distorted.
Here is my test program that I have been experimenting with:
#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
const int WIDTH = 1080;
const int HEIGHT = 720;
GtkWidget* mainWindow;
int currentCol = 0;
uint32_t* framebuffer = NULL;
GdkPixbuf* pixbuf = NULL;
typedef struct _rgbColor {
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
}rgbColor;
void onWindowDestroy (GtkWidget* object, gpointer user_data) {
gtk_main_quit();
}
gboolean onTimerTick(gpointer user_data) {
rgbColor c = {0, 0, 0, 255};
if (currentCol == 0) {
c.red = 255;
}
if (currentCol == 1) {
c.green = 255;
}
if (currentCol == 2) {
c.blue = 255;
currentCol = -1;
}
currentCol++;
fillWithColour(framebuffer, c);
rgbColor c1 = {0, 0, 255, 255};
fillEveryInterval(framebuffer, c1, 20);
gtk_widget_queue_draw(mainWindow);
return 1;
}
gboolean onDraw(GtkWidget* widget, cairo_t *cr, gpointer user_data) {
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
cairo_paint(cr);
return 0;
}
void fillWithColour(uint32_t* fb, rgbColor c) {
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
encodePixel(fb, c, x, y);
}
}
}
void fillEveryInterval(uint32_t* fb, rgbColor c, int interval) {
for (int y = 1; y < HEIGHT; y += interval) {
for (int x = 0; x < WIDTH; x++) {
encodePixel(fb, c, x, y);
}
}
}
void encodePixel(uint32_t* fb, rgbColor c, int x, int y) {
uint32_t r, g, b, a;
r = c.red;
g = c.green << 8;
b = c.blue << 16;
a = c.alpha << 24;
*(fb + (sizeof(uint32_t)*y+x)) = b | g | r | a;
}
int main() {
framebuffer = malloc(sizeof(uint32_t)*WIDTH*HEIGHT);
rgbColor c = {255, 0, 0, 255};
fillWithColour(framebuffer, c);
gtk_init(NULL, NULL);
mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(mainWindow), WIDTH, HEIGHT);
gtk_window_set_title(GTK_WINDOW(mainWindow), "Framebuffer test");
GtkWidget* drawingArea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(mainWindow), drawingArea);
g_signal_connect(GTK_WINDOW(mainWindow), "destroy", (GCallback)onWindowDestroy, NULL);
g_signal_connect(GTK_DRAWING_AREA(drawingArea), "draw", (GCallback)onDraw, NULL);
g_timeout_add(500, onTimerTick, NULL);
gtk_widget_show_all(GTK_WINDOW(mainWindow));
pixbuf = gdk_pixbuf_new_from_data(framebuffer, GDK_COLORSPACE_RGB, true, 8, WIDTH, HEIGHT, WIDTH*4, NULL, NULL);
gtk_main();
}
I can't seem to figure out what is causing the issue, I have experimented with eliminating the alpha channel and packing the RGB values into 24-bits, however I was not successful with that method either. I think it may have something to do with the rowstride, however I have not been able to find a value which corrects the issue. Am I on the right track here, or is there a better way to draw a RGB buffer to screen using GTK?
You're just storing the pixels in the wrong location. In encodePixel, change this line:
*(fb + (sizeof(uint32_t)*y+x)) = b | g | r | a;`
to this
fb[WIDTH*y+x] = b | g | r | a;
And on a sidenote: You should do something with the many warnings from the compiler.

Why dots cannot be drawn "smoothly" with XDrawPoint ( X Window )?

Here is the code snippet (Xlib):
void update_screen()
{
int X,Y;
for (X = 0; X < Wnd_X; X++)
for (Y = 0; Y < Wnd_Y; Y++)
{
XDrawPoint(dsp, win, gc_2, X, Y);
usleep(100);
}
return;
}
But it'll be like this:
and then:
Why dots cannot be drawn smoothly with XDrawPoint?
And how to fill the window with green color fluently?
Full code here:
#include <X11/Xlib.h> // must precede most other headers!
#include <stdlib.h>
int Wnd_X=500;
int Wnd_Y=500;
void update_screen();
GC gc_2;
Window win;
Display *dsp;
int main()
{
dsp = XOpenDisplay(NULL);
int screen = DefaultScreen(dsp);
win = XCreateWindow(dsp, DefaultRootWindow(dsp), 0, 0, Wnd_X, Wnd_Y, 0, 0, 0, 0, 0, 0);
//XCreateSimpleWindow(dsp, DefaultRootWindow(dsp), 0, 0, Wnd_X, Wnd_Y, 0, 0x000000, 0xFFFFFF);
Atom wmDelete = XInternAtom(dsp, "WM_DELETE_WINDOW", True);
XSetWMProtocols(dsp, win, &wmDelete, 1);
XGCValues gcvalues_2;
gcvalues_2.function = GXcopy;
gcvalues_2.plane_mask = AllPlanes;
gcvalues_2.foreground = 0x00FF00;
gcvalues_2.background = 0xFFFFFF;
gc_2 = XCreateGC(dsp, win, GCFunction|GCPlaneMask|GCForeground|GCBackground, &gcvalues_2);
XEvent evt;
long eventMask = StructureNotifyMask;
eventMask |= ButtonPressMask|ButtonReleaseMask|KeyPressMask|KeyReleaseMask;
XSelectInput(dsp, win, eventMask);
XMapWindow(dsp, win);
// wait until window appears
do { XNextEvent(dsp,&evt); } while (evt.type != MapNotify);
update_screen();
XDestroyWindow(dsp, win);
XCloseDisplay(dsp);
return 0;
}
void update_screen()
{
int X,Y;
for (X = 0; X < Wnd_X; X++)
for (Y = 0; Y < Wnd_Y; Y++)
{
XDrawPoint(dsp, win, gc_2, X, Y);
usleep(100);
}
return;
}
You need to flush the updates to the X server. Try this:
XDrawPoint(dsp, win, gc_2, X, Y);
XFlush(dsp);
usleep(100);

how to convert simple opengl line plotting code to use vertex array

I wrote a simple opengl application in C which plots sin(x). This is my current draw function which runs very slow. How do I have to convert this code to make use of the faster 'vertex array' mode?
list of variables and functions used:
N = total number of points
x1 = min(x)
x2 = max(x)
y1 = min(y)
y2 = max(y)
func(x) = sin(x)
and here's the entire code:
/* to compile, do:
$ gcc -o out simple.c -lglut
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#include <time.h>
float xmin = -10, xmax = 10, ymin = -5, ymax = 5;
int nPoints = 3000;
/* function to calculate each data point */
float func(float x)
{
return sin(x);
}
/* plotting function - very slow */
void draw(float (* func)(float x), float x1, float x2, float y1, float y2, int N)
{
float x, dx = 1.0/N;
glPushMatrix();
glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
glTranslatef(-x1, -y1, 0.0);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_STRIP);
for(x = x1; x < x2; x += dx)
{
glVertex2f(x, func(x));
}
glEnd();
glPopMatrix();
};
/* Redrawing func */
void redraw(void)
{
clock_t start = clock();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// -x, +x, -y, +y, number points
draw(func, xmin, xmax, ymin, ymax, nPoints);
glutSwapBuffers();
printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
};
/* Idle proc. Redisplays, if called. */
void idle(void)
{
// shift 'xmin' & 'xmax' by one.
xmin++;
xmax++;
glutPostRedisplay();
};
/* Key press processing */
void key(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
};
/* Window reashape */
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 0, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
};
/* Main function */
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Graph plotter");
glutReshapeWindow(1024, 800);
glutPostRedisplay(); // This call may or may not be necessary
/* Register GLUT callbacks. */
glutDisplayFunc(redraw);
glutKeyboardFunc(key);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
/* Init the GL state */
glLineWidth(2.0);
/* Main loop */
glutMainLoop();
return 0;
}
In terms of LodePNG's C-style vector struct/functions:
// shared
vector pts;
vector_init( &pts, sizeof( float ) );
// whenever x1, x2, or N changes
vector_cleanup( &pts );
float x, dx = 1.0/N;
for(x = x1; x < x2; x += dx)
{
vector_resize( &pts, pts.size + 2 );
*(float*)vector_get( &pts, pts.size-2 ) = x;
*(float*)vector_get( &pts, pts.size-1 ) = func(x);
}
// whenever you want to draw
glPushMatrix();
glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
glTranslatef(-x1, -y1, 0.0);
glColor3f(1.0, 1.0, 1.0);
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, (float*)pts.data );
glDrawArrays( GL_LINE_STRIP, 0, pts.size / 2 );
glDisableClientState( GL_VERTEX_ARRAY );
glPopMatrix();
EDIT: Complete code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#include <time.h>
typedef struct vector /*dynamic vector of void* pointers. This one is used only by the deflate compressor*/
{
void* data;
size_t size; /*in groups of bytes depending on type*/
size_t allocsize; /*in bytes*/
unsigned typesize; /*sizeof the type you store in data*/
} vector;
static unsigned vector_resize(vector* p, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/
{
if(size * p->typesize > p->allocsize)
{
size_t newsize = size * p->typesize * 2;
void* data = realloc(p->data, newsize);
if(data)
{
p->allocsize = newsize;
p->data = data;
p->size = size;
}
else return 0;
}
else p->size = size;
return 1;
}
static void vector_cleanup(void* p)
{
((vector*)p)->size = ((vector*)p)->allocsize = 0;
free(((vector*)p)->data);
((vector*)p)->data = NULL;
}
static void vector_init(vector* p, unsigned typesize)
{
p->data = NULL;
p->size = p->allocsize = 0;
p->typesize = typesize;
}
static void* vector_get(vector* p, size_t index)
{
return &((char*)p->data)[index * p->typesize];
}
float xmin = -10, xmax = 10, ymin = -5, ymax = 5;
int nPoints = 3000;
vector pts;
/* function to calculate each data point */
float func(float x)
{
return sin(x);
}
void update(float (* func)(float x), float x1, float x2, int N)
{
float x, dx = 1.0/N;
vector_cleanup( &pts );
for(x = x1; x < x2; x += dx)
{
vector_resize( &pts, pts.size + 2 );
*(float*)vector_get( &pts, pts.size-2 ) = x;
*(float*)vector_get( &pts, pts.size-1 ) = func(x);
}
}
/* plotting function - very slow */
void draw(float x1, float x2, float y1, float y2)
{
glPushMatrix();
glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
glTranslatef(-x1, -y1, 0.0);
glColor3f(1.0, 1.0, 1.0);
if( pts.size > 0 )
{
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, (float*)pts.data );
glDrawArrays( GL_LINE_STRIP, 0, pts.size / 2 );
glDisableClientState( GL_VERTEX_ARRAY );
}
glPopMatrix();
};
/* Redrawing func */
void redraw(void)
{
clock_t start = clock();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// -x, +x, -y, +y, number points
draw(xmin, xmax, ymin, ymax);
glutSwapBuffers();
printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
};
/* Idle proc. Redisplays, if called. */
void idle(void)
{
// shift 'xmin' & 'xmax' by one.
xmin++;
xmax++;
update(func, xmin, xmax, nPoints);
glutPostRedisplay();
};
/* Key press processing */
void key(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
};
/* Window reashape */
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 0, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
};
/* Main function */
int main(int argc, char **argv)
{
vector_init( &pts, sizeof( float ) );
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Graph plotter");
glutReshapeWindow(1024, 800);
glutPostRedisplay(); // This call may or may not be necessary
/* Register GLUT callbacks. */
glutDisplayFunc(redraw);
glutKeyboardFunc(key);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
/* Init the GL state */
glLineWidth(2.0);
/* Main loop */
glutMainLoop();
return 0;
}

Resources