在ARToolKit5的基础上,对check_id.c文件进行修改,对识别到的标签添加相对应的文字显示信息。代码有两个c文件组成keydakMAR.c和BasicInfo.c
keydakMAR.c的代码如下:
// ============================================================================
// 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"
// ============================================================================
// 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.
typedef struct _cutoffPhaseColours {
int cutoffPhase;
GLubyte colour[3];
} cutoffPhaseColours_t;
//设置的截止相位颜色有10种
const cutoffPhaseColours_t cutoffPhaseColours[AR_MARKER_INFO_CUTOFF_PHASE_DESCRIPTION_COUNT] = {
{ AR_MARKER_INFO_CUTOFF_PHASE_NONE, { 0xff, 0x0, 0x0 } }, // Red. 红色
{ AR_MARKER_INFO_CUTOFF_PHASE_PATTERN_EXTRACTION, { 0x95, 0xd6, 0xf6 } }, // Light blue. 浅蓝
{ AR_MARKER_INFO_CUTOFF_PHASE_MATCH_GENERIC, { 0x0, 0x0, 0xff } }, // Blue. 蓝
{ AR_MARKER_INFO_CUTOFF_PHASE_MATCH_CONTRAST, { 0x99, 0x66, 0x33 } }, // Brown. 棕色
{ AR_MARKER_INFO_CUTOFF_PHASE_MATCH_BARCODE_NOT_FOUND, { 0x7f, 0x0, 0x7f } }, // Purple.紫色
{ AR_MARKER_INFO_CUTOFF_PHASE_MATCH_BARCODE_EDC_FAIL, { 0xff, 0x0, 0xff } }, // Magenta. 品红
{ AR_MARKER_INFO_CUTOFF_PHASE_MATCH_CONFIDENCE, { 0x0, 0xff, 0x0 } }, // Green. 绿色
{ AR_MARKER_INFO_CUTOFF_PHASE_POSE_ERROR, { 0xff, 0x7f, 0x0 } }, // Orange. 橙色
{ AR_MARKER_INFO_CUTOFF_PHASE_POSE_ERROR_MULTI, { 0xff, 0xff, 0x0 } }, // Yellow. 黄色
{ AR_MARKER_INFO_CUTOFF_PHASE_HEURISTIC_TROUBLESOME_MATRIX_CODES, { 0xc6, 0xdc, 0x6a } }, // Khaki. 卡其色,土黄色
};
// ============================================================================
// 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); //计算屏幕中点的正确距离
// ============================================================================
// Functions
// ============================================================================
int main(int argc, char** argv)
{
char glutGamemode[32];
char *cpara = NULL;
//相机参数
char cparaDefault[] = "C:/Program Files (x86)/ARToolKit5/bin/Data/camera_para.dat"; //相机参数文件
char *vconf = NULL;
int patt_names_count = 0;
//最大的类型数据
char *patt_names[CHECK_ID_MULTIMARKERS_MAX] = { NULL };
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;
GLfloat w, bw, bh, vertices[6][2]; //六个顶点
GLubyte pixels[300];
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
#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(0, 0, 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); //正交
glMatrixMode(GL_MODELVIEW);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
arGetPatternDetectionMode(gARHandle, &pattDetectMode);
arGetMatrixCodeType(gARHandle, &matrixCodeType);
// For all markers, draw onscreen position.
// Colour based on cutoffPhase.
glLoadIdentity();
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glLineWidth(2.0f);
for (j = 0; j < gARHandle->marker_num; j++) {
printf("一共有%d个标识\n", gARHandle->marker_num);
//Sets the current color from an already existing array of color values.
//根据截止相位来设置颜色
//glColor3ubv(cutoffPhaseColours[gARHandle->markerInfo[j].cutoffPhase].colour);
if (gARHandle->markerInfo->cf < 0.6)
continue;
//要是只设置绿色
glColor3ubv(cutoffPhaseColours[6].colour);
for (i = 0; i < 5; i++) {
int dir = gARHandle->markerInfo[j].dir;
vertices[i][0] = (float)gARHandle->markerInfo[j].vertex[(i + 4 - dir) % 4][0] * (float)windowWidth / (float)gARHandle->xsize;
vertices[i][1] = ((float)gARHandle->ysize - (float)gARHandle->markerInfo[j].vertex[(i + 4 - dir) % 4][1]) * (float)windowHeight / (float)gARHandle->ysize;
}
vertices[i][0] = (float)gARHandle->markerInfo[j].pos[0] * (float)windowWidth / (float)gARHandle->xsize;
vertices[i][1] = ((float)gARHandle->ysize - (float)gARHandle->markerInfo[j].pos[1]) * (float)windowHeight / (float)gARHandle->ysize;
glDrawArrays(GL_LINE_STRIP, 0, 5);
// For markers that have been identified, draw the ID number.
if (gARHandle->markerInfo[j].id >= 0) {
glColor3ub(0, 255, 0);
if (gARHandle->markerInfo[j].id == 5){
snprintf(text, sizeof(text), " %s",getAirInfo());
}
else if (gARHandle->markerInfo[j].id == 10){
snprintf(text, sizeof(text)," %s", getHotChannelInfo());
//dispContent = getHotChannelInfo();
}
else if (gARHandle->markerInfo[j].id == 99){
snprintf(text, sizeof(text)," %s", getColdChannelInfo());
//dispContent = getColdChannelInfo();
}
else if (gARHandle->markerInfo[j].id == 512){
snprintf(text, sizeof(text)," %s", getCabinetInfo());
//dispContent = getCabinetInfo();
}
else if (gARHandle->markerInfo[j].id==1011){
snprintf(text, sizeof(text)," %s", getPDUInfo());
//dispContent = getPDUInfo();
}
else if (gARHandle->markerInfo[j].id==2047){
snprintf(text,sizeof(text)," %s",getShortColdChannelInfo());
//dispContent = getShortColdChannelInfo();
}
else{
snprintf(text, sizeof(text), " 标识%d未定义", gARHandle->markerInfo[j].id);
//dispContent = "标识未定义";
}
/*根据字符串里面是否包含\n对字符串进行行分割并进行多行显示*/
char delims[] = "\n";
char *lineStr = NULL;
//将字符串常量转为字符串变量
char *dispContentStr = (char *)malloc(sizeof(char)*(strlen(text) + 1));
if (dispContentStr != NULL){
strcpy(dispContentStr, text);
lineStr = strtok(dispContentStr, delims); //strtok中的char *Str为非常量指针,而非常量指针可以隐式转换为常量指针,由于strtok会对指针指向值进行修改,
int lineCnt = 0;
while (lineStr != NULL){ //所以当Str为常量指针时,编译时没有问题,但运行时会报错
//打印字母或者汉字
float topLeftVertexPosX = (float)gARHandle->markerInfo[j].vertex[(4 - gARHandle->markerInfo[j].dir) % 4][0];
float topLeftVertexPosY = (float)gARHandle->markerInfo[j].vertex[(4 - gARHandle->markerInfo[j].dir) % 4][1];
print(lineStr, topLeftVertexPosX * (float)windowWidth / (float)gARHandle->xsize+12.0f, ((float)gARHandle->ysize - topLeftVertexPosY) * (float)windowHeight / (float)gARHandle->ysize - lineCnt*16.0f-12.0f, 0, 0);
lineStr = strtok(NULL, delims);
lineCnt++;
}
}
else{
printf("mallocerror\n");
exit(-1);
}
free(dispContentStr);
dispContentStr = NULL;
//打印字母或者汉字
//print(text, (float)gARHandle->markerInfo[j].pos[0] * (float)windowWidth / (float)gARHandle->xsize, ((float)gARHandle->ysize - (float)gARHandle->markerInfo[j].pos[1]) * (float)windowHeight / (float)gARHandle->ysize, 0, 0);
}
}
glDisableClientState(GL_VERTEX_ARRAY);
glutSwapBuffers();
}
//
// 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);
}
GLFont3D.c的代码如下
//主要在opengl下画中文字符 2D或者3D
#include "GLFont.h"
void c3dtext(LPCTSTR str, HFONT hFont, float z)
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
Printfc3d(TEXT(str), hFont, z);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
}
void Printfc3d(LPCTSTR strText, HFONT hFont, float z)
{
HDC hdc = wglGetCurrentDC();
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
UCHAR * pChar = (UCHAR*)strText/*.GetBuffer(strText.GetLength())*/;
int nListNum;
DWORD dwChar;
GLYPHMETRICSFLOAT pgmf[1];
glPushMatrix();
float m_dXOffset = -1.0;
float m_dYOffset = 1.0;
float m_dZOffset = 2.0;
float m_dXScale = 0.10;
float m_dYScale = 0.10;
float m_dZScale = 0.10;
float m_dXRotate = -90.0;
float m_dYRotate = 0.0;
float m_dZRotate = 0.0;
glTranslatef(m_dXOffset, m_dYOffset, m_dZOffset);
//glScalef(1000.0, 1000.0, 10000.0);
//Scale
glScaled(m_dXScale, m_dYScale, m_dZScale);
//Rotate around X-axis
glRotated(m_dXRotate, 1.0, 0.0, 0.0);
//Rotate around Y-axis
glRotated(m_dYRotate, 0.0, 1.0, 0.0);
//Rotate around Z-axis
glRotated(m_dZRotate, 0.0, 0.0, 1.0);
glColor3f(0.0, 1.0, 1.0);
for (int i = 0; i < _tcslen(strText)/*strText.GetLength()*/; i++)
{
if (IsDBCSLeadByte((BYTE)pChar[i]))
{
dwChar = (DWORD)((pChar[i] << 8) | pChar[i + 1]);
i++;
}
else dwChar = pChar[i];
nListNum = glGenLists(1);
wglUseFontOutlines(hdc,
dwChar,
1,
nListNum,
0.0f,
z,
WGL_FONT_POLYGONS, //WGL_FONT_POLYGONS
pgmf
);
glCallList(nListNum);
glDeleteLists(nListNum, 1);
}
//restore the original angle around Z-axis
glRotated(-1.0f * m_dZRotate, 0.0, 0.0, 1.0);
//restore the original angle around Y-axis
glRotated(-1.0f * m_dYRotate, 0.0, 1.0, 0.0);
//restore the original scale
glScaled(1.0 / m_dXScale, 1.0 / m_dYScale, 1.0 / m_dZScale);
//restore the original angle around X-axis
glRotated(-1.0f * m_dXRotate, 1.0, 0.0, 0.0);
glTranslated(-m_dXOffset, -m_dYOffset, -m_dZOffset);
glPopMatrix();
//strText.ReleaseBuffer();
SelectObject(hdc, hOldFont);
}
void draw3dtextWithCloseLight(LPCTSTR str, HFONT hFont, float cDepth, float dXoffset, float dYoffset, float dZoffset, float dXscale, float dYscale, float dZscale,
float dXrotate, float dYrotate, float dZrotate)
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
draw3dtextIgnoreLight(TEXT(str), hFont, cDepth, dXoffset, dYoffset, dZoffset, dXscale, dYscale, dZscale, dXrotate, dYrotate, dZrotate);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
}
void draw3dtextIgnoreLight(LPCTSTR strText, HFONT hFont, float cDepth, float dXoffset, float dYoffset, float dZoffset, float dXscale, float dYscale, float dZscale,
float dXrotate, float dYrotate, float dZrotate)
{
HDC hdc = wglGetCurrentDC();
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
UCHAR * pChar = (UCHAR*)strText/*.GetBuffer(strText.GetLength())*/;
int nListNum;
DWORD dwChar;
GLYPHMETRICSFLOAT pgmf[1];
glPushMatrix();
float m_dXOffset = dXoffset;
float m_dYOffset = dYoffset;
float m_dZOffset = dZoffset;
float m_dXScale = dXscale;
float m_dYScale = dYscale;
float m_dZScale = dZscale;
float m_dXRotate = dXrotate;
float m_dYRotate = dYrotate;
float m_dZRotate = dZrotate;
glTranslatef(m_dXOffset, m_dYOffset, m_dZOffset);
//Scale
glScaled(m_dXScale, m_dYScale, m_dZScale);
//Rotate around X-axis
glRotated(m_dXRotate, 1.0, 0.0, 0.0);
//Rotate around Y-axis
glRotated(m_dYRotate, 0.0, 1.0, 0.0);
//Rotate around Z-axis
glRotated(m_dZRotate, 0.0, 0.0, 1.0);
glColor4f(0.0, 1.0, 0.0,0.5); //绿色 半透明
for (int i = 0; i < _tcslen(strText)/*strText.GetLength()*/; i++)
{
if (IsDBCSLeadByte((BYTE)pChar[i]))
{
dwChar = (DWORD)((pChar[i] << 8) | pChar[i + 1]);
i++;
}
else dwChar = pChar[i];
nListNum = glGenLists(1);
/*可以用于创建三维的字体
hdc 字体的设备上下文
first 要转换为显示列表的第一个字符
count 要转化为显示列表字符的个数
listBase 显示列表的基数
deviation 指定与实际轮廓的最大偏移量
extrusion 指定字体在z轴负方向的值。通过修改这个值就可以显示3D字符,字体的深度
format 指定显示列表线段或多边形
lpgmf 接受字符的地址,用于保存创建字体的一些信息,通常其指向的空间长度是不小于创建的显示列表数的
*/
wglUseFontOutlines(hdc,
dwChar,
1,
nListNum,
0.0f,
cDepth,
WGL_FONT_POLYGONS, //WGL_FONT_POLYGONS
pgmf
);
glCallList(nListNum);
glDeleteLists(nListNum, 1);
}
//restore the original angle around Z-axis
glRotated(-1.0f * m_dZRotate, 0.0, 0.0, 1.0);
//restore the original angle around Y-axis
glRotated(-1.0f * m_dYRotate, 0.0, 1.0, 0.0);
//restore the original angle around X-axis
glRotated(-1.0f * m_dXRotate, 1.0, 0.0, 0.0);
//restore the original scale
glScaled(1.0 / m_dXScale, 1.0 / m_dYScale, 1.0 / m_dZScale);
glTranslated(-m_dXOffset, -m_dYOffset, -m_dZOffset);
glPopMatrix();
//strText.ReleaseBuffer();
SelectObject(hdc, hOldFont);
}
//检测换行符,如果有换行符,则把字符分行
void draw3dMultiLineText(){
}
//画二维中文字体
void drawCNString(const char* str){
int len, i;
wchar_t* wstring;
HDC hDC = wglGetCurrentDC();
GLuint list = glGenLists(1);
//计算字符的个数
//如果是双字节字符(比如中文字符),两个字节才算一个字符
len = 0;
for (i = 0; str[i] != '\0'; ++i){
if (IsDBCSLeadByte(str[i]))
++i;
++len;
}
//将混合字符转为宽字符
wstring = (wchar_t*)malloc((len + 1)*sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring,len);
wstring[len] = L'\0';
//逐个输出字符
for (i = 0; i < len; ++i){
wglUseFontBitmapsW(hDC,wstring[i],1,list);
glCallList(list);
}
//回收所有临时资源
free(wstring);
glDeleteLists(list, 1);
}
BasicInfo.c的代码如下:
/*
动态获取获取各种设备信息
*/
#include "BasicInfo.h"
/*
获取空调信息
*/
char *getAirInfo(){
//给空调信息分配100个字节
char *airInfoStr=(char *)malloc(sizeof(char)*100);
if (airInfoStr != NULL){
strcpy(airInfoStr,"名称:空调\n温度:");
char buf[10];
float temperature = generateTemp(10, 40);
//snprintf(buf, sizeof(buf)-1, "%5.1f ℃\n", temperature);
sprintf(buf,"%5.1f ℃\n", temperature);
strcat(airInfoStr, buf);
return airInfoStr;
}else{
printf("airInfoStr 内存分配失败\n");
exit(-1);
}
}
/*
获取热通道信息
*/
char *getHotChannelInfo(){
char *channelInfoStr;
channelInfoStr = (char *)malloc(sizeof(char)* 200);
if (channelInfoStr != NULL){
int idleLocationCnt = generateInteger(10, 40);
sprintf(channelInfoStr, "名称:热通道\n空闲位置数量 : %d \n", idleLocationCnt);
return channelInfoStr;
}
else{
printf("channelInfoStr 内存分配失败\n");
exit(-1);
}
}
/*
获取冷通道消息
*/
char *getColdChannelInfo(){
char *channelInfoStr;
channelInfoStr = (char *)malloc(sizeof(char)* 200);
if (channelInfoStr != NULL){
//strcpy(channelInfoStr, "名称:冷通道\n空闲位置数量:");
//char buf[50];
int idleLocationCnt = generateInteger(0, 40);
sprintf(channelInfoStr, "名称:冷通道\n空闲位置数量:%3d个\n", idleLocationCnt);
return channelInfoStr;
}
else{
printf("channelInfoStr 内存分配失败\n");
exit(-1);
}
}
/*
获取机柜信息
*/
char *getCabinetInfo(){
char *cabinetInfoStr=(char *)malloc(sizeof(char)* 350);
//cabinetInfoStr = (char *)malloc(sizeof(char)* 350);
if (cabinetInfoStr != NULL){
strcpy(cabinetInfoStr,"名称:机柜\n");
char buf[300];
float frontDoorUpTemp = generateTemp(20, 40);
float frontDoorBottomTemp = generateTemp(20,40);
float backDoorUpTemp = generateTemp(20, 40);
float backDoorBottomTemp = generateTemp(20,40);
int frontDoorUpHumidity = generateInteger(50, 70);
int frontDoorBottomHumidity = generateInteger(50, 70);
int backDoorUpHumidity = generateInteger(50, 70);
int backDoorBottomHUmidity = generateInteger(50, 70);
/*
snprintf(buf,sizeof(buf)-1,"前门上部温度:%5.1f ℃\n\
前门上部湿度:%d\%\n\
前门底部温度:%5.1f ℃\n\
前门底部湿度:%d %%\n\
后门上部温度:%5.1f ℃\n\
后门上部湿度:%d %%\n\
后门底部温度:%5.1f ℃\n\
后门底部湿度:%d %%\n",frontDoorUpTemp,frontDoorUpHumidity,frontDoorBottomTemp,frontDoorBottomHumidity,
backDoorUpTemp,backDoorUpHumidity,backDoorBottomTemp,backDoorBottomHUmidity);
*/
sprintf(buf, "前门上部温度:%5.1f℃\n前门上部湿度:%d%%\n前门底部温度:%5.1f℃\n前门底部湿度:%d%%\n后门上部温度:%5.1f℃\n后门上部湿度:%d%%\n后门底部温度:%5.1f℃\n\
后门底部湿度:%d %%\n", frontDoorUpTemp, frontDoorUpHumidity, frontDoorBottomTemp, frontDoorBottomHumidity,
backDoorUpTemp, backDoorUpHumidity, backDoorBottomTemp, backDoorBottomHUmidity);
strcat(cabinetInfoStr,buf);
return cabinetInfoStr;
}
else{
printf("cabinetInfoStr 分配失败\n");
exit(-1);
}
}
/*
获取pdu信息
*/
char* getPDUInfo(){
char *pduInfoStr;
pduInfoStr = (char*)malloc(sizeof(char)* 300);
if (pduInfoStr != NULL){
strcpy(pduInfoStr,"名称:PDU\n");
float temp = generateTemp(20, 40);
int voltage = generateInteger(210, 240);
int eCurrent = generateInteger(0, 15);
int humidity = generateInteger(50, 70);
int activePower = generateInteger(70, 100);
char buf[150];
/*snprintf(buf,sizeof(buf)-1,"温度:%5.1f℃\n\
湿度:%d%%\n\
电压:%dV\n\
电流:%dA\n\
有功功率:%dW",temp,humidity,voltage,eCurrent,activePower);*/
sprintf(buf, "温度:%5.1f℃\n湿度:%d%%\n电压:%dV\n电流:%dA\n有功功率:%dW", temp, humidity, voltage, eCurrent, activePower);
strcat(pduInfoStr,buf);
return pduInfoStr;
}else{
printf("pduInfoStr 内存分配失败\n");
exit(-1);
}
}
char *getShortColdChannelInfo(){
char *shortColdChannelInfo;
shortColdChannelInfo = (char*)malloc(sizeof(char)* 300);
if (shortColdChannelInfo != NULL){
strcpy(shortColdChannelInfo,"名称:短冷通道\n位置1:机柜B02\n位置2:机柜A04\n\
位置3:布线机柜B\n位置4:机柜A02\n位置5:机柜A01\n位置6:机柜A03位置7:机柜A05\n\
位置8:B列行间空调\n位置9:配电柜\n位置10:A列行间空调\n位置11:布线机柜A\n位置12:UPS柜\n\
位置13:机柜B01\n位置14:机柜B03");
return shortColdChannelInfo;
}
else{
printf("shortColdChannelInfo内存分配失败\n");
exit(-1);
}
}
/*随机产生一个温度值
lowTemperatur 指定最低温度
highTemperature 指定最高温度
*/
float generateTemp(int lowTemperature,int highTemperature){
int range = highTemperature - lowTemperature;
float randF = (rand() % (range * 10)) / 10.0;
return (lowTemperature + randF);
}
/*
随机产生一个整数,用来表示通道里面的空闲数量
lowNum:产生的最小整数
highNum:产生的最大整数
*/
int generateInteger(int lowInt,int highInt){
int range = highInt - lowInt;
int rangeInt = rand()%range;
return lowInt + rangeInt;
}
运行效果如下: