I'm trying to figure out how do I acess raw pixel information from screen. So far I've been capturing the screen to a HBITMAP, populating a BITMAPINFO then creating a pointer of this BITMAPINFO variable to read directly from the memory.
I know that the header must be "removed" from the file, so I advance the pointer directly to the bitmap data (adding sizeof(MyBMInfo2->bmiHeader) to my pointer offset). I also know that this bitmap is inversed/topdown, the first pixels are on the end of the raw data. I need to figure out how do I extract R G and B bytes from a given X and Y in the image, and that's what I'm being incapable of doing.
So I asking you sirs a light, a snippet or any hint that can help my dirty attempt to recreate Bitmap.GetPixel(x,y) from gdi32 (so slow, I need a better one).
A snippet of my source code so far:
...
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, nScreenWidth, nScreenHeight);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BOOL bOK = BitBlt(hCaptureDC,0,0,nScreenWidth, nScreenHeight, hdc,0,0,SRCCOPY|CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
DeleteDC(hCaptureDC);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the MyBMInfo structure from the bitmap
if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
printf("error\n");
}
BITMAPINFO* MyBMInfo2 = &MyBMInfo;
BYTE* bitmapBits=(BYTE*)MyBMInfo2+sizeof(MyBMInfo2->bmiHeader);
//So... how do I acess X and Y RGB bytes now? xD
...
By the way.... There are any other more direct way to do this without throwing a memory protection fault? Or... another faster way at all?
Thank you.
--Edit--
Using Barmak's code I've figured out how do I access X and Y rgb based on current cursor position, here follows the source code:
#include <windows.h>
int main()
{
HWND hwnd = GetDesktopWindow();
RECT rc;
GetClientRect(hwnd, &rc);
int width = rc.right;
int height = rc.bottom;
if (width < 1 || height < 1)
{
OutputDebugStringA("error\n");
return 0;
}
HDC hdc = GetDC(hwnd);
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
SelectObject(hCaptureDC, hOld);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 32;
DWORD size = ((width * bmpInfoHeader.biBitCount + 31) / 32) * 4 * height;
BYTE *bits = malloc(size);
if (GetDIBits(hdc, hBitmap, 0, height, bits, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS))
{
OutputDebugStringA("success\n");
//you can use bits here
//access bits from upper-left to lower-right corner
POINT p;
GetCursorPos(&p);
int x = p.x;
int y = p.y;
int col = x;
int row = height - y - 1;
int index = (row * width + col) * 4;
BYTE b = bits[index + 0];
BYTE g = bits[index + 1];
BYTE r = bits[index + 2];
printf("r:%i g:%i b:%i \n",r,g,b);
}
else
{
OutputDebugStringA("error\n");
}
free(bits);
DeleteDC(hCaptureDC);
DeleteObject(hBitmap);
ReleaseDC(hwnd, hdc);
return 0;
}
Thank you very much Mr Shemirani. To who downvoted my answer, please, consider the withdrawn of it please? :)
Peace.
GetDibBits requires a buffer to receive the bits. You have to allocate the buffer, then delete when no longer needed.
#include <windows.h>
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
HWND hwnd = GetDesktopWindow();
RECT rc;
GetClientRect(hwnd, &rc);
int width = rc.right;
int height = rc.bottom;
if (width < 1 || height < 1)
{
OutputDebugStringA("error\n");
return 0;
}
HDC hdc = GetDC(hwnd);
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
SelectObject(hCaptureDC, hOld);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 32;
DWORD size = ((width * bmpInfoHeader.biBitCount + 31) / 32) * 4 * height;
BYTE *bits = malloc(size);
if (GetDIBits(hdc, hBitmap, 0, height, bits, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS))
{
OutputDebugStringA("success\n");
//you can use bits here
//access bits from lower-left to upper-right corner
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
//for 32 bit image only:
int index = (row * width + col) * 4;
BYTE blue = bits[index + 0];
BYTE green = bits[index + 1];
BYTE red = bits[index + 2];
}
}
//access bits from upper-left to lower-right corner
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int col = x;
int row = height - y - 1;
int index = (row * width + col) * 4;
BYTE b = bits[index + 0];
BYTE g = bits[index + 1];
BYTE r = bits[index + 2];
}
}
}
else
{
OutputDebugStringA("error\n");
}
free(bits);
DeleteDC(hCaptureDC);
DeleteObject(hBitmap);
ReleaseDC(hwnd, hdc);
return 0;
}
Related
I'm trying to play a simple square wave in SDL via the main audio callback function. However, I can't seem to get any audio to play, despite the fact that data appears to be written into the audio buffer.
However, if I load up a .wav file, the audio plays properly (writing data into the same location
After writing my own code to attempt to solve the problem, I tried numerous sine/square waveforms I found online. It would seem that the issue is perhaps not related to the waveform, but since wav files work, I'm not sure what else could be causing the problem:
#include "x:\SDL2-2.0.10\include\SDL.h"
#define INITIAL_SCREEN_WIDTH (8*80)
#define INITIAL_SCREEN_HEIGHT (8*60)
typedef struct audio_user_data audio_user_data;
struct audio_user_data
{
int SamplesPerSecond;
int BytesPerSample;
int SampleIndex;
int ToneHz;
int ToneVolume;
int WavePeriod;
Uint32 FileLength;
Uint16* BufferLocation;
};
void
AudioCallback(void* UserData, Uint8* Stream, int Length)
{
audio_user_data* AudioUserData = (audio_user_data*)UserData;
static Uint32 Count = 0;
Sint16* SampleBuffer = (Sint16*)Stream;
int SamplesToWrite = Length / AudioUserData->BytesPerSample;
for(int SampleIndex = 0; SampleIndex < SamplesToWrite; SampleIndex++)
{
Sint16 SampleValue = ((Count++ / (AudioUserData->WavePeriod/2)) % 2) ? AudioUserData->ToneVolume : -AudioUserData->ToneVolume;
*SampleBuffer++ = SampleValue;
*SampleBuffer++ = SampleValue;
}
}
int
main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO);
SDL_Window* Window = SDL_CreateWindow("Spell Checker", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, INITIAL_SCREEN_WIDTH*2, INITIAL_SCREEN_HEIGHT*2, 0);
SDL_Renderer* Renderer = SDL_CreateRenderer(Window, 0, SDL_RENDERER_SOFTWARE);
SDL_PixelFormat* Format = SDL_AllocFormat(SDL_PIXELFORMAT_RGB888);
SDL_Texture* Screen = SDL_CreateTexture(Renderer, Format->format, SDL_TEXTUREACCESS_STREAMING, INITIAL_SCREEN_WIDTH, INITIAL_SCREEN_HEIGHT);
audio_user_data AudioUserData = {0};
AudioUserData.SamplesPerSecond = 48000;//44100;
AudioUserData.BytesPerSample = 2 * sizeof(Sint16);
AudioUserData.SampleIndex = 0;
AudioUserData.ToneVolume = 5000;
AudioUserData.ToneHz = 256;
AudioUserData.WavePeriod = AudioUserData.SamplesPerSecond / AudioUserData.ToneHz;
SDL_AudioSpec Want, Have;
SDL_AudioDeviceID AudioDeviceID;
Want.freq = 48000; // 44100;
Want.format = AUDIO_S16;
Want.channels = 2;
Want.samples = 4096;
Want.callback = &AudioCallback;
Want.userdata = &AudioUserData;
AudioDeviceID = SDL_OpenAudioDevice(0, 0, &Want, &Have, SDL_AUDIO_ALLOW_ANY_CHANGE);
SDL_PauseAudioDevice(AudioDeviceID, 0); // Start playing
Uint32* PixelMap = calloc(INITIAL_SCREEN_WIDTH * INITIAL_SCREEN_HEIGHT, sizeof(PixelMap));
int PixelMapLocation = 0;
int Running = 1;
while(Running)
{
SDL_Event Event;
while(SDL_PollEvent(&Event))
{
if(Event.type == SDL_QUIT)
{
Running = 0;
break;
}
}
// Test colors
PixelMapLocation = 0;
for(int Row = 0; Row < INITIAL_SCREEN_WIDTH; ++Row)
{
for(int Col = 0; Col < INITIAL_SCREEN_HEIGHT; ++Col)
{
PixelMap[PixelMapLocation++] = 0xFF00FF;
}
}
for(int Row = 0; Row < INITIAL_SCREEN_WIDTH; ++Row)
{
for(int Col = 0; Col < INITIAL_SCREEN_HEIGHT; ++Col)
{
PixelMap[PixelMapLocation++] = 0x00FFFF;
}
}
SDL_UpdateTexture(Screen, 0, PixelMap, INITIAL_SCREEN_WIDTH * sizeof(PixelMap));
SDL_RenderClear(Renderer);
SDL_RenderCopy(Renderer, Screen, 0, 0);
SDL_RenderPresent(Renderer);
}
return(0);
}
I am trying to implement animations on a Rock64 ARM board, which has a Rockchip RK3328 with a Mali GPU. I am using SDL2 and I am experiencing a low framerate. So I wrote some testing code:
#include <SDL2/SDL.h>
#include <stdbool.h>
// generates a texture with the given color and the output's size
SDL_Texture *colorTexture(SDL_Renderer *renderer,
unsigned char r, unsigned char g, unsigned char b) {
int w, h, pitch;
SDL_GetRendererOutputSize(renderer, &w, &h);
SDL_Texture *ret = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_STREAMING, w, h);
void *pixels;
SDL_LockTexture(ret, NULL, &pixels, &pitch);
for (int y = 0; y < h; ++y) {
unsigned char *cur = pixels + y * pitch;
for (int x = 0; x < w; ++x) {
*cur++ = 255; *cur++ = b; *cur++ = g; *cur++ = r;
}
}
SDL_UnlockTexture(ret);
return ret;
}
int main(int argc, char *argv[]) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
SDL_Window *window;
SDL_Renderer *renderer;
SDL_CreateWindowAndRenderer(640, 480, SDL_WINDOW_OPENGL, &window, &renderer);
SDL_Texture *blue = colorTexture(renderer, 0, 0, 255);
SDL_Texture *red = colorTexture(renderer, 255, 0, 0);
int w, h;
SDL_GetWindowSize(window, &w, &h);
bool running = true;
SDL_Texture *first = blue, *second = red;
uint32_t start = SDL_GetTicks();
int frameCount = 0;
while (running) {
SDL_Event evt;
for (int x = 0; x < w; ++x) {
while (SDL_PollEvent(&evt)) {
if (evt.type == SDL_QUIT) {
running = false;
goto after_animation;
}
}
SDL_Rect firstRect = {.x = 0, .y = 0, .w = x, .h = h},
secondRect = {.x = x, .y = 0, .w = w - x, .h = h};
SDL_RenderCopy(renderer, first, &firstRect, &firstRect);
SDL_RenderCopy(renderer, second, &secondRect, &secondRect);
SDL_RenderPresent(renderer);
frameCount++;
uint32_t cur = SDL_GetTicks();
if (cur - start >= 1000) {
printf("%d FPS\n", frameCount);
frameCount = 0;
start = cur;
}
}
after_animation:;
SDL_Texture *tmp = first; first = second; second = tmp;
}
SDL_Quit();
}
According to the post here, the board is able to reach framerates higher than 60 FPS even for 4k output (my monitor is a 4k TV). However, my testing code reports only 30 FPS. It only renders two textures that have exactly the screen's size, and scrolls horizontally showing one texture on the left and one on the right. I believe I should be able to reach framerates beyond 30 FPS. How can I speed up the rendering?
I was trying to use SDL_UpdateTexture to create a texture from an allocated buffer of pixels, and I was surprised that it wasn't even rendering at 60fps (with the main culprit being SDL_UpdateTexture):
#include <SDL2/SDL.h>
#include <sys/time.h>
static double time_in_ms(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
}
int main(void) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("Pixel formats" , 0, 0, 1920, 1080, 0);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
double last_frame = time_in_ms();
while (1) {
int width, height;
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
return 0;
}
}
SDL_GetWindowSize(window, &width, &height);
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
Uint32 *pixels = malloc(width * height * sizeof(*pixels));
/* fill buffer with blue pixels */
for (int y = 0; y < height; y++) {
Uint32 *row = pixels + y * width;
for (int x = 0; x < width; x++) {
row[x] = 0x0000FFFF;
}
}
double update_begin = time_in_ms();
SDL_UpdateTexture(texture, NULL, pixels, width * sizeof(*pixels));
double update_end = time_in_ms();
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_DestroyTexture(texture);
free(pixels);
double this_frame = time_in_ms();
printf("frame took %fms\n", this_frame - last_frame);
printf(" - update texture: %fms\n", update_end - update_begin);
last_frame = this_frame;
}
}
But, if I just change SDL_PIXELFORMAT_RGBA8888 to SDL_PIXELFORMAT_ARGB8888 (and update 0x0000FFFF to 0xFF0000FF), all of a sudden, SDL_UpdateTexture goes down from taking ~15ms per frame to ~1ms. This happens regardless of whether renderer is an accelerated or software renderer. This seems very strange to me, since even if SDL_Textures are internally ARGB, it takes far less than 15ms to convert from RGBA to ARGB:
for (int y = 0; y < height; y++) {
Uint32 *row = pixels + y * width;
for (int x = 0; x < width; x++) {
Uint32 a = row[x] & 0xFF;
row[x] >>= 8;
row[x] |= a << 24;
}
}
Why might it be that SDL_UpdateTexture is so much faster with ARGB than RGBA (and does this vary across platforms)?
(SDL_PIXELFORMAT_RGB888 is also quite fast (~2ms), but not as fast as ARGB)
I'm new to OpenGL and I am trying to get a mandelbrot set computed with OpenGL and GLFW.
I found the code here but freeglut is broken on my system and for some reason complains about no callback being set even though it clearly is being set. It does however flash one frame and then crash, in that frame I can see the mandelbrot set so I know the math is correct.
I figured this would be a good opportunity to learn more about OpenGL and GLFW, so I set to work making this happen.
After double checking everything, I can see that it definitely calculates the values then switches the buffers properly.
However, I think I'm missing two things:
A vertex which the texture can actually be applied to
EDIT: (from learnopengl.com) "Once glTexImage2D is called, the currently bound texture object now has the texture image attached to it.", so it can't be #2
not sure what's happening with the calculation but it looks like it's binding a texture named 'texture' but then calculating the values in a struct array which don't seem to be associated in any way. I bind the texture with tex (texture) and then send the struct array to glTexImage2D
If someone could just point me in the right direction or confirm my suspicions that would be awesome.
My code is here:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <pthread.h>
#include <GLFW/glfw3.h>
#include <GL/gl.h>
#define VAL 255
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
}rgb_t;
rgb_t **tex_array = 0;
rgb_t *image;
int gwin;
int width = 640;
int height = 480;
int tex_w, tex_h;
double scale = 1./256;
double cx = -.6, cy = 0;
int color_rotate = 0;
int saturation = 1;
int invert = 0;
int max_iter = 256;
int dump = 1;
GLFWwindow* window;
int global_iterator = 0;
int conversion_iterator_x = 0;
int conversion_iterator_y = 0;
GLFWwindow* init_glfw();
void set_texture(GLuint tex);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void render(GLuint tex);
void screen_dump();
void keypress(unsigned char key, int x, int y);
void hsv_to_rgb(int hue, int min, int max, rgb_t *p);
void calc_mandel(rgb_t* px);
void alloc_texture();
void set_texture();
void mouseclick(int button, int state, int x, int y);
void resize(int w, int h);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
int main(int c, char **v)
{
GLFWwindow* win = init_glfw();
glfwSetWindowPos(win, 1000, 500);
GLuint texture;
glGenTextures(1, &texture);
set_texture(texture);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(win))
{
render(texture);
/* Swap front and back buffers */
glfwSwapBuffers(win);
/* Poll for and process events */
glfwPollEvents();
if(glfwGetKey(win, GLFW_KEY_ESCAPE) == GLFW_PRESS){
glfwSetWindowShouldClose(win, GL_TRUE);
}
}
return 0;
}
void set_texture(GLuint tex)
{
printf("Allocating space\n");
alloc_texture();
printf("Calculating mandel... %d\n", global_iterator);
++global_iterator;
calc_mandel(image);
printf("mandel calculation complete\n");
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h,
0, GL_RGB, GL_UNSIGNED_BYTE, tex_array[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
printf("Rendering to screen...\n");
render(tex);
}
void alloc_texture()
{
int i;
int ow = tex_w;
int oh = tex_h;
for (tex_w = 1; tex_w < width; tex_w <<= 1);
for (tex_h = 1; tex_h < height; tex_h <<= 1);
if (tex_h != oh || tex_w != ow){
tex_array = realloc(tex_array, tex_h * tex_w * 3 + tex_h * sizeof(rgb_t*));
}
for (tex_array[0] = (rgb_t *)(tex_array + tex_h), i = 1; i < tex_h; i++){
tex_array[i] = tex_array[i - 1] + tex_w;
}
}
void render(GLuint tex)
{
double x = (double)width /tex_w,
y = (double)height/tex_h;
glClear(GL_COLOR_BUFFER_BIT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2i(0, 0);
glTexCoord2f(x, 0); glVertex2i(width, 0);
glTexCoord2f(x, y); glVertex2i(width, height);
glTexCoord2f(0, y); glVertex2i(0, height);
glEnd();
glFlush();
glFinish();
}
GLFWwindow* init_glfw()
{
/* Initialize the library */
if (!glfwInit()){
return NULL;
}
/*
* Configure window options here if you so desire
*
* i.e.
*/
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
//glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
//the fourth parameter of glfwCreateWindow should be NULL for windowed mode and
//glfGetPrimaryMonitor() for full screen mode
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(width, height, "Mandelbrot", NULL, NULL);
if (!window)
{
glfwTerminate();
return NULL;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
/*
* Initialize glew here
*/
glewExperimental = GL_TRUE;
glewInit();
return window;
}
void calc_mandel(rgb_t* px)
{
int i, j, iter, min, max;
double x, y, zx, zy, zx2, zy2;
min = max_iter;
max = 0;
for (i = 0; i < height; i++) {
px = tex_array[i];
y = (i - height/2) * scale + cy;
for (j = 0; j < width; j++, px++) {
x = (j - width/2) * scale + cx;
iter = 0;
zx = hypot(x - .25, y);
if (x < zx - 2 * zx * zx + .25){
iter = max_iter;
}
if ((x + 1)*(x + 1) + y * y < 1/16){
iter = max_iter;
}
zx = zy = zx2 = zy2 = 0;
for (; iter < max_iter && zx2 + zy2 < 4; iter++) {
zy = 2 * zx * zy + y;
zx = zx2 - zy2 + x;
zx2 = zx * zx;
zy2 = zy * zy;
}
if (iter < min){
min = iter;
}
if (iter > max){
max = iter;
}
*(unsigned short *)px = iter;
}
}
for (i = 0; i < height; i++){
for (j = 0, px = tex_array[i]; j < width; j++, px++){
hsv_to_rgb(*(unsigned short*)px, min, max, px);
}
}
}
void hsv_to_rgb(int hue, int min, int max, rgb_t *p)
{
printf("Converting hsv to rbg... \n");
if (min == max){
max = min + 1;
}
if (invert){
hue = max - (hue - min);
}
if (!saturation) {
p->r = p->g = p->b = 255 * (max - hue) / (max - min);
printf("done! (!saturation)\n");
return;
}
double h = fmod(color_rotate + 1e-4 + 4.0 * (hue - min) / (max - min), 6);
double c = VAL * saturation;
double X = c * (1 - fabs(fmod(h, 2) - 1));
p->r = p->g = p->b = 0;
switch((int)h) {
case 0: p->r = c; p->g = X; break;
case 1: p->r = X; p->g = c; break;
case 2: p->g = c; p->b = X; break;
case 3: p->g = X; p->b = c; break;
case 4: p->r = X; p->b = c; break;
default:p->r = c; p->b = X; break;
}
printf("done! (sauration)\n");
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
glOrtho(0, width, 0, height, -1, 1);
//set_texture();
}
[1]: https://rosettacode.org/wiki/Mandelbrot_set#PPM_non_interactive
I've been assigned to create a barcode image from a number generated randomly by me (that I've already done). So far I tried to create a BMP file and put in a simple black and white columns but my picture is distorted by other colors and not even in columns. I didn't even start to write the barcode itself (that itself is still a mystery to me), I tried to create it for almost 2 weeks now and to no avail.. I mostly need a program that writes black or white to the program by columns or row by row so i can put black or white at will.
This is my code:
`int width, hight;
width = 141;
hight = 70;
FILE* barcode;
fopen_s(&barcode,NEWBARCODE, "wb");
int filesize = 54 + 3 * width*height; //w is your image width, h is image height, both int
char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
char bmpinfoheader[40] = { 0x28,0,0,0, 141,0,0,0, 70,0,0,0, 1,0, 24,0,0,0,0,0,0x8c,0x05,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned char white[3] = {255,255,255 };
unsigned char black[3] = {0,0,0 };
unsigned char pad[1] = { 0 };
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
fwrite(&bmpfileheader, 1, 14, barcode);
fwrite(&bmpinfoheader, 1, 40, barcode);
for (int i = 0; i < height; i++) { //columns
for (int j = 0; j < width*3+1; j++) {
if (i % 2 == 0) {
fwrite(&white, 1, 3, barcode);
fwrite(&black, 1, 3, barcode);
}
else {
fwrite(&black, 1, 3, barcode);
fwrite(&white, 1, 3, barcode);
}
}
fwrite(&pad, 1, 1, barcode);
}
and that outputs the bmp file
What is wrong? And if there are any tips to work on creating a bmp file would be greatly appreciated :)
Try the below. Note that I've moved the BMP to a bit depth of 32. The wrapper function setColumn will allow you to set individual columns to black or white as you see fit. Much more manageable to think of the BMP as an array that you can freely manipulate instead of having to deal with a ton of fwrite logic.
#include "stdafx.h"
#include <fstream>
#define NEWBARCODE "test.bmp"
#define WHITE 255
#define BLACK 0
void setColumn(unsigned char *data, const int height, const int width, const int colIndex, const int grayVal)
{
for (int r = 0; r < height; ++r)
{
data[r * width * 4 + colIndex * 4 + 0] = grayVal;
data[r * width * 4 + colIndex * 4 + 1] = grayVal;
data[r * width * 4 + colIndex * 4 + 2] = grayVal;
data[r * width * 4 + colIndex * 4 + 3] = 255;
}
}
int main()
{
int width, height;
width = 141;
height = 70;
std::ofstream filestream;
filestream.open(NEWBARCODE, std::ios::beg | std::ios::out | std::ios::binary);
int filesize = 54 + 4 * width * height;
char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
char bmpinfoheader[40] = { 0x28,0,0,0, 141,0,0,0, 70,0,0,0, 1,0, 32,0,0,0,0,0,0x8c,0x05,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
filestream.write(bmpfileheader, 14);
filestream.write(bmpinfoheader, 40);
//Allocate BMP data block
unsigned char *data = new unsigned char[width * height * 4]{ 0 };
//Initialize BMP data to all black pixels
for (int i = 0; i < width * height * 4; ++i)
data[i] = 0;
//Set white
for (int i = 75; i < 100; ++i)
setColumn(data, height, width, i, WHITE);
//Set white
for (int i = 15; i < 25; ++i)
setColumn(data, height, width, i, WHITE);
//Set black
for (int i = 20; i < 23; ++i)
setColumn(data, height, width, i, BLACK);
filestream.write((const char *)data, height * width * 4);
filestream.close();
delete data;
return 0;
}