说明:
出于学习目的,自己写了一个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;
}