说明:
出于学习目的,自己写了一个opengl滑动条的类,虽然简单,但是可以基于这个例子去实现ui部分了.
要实现简单ui的最简单方法也许就是直接在屏幕上操作像素,就是不知道效率怎么样.
关键:
用到了glew中的函数:(我不知道opengl标准库是否有相似的函数,如果有的话宁愿用标准函数.glRasterPos2f我没有搞成功)
glewWindowspos2d:
函数说明:void glWindowPos2d(
GLdouble x,GLdouble y)
;
x:屏幕x坐标;
y:屏幕y坐标.
左下角为坐标系原点
作用说明:用于设定滑动条的位置
gl标准函数:
glDrawPixels:
函数说明:
glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
width,height:图像的宽和高;
format:像素缓存的类型:比如GL_RGBA,GL_RGB,与pixels分配缓存是w*h*(4或者3)对应,很重要;
type为数据类型;
pixels:像素缓存
作用说明:
将像素数据拷贝到帧缓存中.
SlidBar类:
说明:
显示结果:
黄色竖条为可移动的部分.
坐标系:
左下角为坐标原点.
这个类有两种使用方法.
class SlidBar { private: GLdouble pos0[2];//滑动条在屏幕上的位置 GLdouble pos_point[2];//滑动点的位置 GLint length;//滑动条长度,单位:像素 GLfloat ratio;//0-1,滑动条当前百分比 unsigned char* pixels;//滑动条的像素信息 GLdouble highvalue;//滑动条达到100%时的数值 GLdouble lowvalue;//0%时的数值 void SetRatio(int x)//设置百分比,滑动点 { ratio = (GLfloat)GLfloat(x - pos0[0]) / GLfloat(length); pos_point[0] = pos0[0] + length*ratio; printf("ratio %f\n",ratio); } void SetPixels()//改变像素信息,也就是滑动条的ui图像 { unsigned int index; for (int i = 0; i < slidheight; i++)//初始化,全部设置成透明状态 { for (int j = 0; j < length; j++) { index = i*length + j;//像素矩阵第i行第j列,每个"单位"有rgba四个值需要设置 pixels[index * 4 + 0] = 0;//r pixels[index * 4 + 1] = 0;//g pixels[index * 4 + 2] = 0;//b pixels[index * 4 + 3] = 0;//a } } for (int i = 0; i < length; i++)//横向 { index = 0.5*slidheight*length + i; pixels[index * 4 + 0] = 255;//r pixels[index * 4 + 1] = 0;//r pixels[index * 4 + 2] = 0;//b pixels[index * 4 + 3] = 255;//a } for (int j = 0; j < slidheight; j++)//纵向 { index = j*length;//最左边的边界,表现为一条红色的竖"1" pixels[index * 4 + 0] = 255; pixels[index * 4 + 1] = 0; pixels[index * 4 + 2] = 0; pixels[index * 4 + 3] = 255; index = j*length + length - 1;//最右边的边界,同上 pixels[index * 4 + 0] = 255; pixels[index * 4 + 1] = 0; pixels[index * 4 + 2] = 0; pixels[index * 4 + 3] = 255; index = j*length + (length - 1)*ratio;//当前滑动点的位置,表现为一条黄色的竖"1" pixels[index * 4 + 0] = 255; pixels[index * 4 + 1] = 255; pixels[index * 4 + 2] = 0; pixels[index * 4 + 3] = 255; } } public: SlidBar() { } ~SlidBar() { free(pixels); } void Init(GLdouble* pos0, GLfloat ratio, GLint length)//策略1:只返回ratio { this->pos0[0] = pos0[0];//滑动条位置 this->pos0[1] = pos0[1]; this->ratio = ratio;//初始百分比 this->length = length;//长度 pos_point[0] = pos0[0] + length*ratio;//滑动点的位置 pos_point[1] = pos0[1]; this->pixels = new unsigned char[length *slidheight * 4];//初始化像素缓存 SetPixels();//根据当前状态在像素缓存中进行绘制 } void Init_value(GLdouble* pos0, GLfloat ratio, GLint length,GLdouble lowvalue,GLdouble highvalue)//策略2:直接获得最低值和最高值,返回现在的值 { this->pos0[0] = pos0[0]; this->pos0[1] = pos0[1]; this->ratio = ratio; this->length = length; pos_point[0] = pos0[0] + length*ratio; pos_point[1] = pos0[1]; this->pixels = new unsigned char[length *slidheight * 4]; SetPixels(); this->lowvalue = lowvalue; this->highvalue = highvalue; } GLfloat GetRatio()//获得当前百分比 { return ratio; } GLdouble GetValue()//如果使用策略2,用这个函数获得当前值 { return (lowvalue + (highvalue - lowvalue)*ratio); } bool TouchTest(int x, int y)//由传进来的鼠标坐标(左下角为原点,所以可能需要变换)测试是否点中 { bool target = false; int x0 = pos0[0];//滑动条左下角x int y0 = pos0[1] - slidheight / 2;//左下角y int x1 = pos0[0] + length;//右上角x int y1 = pos0[1] + slidheight/2;//右上角y if ((x>x0) && (x<x1) && (y>y0) && (y<y1))//是否在上面这个矩形中 { target = true; SetRatio(x);//设置百分比 SetPixels();//改变像素信息,重新画图 } return target; } void DrawSlid()//根据像素信息显示 { __glewWindowPos2d(pos0[0], pos0[1]-slidheight/2);//在屏幕相应的位置放置滑动条,pos0[1]-slidheight/2:pos0[1]其实是滑动条半高处的y,所以还需要减半个高才是左下角的y glDrawPixels(length, slidheight, GL_RGBA, GL_UNSIGNED_BYTE, this->pixels); } };
两种策略:
1.只使用滑动条的百分比,具体数值需要通过百分比自己在外部计算
声明:slidBar test0;
初始化:
GLdouble pos[2] = { 20, 40 };//在屏幕中的位置.屏幕坐标原点设定为左下角
test0.Init(pos, rat, 200);//这里的rat是初始状态滑动条的百分比,200代表滑动条是200像素长度
2.直接在slidbar中设置需要控制的数值的上下范围,并通过slidbar返回当前滑动条所在位置的值.
这两种策略在上面这个类中都有实现.
声明:slidBar test0;
初始化:
GLdouble pos[2] = { 20, 40 };//在屏幕中的位置.屏幕坐标原点设定为左下角
GLfloat rat = colors[0] / 1;//colors[0]为测试用的变量,需要用slidbar调整的某个变量
test0.Init_value(pos, rat, 200,0,1);
#include <GL/glew.h> #include <gl/glut.h> #include <stdio.h> #pragma comment(lib,"glew32.lib") int width = 600; int height = 600; int slidheight = 20; GLfloat colors[4] = { 1, 1, 1, 1 }; class SlidBar { 这里是上面贴出来的SlidBar类代码,直接拷贝代替 }; SlidBar test1; void myDisplay(void) { glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glColor4fv(colors); glBegin(GL_TRIANGLES); glVertex2f(-0.6, -0.5); glVertex2f(0.6, -0.5); glVertex2f(0, 0.4); glEnd(); test1.DrawSlid(); glFlush(); } void uiinit() { GLdouble pos[2] = { 20, 40 }; GLfloat rat = colors[0] / 1; //test1.Init(pos, rat, 200); test1.Init_value(pos, rat, 200,0,1); } void init() { uiinit(); } void mouse(int button, int state, int x, int y) { if (state == GLUT_DOWN&&button == GLUT_LEFT_BUTTON) { printf("x:%d,y:%d\n", x, y); if (test1.TouchTest(x, height - y)) { //GLfloat rat = test1.GetRatio(); //colors[0] = 1 * rat; colors[0] = test1.GetValue(); } } glutPostRedisplay(); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(width, height); glutCreateWindow("test"); glEnable(GL_BLEND);//启用这个特性,放置ui背景覆盖实际画面 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); init(); glewInit(); glutDisplayFunc(&myDisplay); glutMouseFunc(mouse); glutMainLoop(); return 0; }