AR多标签识别3

来源:互联网 发布:仓库数据采集器 编辑:程序博客网 时间:2024/06/06 20:10

需求缘起:领导说使用ARtToolKit识别出barCode后,根据barcode的所在的实际位置和barcode相对应的产品尺寸,给产品所在平面画一方框给产品做上标记,并给产品添加相对应的描述信息。

刚开始时领导说只要给识别出的barcode画上方框,并添加描述信息就好了,结果他又改变主意了,好吧, 作为下属,我还能说什么呢,好好改代码才是正事。

因为标签和产品在同一平面,我以为只要在实际中测试中产品的长和宽,并给出标识在产品平面上的具体坐标,标识的宽度,就可以根据他们之间的比例关系计算出产品平面的四个角在照相机坐标里面的具体位置,后来我发现自己太天真了.照片机拍摄(中心投影(透射投影))的虚拟物体和实际的物体尺寸并不成比例关系,我经过测试后瞬间泪奔。

后来发现三维世界中Marker的位置与其对应的二维投影,遵从以下公式:

P=A*[R|T]*M

其中,M表示三维世界中的点,

        [R|T]表示欧氏变换,是一个3*4矩阵

      A表示相机参数矩阵,存放相机内部参数

    P表示M在二维空间的投影,是一个二维点.

受到该公式的启发,我找到了在ARToolKit中将实际坐标转为屏幕坐标的代码,并学会了使用,顺利完成了领导交代的任务,顿时觉得心情舒畅啊.

下面说说我具体的做法.

1.在ARToolKit中check_id.c例程给出了如何从marker实际坐标转为相机坐标和屏幕坐标的代码.具体做法是:

   1) 编辑一个文本文件,里面放你所需要识别的标识编号,标识尺寸大小,标识实际的三维坐标转换矩阵.例如,我需要识别AR_MATRIX_CODE_4x4类型的标识99,标识宽度为7mm,并建设其放在实际的三维坐标原点,我新建一个marker_99.dat,并给它添加内容:

#the number of patterns to be recognized
1
#marker 1
99
70.0
1.0000 0.0000 0.0000 0.0000
0.0000 1.0000 0.0000 0.0000
0.0000 0.0000 1.0000 0.0000


2 程序中装载该文件

int patt_names_count = ;
//最大的类型数据
char *patt_names[CHECK_ID_MULTIMARKERS_MAX] = { "Data/multi/marker_99.dat"};//, "E:/MyGitProject/20170220AR/ArToolkit_VS2013/marker.dat"
ARdouble pattRatio = (ARdouble)AR_PATT_RATIO;
AR_MATRIX_CODE_TYPE matrixCodeType = AR_MATRIX_CODE_4x4; //AR_MATRIX_CODE_TYPE_DEFAULT

// Load marker(s).
//装载类型数据
if (!setupMarkers(patt_names_count, (const char **)patt_names, gMultiConfigs, gARHandle, &gARPattHandle)) {
ARLOGe("main(): Unable to set up AR marker(s).\n");
cleanup();
exit(-1);
}


3 使用arglCameraViewRH()函数转到标识所在平面,在该平面上可以根据产品大小的实际尺寸画边框如

    arglCameraViewRH((const ARdouble(*)[4])gMultiConfigs[k]->trans, m, 1.0);
    glLoadMatrixf(m);

    drawRectangleP(-99.0, 107.0, 111.0, 107.0,
-99.0, -190.0, 111.0, -190.0); //画A4纸边框

4 在转到物体所在的三维坐标后,若要计算物体平面某点在相机中的坐标,则开始用gluProject函数进行转换,如:

  if (gluProject(-80, 50, 0, m, p, gViewport, &winX, &winY, &winZ) == GL_TRUE)
{

MX[k] = winX; MY[k] = winY;
}

   

理清坐标关系后,根据领导需求而改进的ARToolKit 多标签识别代码主要如下:

