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
Related
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 added cairo.h to run a image processing code. getting this error
ccmKP8Gv.o:flow.c:(.text+0x621): undefined reference to
`cairo_format_stride_for_width'
I think it is a linker-error, but I am not quite sure how to solve it.
Can anyone help?
Code
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <cairo.h>
#ifndef M_PI
#define M_PI 3.1415927
#endif
#define GR(X,Y) (d[(*s)*(Y)+bpp*(X)+((2)%bpp)])
#define GG(X,Y) (d[(*s)*(Y)+bpp*(X)+((1)%bpp)])
#define GB(X,Y) (d[(*s)*(Y)+bpp*(X)+((0)%bpp)])
#define SR(X,Y) (ht[4*tw*((Y)%th)+4*((X)%tw)+2])
#define SG(X,Y) (ht[4*tw*((Y)%th)+4*((X)%tw)+1])
#define SB(X,Y) (ht[4*tw*((Y)%th)+4*((X)%tw)+0])
#define RAD(A) (M_PI*((double)(A))/180.0)
uint8_t *houghtransform(uint8_t *d, int *w, int *h, int *s, int bpp)
{
int rho, theta, y, x, W = *w, H = *h;
int th = sqrt(W*W + H*H)/2.0;
int tw = 360;
uint8_t *ht = ( uint8_t*)malloc(th*tw*4);
memset(ht, 0, 4*th*tw); // black bg
for(rho = 0; rho < th; rho++)
{
for(theta = 0; theta < tw/*720*/; theta++)
{
double C = cos(RAD(theta));
double S = sin(RAD(theta));
uint32_t totalred = 0;
uint32_t totalgreen = 0;
uint32_t totalblue = 0;
uint32_t totalpix = 0;
if ( theta < 45 || (theta > 135 && theta < 225) || theta > 315) {
for(y = 0; y < H; y++) {
double dx = W/2.0 + (rho - (H/2.0-y)*S)/C;
if ( dx < 0 || dx >= W ) continue;
x = floor(dx+.5);
if (x == W) continue;
totalpix++;
totalred += GR(x, y);
totalgreen += GG(x, y);
totalblue += GB(x, y);
}
} else {
for(x = 0; x < W; x++) {
double dy = H/2.0 - (rho - (x - W/2.0)*C)/S;
if ( dy < 0 || dy >= H ) continue;
y = floor(dy+.5);
if (y == H) continue;
totalpix++;
totalred += GR(x, y);
totalgreen += GG(x, y);
totalblue += GB(x, y);
}
}
if ( totalpix > 0 ) {
double dp = totalpix;
SR(theta, rho) = (int)(totalred/dp) &0xff;
SG(theta, rho) = (int)(totalgreen/dp) &0xff;
SB(theta, rho) = (int)(totalblue/dp) &0xff;
}
}
}
*h = th; // sqrt(W*W+H*H)/2
*w = tw; // 360
*s = 4*tw;
return ht;
}
void image_process(char *rgb)
{
cairo_surface_t *inputimg = NULL;
cairo_surface_t *houghimg = NULL;
uint8_t *houghdata = NULL, *inputdata = NULL;
int w, h, s, bpp;
inputimg = cairo_image_surface_create_for_data((unsigned char*)rgb, CAIRO_FORMAT_RGB24, 320, 240, cairo_format_stride_for_width ( CAIRO_FORMAT_RGB24, 320));
w = cairo_image_surface_get_width(inputimg);
h = cairo_image_surface_get_height(inputimg);
s = cairo_image_surface_get_stride(inputimg);
bpp = cairo_image_surface_get_format(inputimg);
switch(bpp)
{
case CAIRO_FORMAT_ARGB32: bpp = 4; break;
case CAIRO_FORMAT_RGB24: bpp = 3; break;
case CAIRO_FORMAT_A8: bpp = 1; break;
default:
fprintf(stderr, "unsupported\n");
goto destroy;
}
inputdata = cairo_image_surface_get_data(inputimg);
houghdata = houghtransform(inputdata, &w, &h, &s, bpp);
printf("w=%d, h=%d\n", w, h);
houghimg = cairo_image_surface_create_for_data(houghdata,
CAIRO_FORMAT_RGB24,
w, h, s);
cairo_surface_write_to_png(houghimg, "hello.png");
destroy:
if (inputimg != NULL) cairo_surface_destroy(inputimg);
if (houghimg != NULL) cairo_surface_destroy(houghimg);
}
Make sure to compile with the -lcairo flag.
If you're using the command line on linux do it like so:
gcc -o main main.c -Wall -Wextra -lcairo
Or if you're using an IDE just add -lcairo to the linker options.
I just got GSL set up on my windows box and I am trying to learn how to use the nonlinear fitting functions. First thing I did was pull an example directly off their website: https://www.gnu.org/software/gsl/manual/html_node/Example-programs-for-Nonlinear-Least_002dSquares-Fitting.html
which is here:
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_multifit_nlin.h>
#define N 40
#define FIT(i) gsl_vector_get(s->x, i)
#define ERR(i) sqrt(gsl_matrix_get(covar,i,i))
struct data {
size_t n;
double * y;
double * sigma;
};
int expb_f (const gsl_vector * x, void *data, gsl_vector * f)
{
size_t n = ((struct data *)data)->n;
double *y = ((struct data *)data)->y;
double *sigma = ((struct data *) data)->sigma;
double A = gsl_vector_get (x, 0);
double lambda = gsl_vector_get (x, 1);
double b = gsl_vector_get (x, 2);
size_t i;
for (i = 0; i < n; i++)
{
/* Model Yi = A * exp(-lambda * i) + b */
double t = i;
double Yi = A * exp (-lambda * t) + b;
gsl_vector_set (f, i, (Yi - y[i])/sigma[i]);
}
return GSL_SUCCESS;
}
int expb_df (const gsl_vector * x, void *data, gsl_matrix * J)
{
size_t n = ((struct data *)data)->n;
double *sigma = ((struct data *) data)->sigma;
double A = gsl_vector_get (x, 0);
double lambda = gsl_vector_get (x, 1);
size_t i;
for (i = 0; i < n; i++)
{
/* Jacobian matrix J(i,j) = dfi / dxj, */
/* where fi = (Yi - yi)/sigma[i], */
/* Yi = A * exp(-lambda * i) + b */
/* and the xj are the parameters (A,lambda,b) */
double t = i;
double s = sigma[i];
double e = exp(-lambda * t);
gsl_matrix_set (J, i, 0, e/s);
gsl_matrix_set (J, i, 1, -t * A * e/s);
gsl_matrix_set (J, i, 2, 1/s);
}
return GSL_SUCCESS;
}
int expb_fdf (const gsl_vector * x, void *data, gsl_vector * f, gsl_matrix * J)
{
expb_f (x, data, f);
expb_df (x, data, J);
return GSL_SUCCESS;
}
void print_state (size_t iter, gsl_multifit_fdfsolver * s);
int main (void)
{
const gsl_multifit_fdfsolver_type *T;
gsl_multifit_fdfsolver *s;
int status;
unsigned int i, iter = 0;
const size_t n = N;
const size_t p = 3;
gsl_matrix *covar = gsl_matrix_alloc (p, p);
double y[N], sigma[N];
struct data d = { n, y, sigma};
gsl_multifit_function_fdf f;
double x_init[3] = { 1.0, 0.0, 0.0 };
gsl_vector_view x = gsl_vector_view_array (x_init, p);
const gsl_rng_type * type;
gsl_rng * r;
gsl_rng_env_setup();
type = gsl_rng_default;
r = gsl_rng_alloc (type);
f.f = &expb_f;
f.df = &expb_df;
f.fdf = &expb_fdf;
f.n = n;
f.p = p;
f.params = &d;
/* This is the data to be fitted */
for (i = 0; i < n; i++)
{
double t = i;
y[i] = 1.0 + 5 * exp (-0.1 * t) + gsl_ran_gaussian (r, 0.1);
sigma[i] = 0.1;
printf ("data: %u %g %g\n", i, y[i], sigma[i]);
};
T = gsl_multifit_fdfsolver_lmsder;
s = gsl_multifit_fdfsolver_alloc (T, n, p);
gsl_multifit_fdfsolver_set (s, &f, &x.vector);
print_state (iter, s);
do
{
iter++;
status = gsl_multifit_fdfsolver_iterate (s);
printf ("status = %s\n", gsl_strerror (status));
print_state (iter, s);
if (status)
break;
status = gsl_multifit_test_delta (s->dx, s->x,
1e-4, 1e-4);
}
while (status == GSL_CONTINUE && iter < 500);
gsl_multifit_covar (s->J, 0.0, covar);
{
double chi = gsl_blas_dnrm2(s->f);
double dof = n - p;
double c = GSL_MAX_DBL(1, chi / sqrt(dof));
printf("chisq/dof = %g\n", pow(chi, 2.0) / dof);
printf ("A = %.5f +/- %.5f\n", FIT(0), c*ERR(0));
printf ("lambda = %.5f +/- %.5f\n", FIT(1), c*ERR(1));
printf ("b = %.5f +/- %.5f\n", FIT(2), c*ERR(2));
}
printf ("status = %s\n", gsl_strerror (status));
gsl_multifit_fdfsolver_free (s);
gsl_matrix_free (covar);
gsl_rng_free (r);
return 0;
}
void print_state (size_t iter, gsl_multifit_fdfsolver * s)
{
printf ("iter: %3u x = % 15.8f % 15.8f % 15.8f "
"|f(x)| = %g\n",
iter,
gsl_vector_get (s->x, 0),
gsl_vector_get (s->x, 1),
gsl_vector_get (s->x, 2),
gsl_blas_dnrm2 (s->f));
}
Ideally it should simply generate a short data set that follows a decaying exponential with some white noise on top and then fit it.
To get it running in Code::Blocks in windows I followed the procedure outlined here: installing GSL on Windows XP 32bit for use with codeblocks
It compiles without warnings even with -Wall and -Wextra flags. However, it fails on the line: gsl_multifit_fdfsolver_set (s, &f, &x.vector); with the error: multifit\fdfsolver.c:132: ERROR: vector length does not match solver. Default GSL error handler invoked.
I was a little surprised to find this in what should be raw example code, but here we are. So I am hoping someone more knowledgeable than I can tell me what I am doing wrong with this simple example.
Figured it out: They were allocating their initial vector wrong. The fixed code is here:
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_multifit_nlin.h>
#define N 40
#define FIT(i) gsl_vector_get(s->x, i)
#define ERR(i) sqrt(gsl_matrix_get(covar,i,i))
struct data {
size_t n;
double * y;
double * sigma;
};
int expb_f (const gsl_vector * x, void *data, gsl_vector * f)
{
size_t n = ((struct data *)data)->n;
double *y = ((struct data *)data)->y;
double *sigma = ((struct data *) data)->sigma;
double A = gsl_vector_get (x, 0);
double lambda = gsl_vector_get (x, 1);
double b = gsl_vector_get (x, 2);
size_t i;
for (i = 0; i < n; i++)
{
/* Model Yi = A * exp(-lambda * i) + b */
double t = i;
double Yi = A * exp (-lambda * t) + b;
gsl_vector_set (f, i, (Yi - y[i])/sigma[i]);
}
return GSL_SUCCESS;
}
int expb_df (const gsl_vector * x, void *data, gsl_matrix * J)
{
size_t n = ((struct data *)data)->n;
double *sigma = ((struct data *) data)->sigma;
double A = gsl_vector_get (x, 0);
double lambda = gsl_vector_get (x, 1);
size_t i;
for (i = 0; i < n; i++)
{
/* Jacobian matrix J(i,j) = dfi / dxj, */
/* where fi = (Yi - yi)/sigma[i], */
/* Yi = A * exp(-lambda * i) + b */
/* and the xj are the parameters (A,lambda,b) */
double t = i;
double s = sigma[i];
double e = exp(-lambda * t);
gsl_matrix_set (J, i, 0, e/s);
gsl_matrix_set (J, i, 1, -t * A * e/s);
gsl_matrix_set (J, i, 2, 1/s);
}
return GSL_SUCCESS;
}
int expb_fdf (const gsl_vector * x, void *data, gsl_vector * f, gsl_matrix * J)
{
expb_f (x, data, f);
expb_df (x, data, J);
return GSL_SUCCESS;
}
void print_state (size_t iter, gsl_multifit_fdfsolver * s);
int main (void)
{
const gsl_multifit_fdfsolver_type *T;
gsl_multifit_fdfsolver *s;
int status;
unsigned int i, iter = 0;
const size_t n = N;
const size_t p = 3;
gsl_matrix *covar = gsl_matrix_alloc (p, p);
double y[N], sigma[N];
struct data d = { n, y, sigma};
gsl_multifit_function_fdf f;
gsl_vector *x = gsl_vector_alloc(p);
for (i=0; i<p; i++)
{
gsl_vector_set(x,i,i==0 ? 1 : 0);
}
const gsl_rng_type * type;
gsl_rng * r;
gsl_rng_env_setup();
type = gsl_rng_default;
r = gsl_rng_alloc (type);
f.f = &expb_f;
f.df = &expb_df;
f.fdf = &expb_fdf;
f.n = n;
f.p = p;
f.params = &d;
/* This is the data to be fitted */
for (i = 0; i < n; i++)
{
double t = i;
y[i] = 1.0 + 5 * exp (-0.1 * t) + gsl_ran_gaussian (r, 0.1);
sigma[i] = 0.1;
printf ("data: %u %g %g\n", i, y[i], sigma[i]);
};
T = gsl_multifit_fdfsolver_lmsder;
s = gsl_multifit_fdfsolver_alloc (T, n, p);
gsl_multifit_fdfsolver_set (s, &f, x);
print_state (iter, s);
do
{
iter++;
status = gsl_multifit_fdfsolver_iterate (s);
printf ("status = %s\n", gsl_strerror (status));
print_state (iter, s);
if (status)
break;
status = gsl_multifit_test_delta (s->dx, s->x,
1e-4, 1e-4);
}
while (status == GSL_CONTINUE && iter < 500);
gsl_multifit_covar (s->J, 0.0, covar);
{
double chi = gsl_blas_dnrm2(s->f);
double dof = n - p;
double c = GSL_MAX_DBL(1, chi / sqrt(dof));
printf("chisq/dof = %g\n", pow(chi, 2.0) / dof);
printf ("A = %.5f +/- %.5f\n", FIT(0), c*ERR(0));
printf ("lambda = %.5f +/- %.5f\n", FIT(1), c*ERR(1));
printf ("b = %.5f +/- %.5f\n", FIT(2), c*ERR(2));
}
printf ("status = %s\n", gsl_strerror (status));
gsl_multifit_fdfsolver_free (s);
gsl_matrix_free (covar);
gsl_rng_free (r);
gsl_vector_free(x);
return 0;
}
void print_state (size_t iter, gsl_multifit_fdfsolver * s)
{
printf ("iter: %3u x = % 15.8f % 15.8f % 15.8f "
"|f(x)| = %g\n",
iter,
gsl_vector_get (s->x, 0),
gsl_vector_get (s->x, 1),
gsl_vector_get (s->x, 2),
gsl_blas_dnrm2 (s->f));
}
I am studying a CUDA C example (ripple.cu in chapter 5) on the CUDA C by Example book; when I compile the file it seems there is no problem; here's what i type on the terminal:
nvcc ripple.cu -lGL -lGLU -lX11 -lXi -lXmu -lglut -lGLEW
When I run the executable i should get an image like this:
However this is what i get instead:
Here I post the file ripple.cu and the related header files:
// ripple.cu
#include "cuda.h"
#include "../common/book.h"
#include "../common/cpu_anim.h"
#define DIM 1024
#define PI 3.1415926535897932f
__global__ void kernel( unsigned char *ptr, int ticks ) {
// map from threadIdx/BlockIdx to pixel position
int x = threadIdx.x + blockIdx.x * blockDim.x;
int y = threadIdx.y + blockIdx.y * blockDim.y;
int offset = x + y * blockDim.x * gridDim.x;
// now calculate the value at that position
float fx = x - DIM/2;
float fy = y - DIM/2;
float d = sqrtf( fx * fx + fy * fy );
unsigned char grey = (unsigned char)(128.0f + 127.0f *
cos(d/10.0f - ticks/7.0f) /
(d/10.0f + 1.0f));
ptr[offset*4 + 0] = grey;
ptr[offset*4 + 1] = grey;
ptr[offset*4 + 2] = grey;
ptr[offset*4 + 3] = 255;
}
struct DataBlock {
unsigned char *dev_bitmap;
CPUAnimBitmap *bitmap;
};
void generate_frame( DataBlock *d, int ticks ) {
dim3 blocks(DIM/16,DIM/16);
dim3 threads(16,16);
kernel<<<blocks,threads>>>( d->dev_bitmap, ticks );
HANDLE_ERROR( cudaMemcpy( d->bitmap->get_ptr(),
d->dev_bitmap,
d->bitmap->image_size(),
cudaMemcpyDeviceToHost ) );
}
// clean up memory allocated on the GPU
void cleanup( DataBlock *d ) {
HANDLE_ERROR( cudaFree( d->dev_bitmap ) );
}
int main( void ) {
DataBlock data;
CPUAnimBitmap bitmap( DIM, DIM, &data );
data.bitmap = &bitmap;
HANDLE_ERROR( cudaMalloc( (void**)&data.dev_bitmap,
bitmap.image_size() ) );
bitmap.anim_and_exit( (void (*)(void*,int))generate_frame,
(void (*)(void*))cleanup );
}
Now i post the headers which are contained into a folder named common:
// book.h
#ifndef __BOOK_H__
#define __BOOK_H__
#include <stdio.h>
static void HandleError( cudaError_t err,
const char *file,
int line ) {
if (err != cudaSuccess) {
printf( "%s in %s at line %d\n", cudaGetErrorString( err ),
file, line );
exit( EXIT_FAILURE );
}
}
#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ ))
#define HANDLE_NULL( a ) {if (a == NULL) { \
printf( "Host memory failed in %s at line %d\n", \
__FILE__, __LINE__ ); \
exit( EXIT_FAILURE );}}
template< typename T >
void swap( T& a, T& b ) {
T t = a;
a = b;
b = t;
}
void* big_random_block( int size ) {
unsigned char *data = (unsigned char*)malloc( size );
HANDLE_NULL( data );
for (int i=0; i<size; i++)
data[i] = rand();
return data;
}
int* big_random_block_int( int size ) {
int *data = (int*)malloc( size * sizeof(int) );
HANDLE_NULL( data );
for (int i=0; i<size; i++)
data[i] = rand();
return data;
}
// a place for common kernels - starts here
__device__ unsigned char value( float n1, float n2, int hue ) {
if (hue > 360) hue -= 360;
else if (hue < 0) hue += 360;
if (hue < 60)
return (unsigned char)(255 * (n1 + (n2-n1)*hue/60));
if (hue < 180)
return (unsigned char)(255 * n2);
if (hue < 240)
return (unsigned char)(255 * (n1 + (n2-n1)*(240-hue)/60));
return (unsigned char)(255 * n1);
}
__global__ void float_to_color( unsigned char *optr,
const float *outSrc ) {
// map from threadIdx/BlockIdx to pixel position
int x = threadIdx.x + blockIdx.x * blockDim.x;
int y = threadIdx.y + blockIdx.y * blockDim.y;
int offset = x + y * blockDim.x * gridDim.x;
float l = outSrc[offset];
float s = 1;
int h = (180 + (int)(360.0f * outSrc[offset])) % 360;
float m1, m2;
if (l <= 0.5f)
m2 = l * (1 + s);
else
m2 = l + s - l * s;
m1 = 2 * l - m2;
optr[offset*4 + 0] = value( m1, m2, h+120 );
optr[offset*4 + 1] = value( m1, m2, h );
optr[offset*4 + 2] = value( m1, m2, h -120 );
optr[offset*4 + 3] = 255;
}
__global__ void float_to_color( uchar4 *optr,
const float *outSrc ) {
// map from threadIdx/BlockIdx to pixel position
int x = threadIdx.x + blockIdx.x * blockDim.x;
int y = threadIdx.y + blockIdx.y * blockDim.y;
int offset = x + y * blockDim.x * gridDim.x;
float l = outSrc[offset];
float s = 1;
int h = (180 + (int)(360.0f * outSrc[offset])) % 360;
float m1, m2;
if (l <= 0.5f)
m2 = l * (1 + s);
else
m2 = l + s - l * s;
m1 = 2 * l - m2;
optr[offset].x = value( m1, m2, h+120 );
optr[offset].y = value( m1, m2, h );
optr[offset].z = value( m1, m2, h -120 );
optr[offset].w = 255;
}
#if _WIN32
//Windows threads.
#include <windows.h>
typedef HANDLE CUTThread;
typedef unsigned (WINAPI *CUT_THREADROUTINE)(void *);
#define CUT_THREADPROC unsigned WINAPI
#define CUT_THREADEND return 0
#else
//POSIX threads.
#include <pthread.h>
typedef pthread_t CUTThread;
typedef void *(*CUT_THREADROUTINE)(void *);
#define CUT_THREADPROC void
#define CUT_THREADEND
#endif
//Create thread.
CUTThread start_thread( CUT_THREADROUTINE, void *data );
//Wait for thread to finish.
void end_thread( CUTThread thread );
//Destroy thread.
void destroy_thread( CUTThread thread );
//Wait for multiple threads.
void wait_for_threads( const CUTThread *threads, int num );
#if _WIN32
//Create thread
CUTThread start_thread(CUT_THREADROUTINE func, void *data){
return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, data, 0, NULL);
}
//Wait for thread to finish
void end_thread(CUTThread thread){
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
}
//Destroy thread
void destroy_thread( CUTThread thread ){
TerminateThread(thread, 0);
CloseHandle(thread);
}
//Wait for multiple threads
void wait_for_threads(const CUTThread * threads, int num){
WaitForMultipleObjects(num, threads, true, INFINITE);
for(int i = 0; i < num; i++)
CloseHandle(threads[i]);
}
#else
//Create thread
CUTThread start_thread(CUT_THREADROUTINE func, void * data){
pthread_t thread;
pthread_create(&thread, NULL, func, data);
return thread;
}
//Wait for thread to finish
void end_thread(CUTThread thread){
pthread_join(thread, NULL);
}
//Destroy thread
void destroy_thread( CUTThread thread ){
pthread_cancel(thread);
}
//Wait for multiple threads
void wait_for_threads(const CUTThread * threads, int num){
for(int i = 0; i < num; i++)
end_thread( threads[i] );
}
#endif
// cpu_anim.h
#endif // __BOOK_H__
Here's the second header:
// cpu_anim.h
#ifndef __CPU_ANIM_H__
#define __CPU_ANIM_H__
#include "gl_helper.h"
#include <iostream>
struct CPUAnimBitmap {
unsigned char *pixels;
int width, height;
void *dataBlock;
void (*fAnim)(void*,int);
void (*animExit)(void*);
void (*clickDrag)(void*,int,int,int,int);
int dragStartX, dragStartY;
CPUAnimBitmap( int w, int h, void *d = NULL ) {
width = w;
height = h;
pixels = new unsigned char[width * height * 4];
dataBlock = d;
clickDrag = NULL;
}
~CPUAnimBitmap() {
delete [] pixels;
}
unsigned char* get_ptr( void ) const { return pixels; }
long image_size( void ) const { return width * height * 4; }
void click_drag( void (*f)(void*,int,int,int,int)) {
clickDrag = f;
}
void anim_and_exit( void (*f)(void*,int), void(*e)(void*) ) {
CPUAnimBitmap** bitmap = get_bitmap_ptr();
*bitmap = this;
fAnim = f;
animExit = e;
// a bug in the Windows GLUT implementation prevents us from
// passing zero arguments to glutInit()
int c=1;
char* dummy = (char *)(void *)"";
glutInit( &c, &dummy );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA );
glutInitWindowSize( width, height );
glutCreateWindow( "bitmap" );
glutKeyboardFunc(Key);
glutDisplayFunc(Draw);
if (clickDrag != NULL)
glutMouseFunc( mouse_func );
glutIdleFunc( idle_func );
glutMainLoop();
}
// static method used for glut callbacks
static CPUAnimBitmap** get_bitmap_ptr( void ) {
static CPUAnimBitmap* gBitmap;
return &gBitmap;
}
// static method used for glut callbacks
static void mouse_func( int button, int state,
int mx, int my ) {
if (button == GLUT_LEFT_BUTTON) {
CPUAnimBitmap* bitmap = *(get_bitmap_ptr());
if (state == GLUT_DOWN) {
bitmap->dragStartX = mx;
bitmap->dragStartY = my;
} else if (state == GLUT_UP) {
bitmap->clickDrag( bitmap->dataBlock,
bitmap->dragStartX,
bitmap->dragStartY,
mx, my );
}
}
}
// static method used for glut callbacks
static void idle_func( void ) {
static int ticks = 1;
CPUAnimBitmap* bitmap = *(get_bitmap_ptr());
bitmap->fAnim( bitmap->dataBlock, ticks++ );
glutPostRedisplay();
}
// static method used for glut callbacks
static void Key(unsigned char key, int x, int y) {
switch (key) {
case 27:
CPUAnimBitmap* bitmap = *(get_bitmap_ptr());
bitmap->animExit( bitmap->dataBlock );
//delete bitmap;
exit(0);
}
}
// static method used for glut callbacks
static void Draw( void ) {
CPUAnimBitmap* bitmap = *(get_bitmap_ptr());
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glDrawPixels( bitmap->width, bitmap->height, GL_RGBA, GL_UNSIGNED_BYTE, bitmap->pixels );
glutSwapBuffers();
}
};
#endif // __CPU_ANIM_H__
I don't really know where the problem might be... I have already asked in the NVIDA FORUM without success... Here's the link where you can download the source code in case you want: https://developer.nvidia.com/content/cuda-example-introduction-general-purpose-gpu-programming-0
I know it is a very specific problem and it takes a lot of effort to read it but any suggestion is welcome.
I just figured out how to make it work... so i basically changed the dimensions of the window from 1024 to 512:
ripple.cu: #define DIM 1024 ----> #define DIM 512
I don't know why but it works now! I just got lucky.
Can anyone give me a short code example in c using opengl where clicking in two different squares changes their color? I'm particularly interested in knowing how to detect that a mouse click has happened to a particular primitive.
Here's a GL selection-mode example
/* Copyright (c) Mark J. Kilgard, 1994. */
/**
* (c) Copyright 1993, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <GL/glut.h>
#define MAXOBJS 10000
#define MAXSELECT 100
#define MAXFEED 300
#define SOLID 1
#define LINE 2
#define POINT 3
GLint windW = 300, windH = 300;
GLuint selectBuf[MAXSELECT];
GLfloat feedBuf[MAXFEED];
GLint vp[4];
float zRotation = 90.0;
float zoom = 1.0;
GLint objectCount;
GLint numObjects;
struct object {
float v1[2];
float v2[2];
float v3[2];
float color[3];
} objects[MAXOBJS];
GLenum linePoly = GL_FALSE;
static void InitObjects(GLint num)
{
GLint i;
float x, y;
if (num > MAXOBJS) {
num = MAXOBJS;
}
if (num < 1) {
num = 1;
}
objectCount = num;
srand((unsigned int) time(NULL));
for (i = 0; i < num; i++) {
x = (rand() % 300) - 150;
y = (rand() % 300) - 150;
objects[i].v1[0] = x + (rand() % 50) - 25;
objects[i].v2[0] = x + (rand() % 50) - 25;
objects[i].v3[0] = x + (rand() % 50) - 25;
objects[i].v1[1] = y + (rand() % 50) - 25;
objects[i].v2[1] = y + (rand() % 50) - 25;
objects[i].v3[1] = y + (rand() % 50) - 25;
objects[i].color[0] = ((rand() % 100) + 50) / 150.0;
objects[i].color[1] = ((rand() % 100) + 50) / 150.0;
objects[i].color[2] = ((rand() % 100) + 50) / 150.0;
}
}
static void Init(void)
{
numObjects = 10;
InitObjects(numObjects);
}
static void Reshape(int width, int height)
{
windW = width;
windH = height;
glViewport(0, 0, windW, windH);
glGetIntegerv(GL_VIEWPORT, vp);
}
static void Render(GLenum mode)
{
GLint i;
for (i = 0; i < objectCount; i++) {
if (mode == GL_SELECT) {
glLoadName(i);
}
glColor3fv(objects[i].color);
glBegin(GL_POLYGON);
glVertex2fv(objects[i].v1);
glVertex2fv(objects[i].v2);
glVertex2fv(objects[i].v3);
glEnd();
}
}
static GLint DoSelect(GLint x, GLint y)
{
GLint hits;
glSelectBuffer(MAXSELECT, selectBuf);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(~0);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPickMatrix(x, windH - y, 4, 4, vp);
gluOrtho2D(-175, 175, -175, 175);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glScalef(zoom, zoom, zoom);
glRotatef(zRotation, 0, 0, 1);
Render(GL_SELECT);
glPopMatrix();
hits = glRenderMode(GL_RENDER);
if (hits <= 0) {
return -1;
}
return selectBuf[(hits - 1) * 4 + 3];
}
static void RecolorTri(GLint h)
{
objects[h].color[0] = ((rand() % 100) + 50) / 150.0;
objects[h].color[1] = ((rand() % 100) + 50) / 150.0;
objects[h].color[2] = ((rand() % 100) + 50) / 150.0;
}
static void DeleteTri(GLint h)
{
objects[h] = objects[objectCount - 1];
objectCount--;
}
static void GrowTri(GLint h)
{
float v[2];
float *oldV;
GLint i;
v[0] = objects[h].v1[0] + objects[h].v2[0] + objects[h].v3[0];
v[1] = objects[h].v1[1] + objects[h].v2[1] + objects[h].v3[1];
v[0] /= 3;
v[1] /= 3;
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
oldV = objects[h].v1;
break;
case 1:
oldV = objects[h].v2;
break;
case 2:
oldV = objects[h].v3;
break;
}
oldV[0] = 1.5 * (oldV[0] - v[0]) + v[0];
oldV[1] = 1.5 * (oldV[1] - v[1]) + v[1];
}
}
static void Mouse(int button, int state, int mouseX, int mouseY)
{
GLint hit;
if (state == GLUT_DOWN) {
hit = DoSelect((GLint) mouseX, (GLint) mouseY);
if (hit != -1) {
if (button == GLUT_LEFT_BUTTON) {
RecolorTri(hit);
} else if (button == GLUT_MIDDLE_BUTTON) {
GrowTri(hit);
} else if (button == GLUT_RIGHT_BUTTON) {
DeleteTri(hit);
}
glutPostRedisplay();
}
}
}
static void Draw(void)
{
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-175, 175, -175, 175);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glScalef(zoom, zoom, zoom);
glRotatef(zRotation, 0, 0, 1);
Render(GL_RENDER);
glPopMatrix();
glutSwapBuffers();
}
static void DumpFeedbackVert(GLint * i, GLint n)
{
GLint index;
index = *i;
if (index + 7 > n) {
*i = n;
printf(" ???\n");
return;
}
printf(" (%g %g %g), color = (%4.2f %4.2f %4.2f)\n",
feedBuf[index],
feedBuf[index + 1],
feedBuf[index + 2],
feedBuf[index + 3],
feedBuf[index + 4],
feedBuf[index + 5]);
index += 7;
*i = index;
}
static void DrawFeedback(GLint n)
{
GLint i;
GLint verts;
printf("Feedback results (%d floats):\n", n);
for (i = 0; i < n; i++) {
switch ((GLint) feedBuf[i]) {
case GL_POLYGON_TOKEN:
printf("Polygon");
i++;
if (i < n) {
verts = (GLint) feedBuf[i];
i++;
printf(": %d vertices", verts);
} else {
verts = 0;
}
printf("\n");
while (verts) {
DumpFeedbackVert(&i, n);
verts--;
}
i--;
break;
case GL_LINE_TOKEN:
printf("Line:\n");
i++;
DumpFeedbackVert(&i, n);
DumpFeedbackVert(&i, n);
i--;
break;
case GL_LINE_RESET_TOKEN:
printf("Line Reset:\n");
i++;
DumpFeedbackVert(&i, n);
DumpFeedbackVert(&i, n);
i--;
break;
default:
printf("%9.2f\n", feedBuf[i]);
break;
}
}
if (i == MAXFEED) {
printf("...\n");
}
printf("\n");
}
static void DoFeedback(void)
{
GLint x;
glFeedbackBuffer(MAXFEED, GL_3D_COLOR, feedBuf);
(void) glRenderMode(GL_FEEDBACK);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-175, 175, -175, 175);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glScalef(zoom, zoom, zoom);
glRotatef(zRotation, 0, 0, 1);
Render(GL_FEEDBACK);
glPopMatrix();
x = glRenderMode(GL_RENDER);
if (x == -1) {
x = MAXFEED;
}
DrawFeedback((GLint) x);
}
static void Key(unsigned char key, int x, int y)
{
switch (key) {
case 'z':
zoom /= 0.75;
glutPostRedisplay();
break;
case 'Z':
zoom *= 0.75;
glutPostRedisplay();
break;
case 'f':
DoFeedback();
glutPostRedisplay();
break;
case 'l':
linePoly = !linePoly;
if (linePoly) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
glutPostRedisplay();
break;
case 27:
exit(0);
}
}
static void SpecialKey(int key, int x, int y)
{
switch (key) {
case GLUT_KEY_LEFT:
zRotation += 0.5;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
zRotation -= 0.5;
glutPostRedisplay();
break;
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Select Test");
Init();
glutReshapeFunc(Reshape);
glutKeyboardFunc(Key);
glutSpecialFunc(SpecialKey);
glutMouseFunc(Mouse);
glutDisplayFunc(Draw);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
That program is a part of some other GLUT examples.
The GL selection buffer is old and busted though, you're probably better off using color-readback selection or some CPU-side "ray casting" system that integrates with your geometry representation.
Read up on OpenGL's selection feature. That is the classical way of doing it, and should work well for at least small amount of object (which sounds right for your question).
Not a complete example, but there's also a section on the OpenGL FAQ on Picking and Selection which should be noted.