В-общем я написал этот код. Цель этого кода - крутить головой во все стороны.
Код:
#include <stdio.h>
#include <stdlib.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <X11/extensions/xf86vmode.h>
#include <X11/keysym.h>
GLfloat eye1 = 0.0;
GLfloat eye2 = 0.0;
GLfloat eye3 = 0.0;
GLfloat center1 = -5.0; /* - */
GLfloat center2 = 1.5; /* | */
GLfloat center3 = -10.0;
GLfloat vector1 = 0.0;
GLfloat vector2 = 1.0;
GLfloat vector3 = 0.0;
/* stuff about our window grouped together */
typedef struct {
Display *dpy;
int screen;
Window win;
GLXContext ctx;
XSetWindowAttributes attr;
Bool fs;
XF86VidModeModeInfo deskMode;
int x, y;
unsigned int width, height;
unsigned int depth;
} GLWindow;
typedef struct {
int width;
int height;
unsigned char *data;
} textureImage;
int rotDown, rotUp;
/* attributes for a single buffered visual in RGBA format with at least
* 4 bits per color and a 16 bit depth buffer */
static int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 16,
None};
/* attributes for a double buffered visual in RGBA format with at least
* 4 bits per color and a 16 bit depth buffer */
static int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 16,
None };
GLWindow GLWin;
Bool done;
GLfloat rotX; /* X Rotation */
GLfloat rotY; /* Y Rotation */
GLfloat rotZ; /* Z Rotation */
GLuint texture[1]; /* Storage For One Texture */
/* simple loader for 24bit bitmaps (data is in rgb-format) */
int loadBMP(char *filename, textureImage *texture)
{
FILE *file;
unsigned short int bfType;
long int bfOffBits;
short int biPlanes;
short int biBitCount;
long int biSizeImage;
int i;
unsigned char temp;
/* make sure the file is there and open it read-only (binary) */
if ((file = fopen(filename, "rb")) == NULL)
{
printf("File not found : %s\n", filename);
return 0;
}
if(!fread(&bfType, sizeof(short int), 1, file))
{
printf("Error reading file!\n");
return 0;
}
/* check if file is a bitmap */
if (bfType != 19778)
{
printf("Not a Bitmap-File!\n");
return 0;
}
/* get the file size */
/* skip file size and reserved fields of bitmap file header */
fseek(file, 8, SEEK_CUR);
/* get the position of the actual bitmap data */
if (!fread(&bfOffBits, sizeof(long int), 1, file))
{
printf("Error reading file!\n");
return 0;
}
printf("Data at Offset: %ld\n", bfOffBits);
/* skip size of bitmap info header */
fseek(file, 4, SEEK_CUR);
/* get the width of the bitmap */
fread(&texture->width, sizeof(int), 1, file);
printf("Width of Bitmap: %d\n", texture->width);
/* get the height of the bitmap */
fread(&texture->height, sizeof(int), 1, file);
printf("Height of Bitmap: %d\n", texture->height);
/* get the number of planes (must be set to 1) */
fread(&biPlanes, sizeof(short int), 1, file);
if (biPlanes != 1)
{
printf("Error: number of Planes not 1!\n");
return 0;
}
/* get the number of bits per pixel */
if (!fread(&biBitCount, sizeof(short int), 1, file))
{
printf("Error reading file!\n");
return 0;
}
printf("Bits per Pixel: %d\n", biBitCount);
if (biBitCount != 24)
{
printf("Bits per Pixel not 24\n");
return 0;
}
/* calculate the size of the image in bytes */
biSizeImage = texture->width * texture->height * 3;
printf("Size of the image data: %ld\n", biSizeImage);
texture->data = malloc(biSizeImage);
/* seek to the actual data */
fseek(file, bfOffBits, SEEK_SET);
if (!fread(texture->data, biSizeImage, 1, file))
{
printf("Error loading file!\n");
return 0;
}
/* swap red and blue (bgr -> rgb) */
for (i = 0; i < biSizeImage; i += 3)
{
temp = texture->data[i];
texture->data[i] = texture->data[i + 2];
texture->data[i + 2] = temp;
}
return 1;
}
Bool loadGLTextures() /* Load Bitmaps And Convert To Textures */
{
Bool status;
textureImage *texti;
status = False;
texti = malloc(sizeof(textureImage));
if (loadBMP("data/texture.bmp", texti))
{
status = True;
glGenTextures(1, &texture[0]); /* create the texture */
glBindTexture(GL_TEXTURE_2D, texture[0]);
/* actually generate the texture */
glTexImage2D(GL_TEXTURE_2D, 0, 3, texti->width, texti->height, 0,
GL_RGB, GL_UNSIGNED_BYTE, texti->data);
/* enable linear filtering */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
/* free the ram we used in our texture generation process */
if (texti)
{
if (texti->data)
free(texti->data);
free(texti);
}
return status;
}
/* function called when our window is resized (should only happen in window mode) */
void resizeGLScene(unsigned int width, unsigned int height)
{
if (height == 0) /* Prevent A Divide By Zero If The Window Is Too Small */
height = 1;
/* Reset The Current Viewport And Perspective Transformation */
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
}
/* general OpenGL initialization function */
int initGL(GLvoid)
{
if (!loadGLTextures())
{
return False;
}
glEnable(GL_TEXTURE_2D); /* Enable Texture Mapping */
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
/* we use resizeGLScene once to set up our initial perspective */
resizeGLScene(GLWin.width, GLWin.height);
glFlush();
return True;
}
/* Here goes our drawing code */
int drawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(eye1, eye2, eye3, center1, center2, center3, vector1, vector2, vector3);
glBindTexture(GL_TEXTURE_2D, texture[0]); /* select our texture */
glBegin(GL_QUADS);
/* front face */
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
/* back face */
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
/* right face */
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
/* left face */
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
/* top face */
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
/* bottom face */
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glEnd();
/* change the rotation angles */
rotX += 0.3f;
rotY += 0.2f;
rotZ += 0.4f;
glXSwapBuffers(GLWin.dpy, GLWin.win);
return True;
}
/* function to release/destroy our resources and restoring the old desktop */
GLvoid killGLWindow(GLvoid)
{
if (GLWin.ctx)
{
if (!glXMakeCurrent(GLWin.dpy, None, NULL))
{
printf("Could not release drawing context.\n");
}
glXDestroyContext(GLWin.dpy, GLWin.ctx);
GLWin.ctx = NULL;
}
/* switch back to original desktop resolution if we were in fs */
if (GLWin.fs)
{
XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode);
XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
}
XCloseDisplay(GLWin.dpy);
}
/* this function creates our window and sets it up properly */
Bool createGLWindow(char* title, int width, int height, int bits,
Bool fullscreenflag)
{
XVisualInfo *vi;
Colormap cmap;
int dpyWidth, dpyHeight;
int i;
int glxMajorVersion, glxMinorVersion;
int vidModeMajorVersion, vidModeMinorVersion;
XF86VidModeModeInfo **modes;
int modeNum;
int bestMode;
Atom wmDelete;
Window winDummy;
unsigned int borderDummy;
GLWin.fs = fullscreenflag;
/* set best mode to current */
bestMode = 0;
/* get a connection */
GLWin.dpy = XOpenDisplay(0);
GLWin.screen = DefaultScreen(GLWin.dpy);
XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion,
&vidModeMinorVersion);
printf("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion,
vidModeMinorVersion);
XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes);
/* save desktop-resolution before switching modes */
GLWin.deskMode = *modes[0];
/* look for mode with requested resolution */
for (i = 0; i < modeNum; i++)
{
if ((modes[i]->hdisplay == width) && (modes[i]->vdisplay == height))
{
bestMode = i;
}
}
/* get an appropriate visual */
vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
if (vi == NULL)
{
vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl);
printf("Only Singlebuffered Visual!\n");
}
else
{
printf("Got Doublebuffered Visual!\n");
}
glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion);
printf("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion);
/* create a GLX context */
GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE);
/* create a color map */
cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
vi->visual, AllocNone);
GLWin.attr.colormap = cmap;
GLWin.attr.border_pixel = 0;
if (GLWin.fs)
{
XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]);
XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
dpyWidth = modes[bestMode]->hdisplay;
dpyHeight = modes[bestMode]->vdisplay;
printf("Resolution %dx%d\n", dpyWidth, dpyHeight);
XFree(modes);
/* create a fullscreen window */
GLWin.attr.override_redirect = True;
GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
StructureNotifyMask;
GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
&GLWin.attr);
XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0);
XMapRaised(GLWin.dpy, GLWin.win);
XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync,
GrabModeAsync, CurrentTime);
XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask,
GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime);
}
else
{
/* create a window in window mode*/
GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
StructureNotifyMask;
GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr);
/* only set window title and handle wm_delete_events if in windowed mode */
wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True);
XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1);
XSetStandardProperties(GLWin.dpy, GLWin.win, title,
title, None, NULL, 0, NULL);
XMapRaised(GLWin.dpy, GLWin.win);
}
/* connect the glx-context to the window */
glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
&GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
printf("Depth %d\n", GLWin.depth);
if (glXIsDirect(GLWin.dpy, GLWin.ctx))
printf("Congrats, you have Direct Rendering!\n");
else
printf("Sorry, no Direct Rendering possible!\n");
if (!initGL())
{
printf("Could not initialize OpenGL.\nAborting...\n");
return False;
}
return True;
}
void keyPressed(KeySym key)
{
switch (key)
{
case XK_Escape:
done = True;
break;
case XK_F1:
killGLWindow();
GLWin.fs = !GLWin.fs;
createGLWindow("3D Room",
800, 800, 24, GLWin.fs);
break;
case XK_Up:
center2 += 0.3;
break;
case XK_Down:
center2 -= 0.3;
break;
case XK_Right:
center1 += 0.3;
break;
case XK_Left:
center1 -= 0.3;
break;
}
}
int main(int argc, char *argv[])
{
XEvent event;
KeySym key;
int c;
done = False;
/* check for --fullscreen option */
if (argc > 1 && (*++argv)[0] == '-')
switch ( c = *++argv[0])
case 'f':
GLWin.fs = True;
if (!createGLWindow("3D Room", 800, 600, 24,
GLWin.fs))
{
done = True;
}
/* wait for events*/
while (!done)
{
/* handle the events in the queue */
while (XPending(GLWin.dpy) > 0)
{
XNextEvent(GLWin.dpy, &event);
switch (event.type)
{
case Expose:
if (event.xexpose.count != 0)
break;
drawGLScene();
break;
case ConfigureNotify:
/* call resizeGLScene only if our window-size changed */
if ((event.xconfigure.width != GLWin.width) ||
(event.xconfigure.height != GLWin.height))
{
GLWin.width = event.xconfigure.width;
GLWin.height = event.xconfigure.height;
printf("Resize event\n");
resizeGLScene(event.xconfigure.width,
event.xconfigure.height);
}
break;
/* exit in case of a mouse button press */
case ButtonPress:
done = True;
break;
case KeyPress:
key = XLookupKeysym(&event.xkey, 0);
keyPressed(key);
break;
case ClientMessage:
if (*XGetAtomName(GLWin.dpy, event.xclient.message_type)
== *"WM_PROTOCOLS")
{
printf("Exiting sanely...\n");
done = True;
}
break;
default:
break;
}
}
drawGLScene();
}
killGLWindow();
return 0;
}
Управление стрелками, но когда я далеко разворачиваюсь в сторону или вверх, то это движение стает плавным и останавливается. Как сделать чтобы я мог крутить камерой без ограничений, как в Quake, например.
Код под Linux (GLX)