// ============================================================================
// Includes
// ============================================================================


#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#  define snprintf _snprintf
#endif
#include <stdlib.h> // malloc(), free()
#ifdef __APPLE__
#  include <GLUT/glut.h>
#else
#  include <GL/glut.h>
#endif
#include <AR/config.h>
#include <AR/video.h>
#include <AR/param.h> // arParamDisp()
#include <AR/ar.h>
#include <AR/gsub_lite.h>
#include <AR/arMulti.h>


#include "GLFont.h"
#include "BasicInfo.h"
#include "mathutil.h"


// ============================================================================
// Constants
// ============================================================================


#define VIEW_DISTANCE_MIN 1.0// Objects closer to the camera than this will not be displayed.
#define VIEW_DISTANCE_MAX 10000.0// Objects further away from the camera than this will not be displayed.




/*
"Marker OK.",
"Pattern extraction failed.",
"Generic error during matching phase.",
"Insufficient contrast during matching.",
"Barcode matching could not find correct barcode locator pattern.",
"Barcode matching error detection/correction found unrecoverable error.",
"Matching confidence cutoff value not reached.",
"Maximum allowable pose error exceeded.",
"Multi-marker pose error value exceeded.",
"Rejected frequently misrecognised matrix marker."
*/
// ============================================================================
// Global variables
// ============================================================================


static int windowed = TRUE;                     // Use windowed (TRUE) or fullscreen mode (FALSE) on launch.
static int windowWidth = 640; // Initial window width, also updated during program execution.
static int windowHeight = 480;                  // Initial window height, also updated during program execution.
static int windowDepth = 32; // Fullscreen mode bit depth.
static int windowRefresh = 0; // Fullscreen mode refresh rate. Set to 0 to use default rate.


// Image acquisition.
static ARUint8 *gARTImage = NULL;
static int          gARTImageSavePlease = FALSE;  //是否保存图片


// Marker detection.
static ARHandle *gARHandle = NULL;   //标识检测
static ARPattHandle *gARPattHandle = NULL;
static long gCallCountMarkerDetect = 0;
static int          gPattSize = AR_PATT_SIZE1;  //标识检测
static int          gPattCountMax = AR_PATT_NUM_MAX;


// Transformation matrix retrieval.
static AR3DHandle *gAR3DHandle = NULL;  //3维处理矩阵
static int          gRobustFlag = TRUE;
#define CHECK_ID_MULTIMARKERS_MAX 16
static int gMultiConfigCount = 0;
static ARMultiMarkerInfoT *gMultiConfigs[CHECK_ID_MULTIMARKERS_MAX] = { NULL };
static ARdouble gMultiErrs[CHECK_ID_MULTIMARKERS_MAX];


// Drawing.
static ARParamLT *gCparamLT = NULL;   //画图函数
static ARGL_CONTEXT_SETTINGS_REF gArglSettings = NULL;
static GLint gViewport[4];


// ============================================================================
// Function prototypes.
// ============================================================================


static int setupCamera(const char *cparam_name, char *vconf, ARParamLT **cparamLT_p, ARHandle **arhandle, AR3DHandle **ar3dhandle);
static int setupMarkers(const int patt_count, const char *patt_names[], ARMultiMarkerInfoT *multiConfigs[], ARHandle *arhandle, ARPattHandle **pattHandle_p);
static void cleanup(void);
static void Visibility(int visible);
static void Reshape(int w, int h);
static void Display(void);
static void print(const char *text, const float x, const float y, int calculateXFromRightEdge, int calculateYFromTopEdge);  //计算屏幕中点的正确距离
static void drawRectangleP(float topLeftX, float topLeftY, float topRightX, float topRightY,
float bottomLeftX, float bottomLeftY, float bottomRightX, float bottomRightY);
// ============================================================================
// Functions
// ============================================================================


int main(int argc, char** argv)
{
char glutGamemode[32];
char *cpara = NULL;
//相机参数
char cparaDefault[] = "Data/camera_para.dat";  //相机参数文件
char *vconf = NULL;
int patt_names_count = 2;
//最大的类型数据
char *patt_names[CHECK_ID_MULTIMARKERS_MAX] = { "Data/multi/marker_99.dat", "Data/multi/marker_5.dat", "E:/MyGitProject/20170220AR/matlabAR/marker.dat" };//, "E:/MyGitProject/20170220AR/ArToolkit_VS2013/marker.dat"
ARdouble pattRatio = (ARdouble)AR_PATT_RATIO;
AR_MATRIX_CODE_TYPE matrixCodeType = AR_MATRIX_CODE_4x4; //AR_MATRIX_CODE_TYPE_DEFAULT
int labelingMode = AR_DEFAULT_LABELING_MODE; //AR默认的标签形式
int patternDetectionMode = AR_DEFAULT_PATTERN_DETECTION_MODE;
int i, gotTwoPartOption;
float tempF; //浮点数暂存型
int tempI; //整数暂存型
//
// Library inits.
//
glutInit(&argc, argv); //glut初始化
//
// Video setup.
//
//摄像头配置
if (!cpara) cpara = cparaDefault;
if (!setupCamera(cpara, vconf, &gCparamLT, &gARHandle, &gAR3DHandle)) {
ARLOGe("main(): Unable to set up AR camera.\n");
exit(-1);
}
//
// AR init.
//
//设置需要识别的标签类型
arSetPatternDetectionMode(gARHandle, patternDetectionMode);
//设置标签模式
arSetLabelingMode(gARHandle, labelingMode);
//设置类型标记比例
arSetPattRatio(gARHandle, pattRatio);
//设置需要检测的二维码类型
arSetMatrixCodeType(gARHandle, matrixCodeType);


//
// Graphics setup.
//


// Set up GL context(s) for OpenGL to draw into.
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
//设置opengl的显示环境
if (!windowed) {
if (windowRefresh) sprintf(glutGamemode, "%ix%i:%i@%i", windowWidth, windowHeight, windowDepth, windowRefresh);
else sprintf(glutGamemode, "%ix%i:%i", windowWidth, windowHeight, windowDepth);
glutGameModeString(glutGamemode);
glutEnterGameMode();
}
else {
glutInitWindowSize(gCparamLT->param.xsize, gCparamLT->param.ysize);
glutCreateWindow(argv[0]);
}


// Setup ARgsub_lite library for current OpenGL context.
if ((gArglSettings = arglSetupForCurrentContext(&(gCparamLT->param), arVideoGetPixelFormat())) == NULL) {
ARLOGe("main(): arglSetupForCurrentContext() returned error.\n");
cleanup();
exit(-1);
}
arglSetupDebugMode(gArglSettings, gARHandle);
arUtilTimerReset();


// Load marker(s).
//装载类型数据
if (!setupMarkers(patt_names_count, (const char **)patt_names, gMultiConfigs, gARHandle, &gARPattHandle)) {
ARLOGe("main(): Unable to set up AR marker(s).\n");
cleanup();
exit(-1);
}


gMultiConfigCount = patt_names_count;
// Register GLUT event-handling callbacks.
// NB: mainLoop() is registered by Visibility.
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);
glutVisibilityFunc(Visibility);
glutMainLoop();


return (0);
}






//设置相机参数
static int setupCamera(const char *cparam_name, char *vconf, ARParamLT **cparamLT_p, ARHandle **arhandle, AR3DHandle **ar3dhandle)
{
ARParam cparam;
int xsize, ysize;
AR_PIXEL_FORMAT pixFormat;


// Open the video path.
if (arVideoOpen(vconf) < 0) {
ARLOGe("setupCamera(): Unable to open connection to camera.\n");
return (FALSE);
}




// Find the size of the window. 
if (arVideoGetSize(&xsize, &ysize) < 0) {
ARLOGe("setupCamera(): Unable to determine camera frame size.\n");
arVideoClose();
return (FALSE);
}
ARLOGi("Camera image size (x,y) = (%d,%d)\n", xsize, ysize);


// Get the format in which the camera is returning pixels.
pixFormat = arVideoGetPixelFormat();
if (pixFormat == AR_PIXEL_FORMAT_INVALID) {
ARLOGe("setupCamera(): Camera is using unsupported pixel format.\n");
arVideoClose();
return (FALSE);
}


// Load the camera parameters, resize for the window and init.
if (arParamLoad(cparam_name, 1, &cparam) < 0) {
ARLOGe("setupCamera(): Error loading parameter file %s for camera.\n", cparam_name);
arVideoClose();
return (FALSE);
}
if (cparam.xsize != xsize || cparam.ysize != ysize) {
ARLOGw("*** Camera Parameter resized from %d, %d. ***\n", cparam.xsize, cparam.ysize);
arParamChangeSize(&cparam, xsize, ysize, &cparam); //改变相机参数
}
#ifdef DEBUG
ARLOG("*** Camera Parameter ***\n");
arParamDisp(&cparam);
#endif
if ((*cparamLT_p = arParamLTCreate(&cparam, AR_PARAM_LT_DEFAULT_OFFSET)) == NULL) {
ARLOGe("setupCamera(): Error: arParamLTCreate.\n");
return (FALSE);
}


if ((*arhandle = arCreateHandle(*cparamLT_p)) == NULL) {
ARLOGe("setupCamera(): Error: arCreateHandle.\n");
return (FALSE);
}
if (arSetPixelFormat(*arhandle, pixFormat) < 0) {
ARLOGe("setupCamera(): Error: arSetPixelFormat.\n");
return (FALSE);
}
if (arSetDebugMode(*arhandle, AR_DEBUG_DISABLE) < 0) {
ARLOGe("setupCamera(): Error: arSetDebugMode.\n");
return (FALSE);
}
if ((*ar3dhandle = ar3DCreateHandle(&cparam)) == NULL) {
ARLOGe("setupCamera(): Error: ar3DCreateHandle.\n");
return (FALSE);
}


if (arVideoCapStart() != 0) {
ARLOGe("setupCamera(): Unable to begin camera data capture.\n");
return (FALSE);
}


return (TRUE);
}


//设置标识 patt_names 标记文件  多配置文件 多标签识别
static int setupMarkers(const int patt_count, const char *patt_names[], ARMultiMarkerInfoT *multiConfigs[], ARHandle *arhandle, ARPattHandle **pattHandle_p)
{
int i;
//如果没有设置类型检测的数量,则检测二维码标识
if (!patt_count) {
// Default behaviour is to default to matrix mode.
*pattHandle_p = NULL;
arSetPatternDetectionMode(arhandle, AR_MATRIX_CODE_DETECTION); // If no markers specified, default to matrix mode.
}
else {
// If marker configs have been specified, attempt to load them.        
int mode = -1, nextMode;
// Need a pattern handle because the config file could specify matrix or template markers.
if ((*pattHandle_p = arPattCreateHandle2(gPattSize, gPattCountMax)) == NULL) {  //gPattCountMax为50个
ARLOGe("setupMarkers(): Error: arPattCreateHandle2.\n");
return (FALSE);
}


for (i = 0; i < patt_count; i++) {


if (!(multiConfigs[i] = arMultiReadConfigFile(patt_names[i], *pattHandle_p))) {
ARLOGe("setupMarkers(): Error reading multimarker config file '%s'.\n", patt_names[i]);
for (i--; i >= 0; i--) {
arMultiFreeConfig(multiConfigs[i]);
}
arPattDeleteHandle(*pattHandle_p);
return (FALSE);
}


if (multiConfigs[i]->patt_type == AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE) {
nextMode = AR_TEMPLATE_MATCHING_COLOR;  //颜色匹配
}
else if (multiConfigs[i]->patt_type == AR_MULTI_PATTERN_DETECTION_MODE_MATRIX) {
nextMode = AR_MATRIX_CODE_DETECTION;   //二维码匹配
}
else { // AR_MULTI_PATTERN_DETECTION_MODE_TEMPLATE_AND_MATRIX or mixed.
nextMode = AR_TEMPLATE_MATCHING_COLOR_AND_MATRIX; //颜色和二维码匹配
}
if (mode == -1) {
mode = nextMode;
}
else if (mode != nextMode) {
mode = AR_TEMPLATE_MATCHING_COLOR_AND_MATRIX;
}
}
arSetPatternDetectionMode(arhandle, mode);


arPattAttach(arhandle, *pattHandle_p);
}


return (TRUE);
}
//清理缓存
static void cleanup(void)
{
int i;


arglCleanup(gArglSettings);
gArglSettings = NULL;


arPattDetach(gARHandle);
for (i = 0; i < gMultiConfigCount; i++) {
arMultiFreeConfig(gMultiConfigs[i]);
}
if (gARPattHandle) arPattDeleteHandle(gARPattHandle);


arVideoCapStop();
arDeleteHandle(gARHandle);
arParamLTFree(&gCparamLT);
arVideoClose();
}


//主循环
static void mainLoop(void)
{
int i;
static int imageNumber = 0;//图片的数量索引
static int ms_prev;
int ms;
float s_elapsed;
ARUint8 *image;


// Find out how long since mainLoop() last ran.
ms = glutGet(GLUT_ELAPSED_TIME); //计算主程序运行时间
s_elapsed = (float)(ms - ms_prev) * 0.001f;
if (s_elapsed < 0.01f) return; // Don't update more often than 100 Hz. 以100Hz的频率对图像进行刷新
ms_prev = ms;


// Grab a video frame. 抓取视频帧
if ((image = arVideoGetImage()) != NULL) {
gARTImage = image;// Save the fetched image.
//如果gARTImageSavePlease为真,则保存图片
if (gARTImageSavePlease) {
char imageNumberText[15];
sprintf(imageNumberText, "image-%04d.jpg", imageNumber++);
//保存图片
if (arVideoSaveImageJPEG(gARHandle->xsize, gARHandle->ysize, gARHandle->arPixelFormat, gARTImage, imageNumberText, 75, 0) < 0) {
ARLOGe("Error saving video image.\n");
}
gARTImageSavePlease = FALSE;
}
gCallCountMarkerDetect++; // Increment ARToolKit FPS counter.


// Detect the markers in the video frame.
//检测标识算法
if (arDetectMarker(gARHandle, gARTImage) < 0) {
exit(-1);
}
//寻找到所有的标识标签


// If  marker config files were specified, evaluate detected patterns against them now.
for (i = 0; i < gMultiConfigCount; i++) {
if (gRobustFlag) gMultiErrs[i] = arGetTransMatMultiSquareRobust(gAR3DHandle, arGetMarker(gARHandle), arGetMarkerNum(gARHandle), gMultiConfigs[i]);
else gMultiErrs[i] = arGetTransMatMultiSquare(gAR3DHandle, arGetMarker(gARHandle), arGetMarkerNum(gARHandle), gMultiConfigs[i]);
//if (gMultiConfigs[i]->prevF != 0) ARLOGe("Found multimarker set %d, err=%0.3f\n", i, gMultiErrs[i]);
}
// Tell GLUT the display has changed.
glutPostRedisplay();
}
}


//
// This function is called on events when the visibility of the
// GLUT window changes (including when it first becomes visible).
//
static void Visibility(int visible)
{
if (visible == GLUT_VISIBLE) {
glutIdleFunc(mainLoop);
}
else {
glutIdleFunc(NULL);
}
}


//
// This function is called when the
// GLUT window is resized.
//
static void Reshape(int w, int h)
{
windowWidth = w;
windowHeight = h;


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gViewport[0] = 0;
gViewport[1] = 0;
gViewport[2] = w;
gViewport[3] = h;
glViewport(0, 0, (GLsizei)w, (GLsizei)h);


// Call through to anyone else who needs to know about window sizing here.
}




//
// This function is called when the window needs redrawing.
// 核心部分 窗口重画需要的核心部分
//
static void Display(void)
{
ARdouble p[16];
ARdouble m[16];
#ifdef ARDOUBLE_IS_FLOAT
GLdouble p0[16];
GLdouble m0[16];
#endif
int i, j, k;
char text[256];  //字符串数组长度
GLdouble winX, winY, winZ;
int showMErr[CHECK_ID_MULTIMARKERS_MAX]; //显示错误
GLdouble MX[CHECK_ID_MULTIMARKERS_MAX];
GLdouble MY[CHECK_ID_MULTIMARKERS_MAX];
int pattDetectMode;  //类型检测模式
AR_MATRIX_CODE_TYPE matrixCodeType; //二维码类型
// Select correct buffer for this context.
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the buffers for new frame.
//将图像设置纹理显示
arglPixelBufferDataUpload(gArglSettings, gARTImage);
arglDispImage(gArglSettings);


if (gMultiConfigCount) {
arglCameraFrustumRH(&(gCparamLT->param), VIEW_DISTANCE_MIN, VIEW_DISTANCE_MAX, p);
glMatrixMode(GL_PROJECTION); //GL映射
#ifdef ARDOUBLE_IS_FLOAT
glLoadMatrixf(p);
#else
glLoadMatrixd(p);//长度为16的double数组
#endif
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
// If we have multi-configs, show their origin onscreen.
for (k = 0; k < gMultiConfigCount; k++) {
showMErr[k] = FALSE;
if (gMultiConfigs[k]->prevF != 0) { //预测到相对应的标签
arglCameraViewRH((const ARdouble(*)[4])gMultiConfigs[k]->trans, m, 1.0);
#ifdef ARDOUBLE_IS_FLOAT
glLoadMatrixf(m);
#else
glLoadMatrixd(m);
#endif

drawRectangleP(-99.0, 107.0, 111.0, 107.0,
-99.0, -190.0, 111.0, -190.0);
#ifdef ARDOUBLE_IS_FLOAT
for (i = 0; i < 16; i++) m0[i] = (GLdouble)m[i];
for (i = 0; i < 16; i++) p0[i] = (GLdouble)p[i];
if (gluProject(0, 0, 0, m0, p0, gViewport, &winX, &winY, &winZ) == GL_TRUE)
#else           //将物体坐标转为窗口坐标
if (gluProject(-80, 50, 0, m, p, gViewport, &winX, &winY, &winZ) == GL_TRUE)
#endif
{
showMErr[k] = TRUE;
MX[k] = winX; MY[k] = winY;
}
}


} // for k
}


// Any 2D overlays go here.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();


glOrtho(0, (GLdouble)windowWidth, 0, (GLdouble)windowHeight, -1.0, 1.0); //正射投影 创建一个平行视景体 left right bottom top near far


glMatrixMode(GL_MODELVIEW);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);


arGetPatternDetectionMode(gARHandle, &pattDetectMode);
arGetMatrixCodeType(gARHandle, &matrixCodeType);
//labelOnePoint();
//labelFourPoint();
//检测到配置文件中给定的标识,则显示相关信息
glLoadIdentity();
for (k = 0; k < gMultiConfigCount; k++){
if (gMultiConfigs[k]->prevF != 0){
if (gMultiConfigs[k]->marker->patt_id == 99){
snprintf(text, sizeof(text), " %s", getCabinetInfo());//); //温湿度传感器机柜
}
else if (gMultiConfigs[k]->marker->patt_id == 5){
snprintf(text, sizeof(text), " %s", getPowerDistribInfo());
//dispContent = getHotChannelInfo();
}
else if (gMultiConfigs[k]->marker->patt_id == 10){
snprintf(text, sizeof(text), " %s", getColdChannelInfo());
//dispContent = getColdChannelInfo();
}
else if (gMultiConfigs[k]->marker->patt_id == 512){
snprintf(text, sizeof(text), " %s", getCabinetInfo());
//dispContent = getCabinetInfo();
}
else if (gMultiConfigs[k]->marker->patt_id == 1011){
snprintf(text, sizeof(text), " %s", getPDUInfo());
//dispContent = getPDUInfo();
}
else if (gMultiConfigs[k]->marker->patt_id == 2047){
snprintf(text, sizeof(text), " %s", getShortColdChannelInfo());
//dispContent = getShortColdChannelInfo();
}
else{
snprintf(text, sizeof(text), " 标识未定义");
//dispContent = "标识未定义";
}


/*根据字符串里面是否包含\n对字符串进行行分割并进行多行显示*/
char delims[] = "\n";
char *lineStr = NULL;
//将字符串常量转为字符串变量
char *dispContentStr = (char *)malloc(sizeof(char)*(strlen(text) + 1));
glColor3ub(0, 255, 0);
if (dispContentStr != NULL){
strcpy(dispContentStr, text);
lineStr = strtok(dispContentStr, delims); //strtok中的char *Str为非常量指针,而非常量指针可以隐式转换为常量指针,由于strtok会对指针指向值进行修改,
int lineCnt = 0;
while (lineStr != NULL){        //所以当Str为常量指针时,编译时没有问题,但运行时会报错
//打印字母或者汉字
float topLeftVertexPosX =MX[k]; //左上角坐标x
float topLeftVertexPosY =MY[k]; //左上角坐标y
print(lineStr, topLeftVertexPosX, topLeftVertexPosY - lineCnt*16.0f, 0, 0);
lineStr = strtok(NULL, delims);
lineCnt++;
}
}
else{
printf("mallocerror\n");
exit(-1);
}


free(dispContentStr);
dispContentStr = NULL;
}


}


glutSwapBuffers();
}


static void drawRectangleP(float topLeftX,float topLeftY,float topRightX,float topRightY,
float bottomLeftX,float bottomLeftY,float bottomRightX,float bottomRightY){
GLfloat vertices[5][3] = {
{ topLeftX, topLeftY, 0.0f }, { topRightX, topRightY, 0.0f },
{ bottomRightX, bottomRightY, 0.0f }, { bottomLeftX, bottomLeftY, 0.0f },
{ topLeftX, topLeftY, 0.0f }
};
//绿色
GLubyte colours[5][4] = {
{ 0, 255, 0, 255 }, { 0, 255, 0, 255 },
{ 0, 255, 0, 255 }, { 0, 255, 0, 255 },
{ 0, 255, 0, 255 }
};


glVertexPointer(3, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colours);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glLineWidth(2.0f);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDrawArrays(GL_LINE_STRIP, 0, 5);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);


}


//
// The following functions provide the onscreen help text and mode info.
//


static void print(const char *text, const float x, const float y, int calculateXFromRightEdge, int calculateYFromTopEdge)
{
int i, len;
GLfloat x0, y0;


if (!text) return;


if (calculateXFromRightEdge) {
x0 = windowWidth - x - (float)glutBitmapLength(GLUT_BITMAP_HELVETICA_10, (const unsigned char *)text);
}
else {
x0 = x;
}
if (calculateYFromTopEdge) {
y0 = windowHeight - y - 10.0f;
}
else {
y0 = y;
}
glRasterPos2f(x0, y0);
drawCNString(text);
}


运行效果如下:





程序代码见:http://download.csdn.net/detail/huangzhichang13/9844895





原创粉丝点击