layer1/Text.cpp (654 lines of code) (raw):

/* A* ------------------------------------------------------------------- B* This file contains source code for the PyMOL computer program C* copyright 1998-2003 by Warren Lyford Delano of DeLano Scientific. D* ------------------------------------------------------------------- E* It is unlawful to modify or remove this copyright notice. F* ------------------------------------------------------------------- G* Please see the accompanying LICENSE file for further information. H* --------------------------------------------------\----------------- I* Additional authors of this source file include: -* -* -* Z* ------------------------------------------------------------------- */ #include"os_python.h" #include"MemoryDebug.h" #include"Text.h" #include"Font.h" #include"FontGLUT.h" #include"FontType.h" #include"Color.h" #include"Vector.h" #include"Executive.h" #ifdef _PYMOL_FREETYPE #include "FontTTF.h" #include "FontTTF2.h" #endif #define FONT_NAME_MAX 255 #define TEXT_DEFAULT_SIZE 12.0F static const float _255 = 255.0F; static const float _499 = 0.4999F; typedef struct { int Src; int Code; char Name[FONT_NAME_MAX]; int Mode; int Style; CFont *Font; } ActiveRec; #define NFONTS 20 struct _CText { int NActive; ActiveRec *Active; float Pos[4]; float WorldPos[4]; float ScreenWorldOffset[3]; float TargetPos[3]; float LabelPushPos[3]; float LabelPos[3]; unsigned char LabelPosIsSet; // 1 for just z, 2 for 3f float TextIndentFactor[2]; float Color[4]; unsigned char UColor[4]; unsigned char OutlineColor[4]; int Default_ID; float Height, Width; float Spacing, Just; float LabelBuf[2]; int XHRFetched[NFONTS]; int XHRFailed[NFONTS]; bool Flat, IsPicking; }; static void TextUpdateUColor(CText * I) { I->UColor[0] = (unsigned char) (_255 * I->Color[0] + _499); I->UColor[1] = (unsigned char) (_255 * I->Color[1] + _499); I->UColor[2] = (unsigned char) (_255 * I->Color[2] + _499); I->UColor[3] = (unsigned char) (_255 * I->Color[3] + _499); } void TextSetLabelBkgrdInfo(PyMOLGlobals * G, float label_spacing, float label_just, const float *buff){ CText *I = G->Text; I->Spacing = label_spacing; I->Just = label_just; if (buff){ I->LabelBuf[0] = buff[0]; I->LabelBuf[1] = buff[1]; } else { I->LabelBuf[0] = I->LabelBuf[1] = .2f; } } void TextSetIsPicking(PyMOLGlobals * G, bool IsPicking) { CText *I = G->Text; I->IsPicking = IsPicking; } bool TextGetIsPicking(PyMOLGlobals * G) { CText *I = G->Text; return I->IsPicking; } void TextSetPosNColor(PyMOLGlobals * G, const float *pos, const float *color) { CText *I = G->Text; copy3f(pos, I->Pos); copy3f(color, I->Color); I->Flat = false; I->Pos[3] = 1.0F; I->Color[3] = 1.0F; TextUpdateUColor(I); } void TextAdvance(PyMOLGlobals * G, float advance) { G->Text->Pos[0] += advance; } void TextSetLabPos(PyMOLGlobals * G, const float *pos, const LabPosType * labpos, const char *text) { if((!labpos) || (!labpos->mode)) TextSetPos(G, pos); else { CText *I = G->Text; switch (labpos->mode) { default: copy3f(pos, I->Pos); add3f(labpos->offset, I->Pos, I->Pos); break; } } } void TextIndent(PyMOLGlobals * G, float x, float y) { CText *I = G->Text; I->Pos[0] -= x; I->Pos[1] -= y; } void TextSetPos(PyMOLGlobals * G, const float *pos) { CText *I = G->Text; copy3f(pos, I->Pos); I->Pos[3] = 1.0F; } void TextSetWorldPos(PyMOLGlobals * G, const float *pos) { CText *I = G->Text; copy3f(pos, I->WorldPos); I->WorldPos[3] = 1.0F; } float *TextGetWorldPos(PyMOLGlobals * G){ CText *I = G->Text; return I->WorldPos; } void TextSetLabelPos(PyMOLGlobals * G, const float *pos) { CText *I = G->Text; copy3f(pos, I->LabelPos); } float *TextGetLabelPos(PyMOLGlobals * G) { CText *I = G->Text; return (I->LabelPos); } void TextSetLabelPosIsSet(PyMOLGlobals * G, unsigned char isSet) { CText *I = G->Text; I->LabelPosIsSet = isSet; } unsigned char TextGetLabelPosIsSet(PyMOLGlobals * G) { CText *I = G->Text; return I->LabelPosIsSet; } void TextSetLabelPushPos(PyMOLGlobals * G, const float *pos) { CText *I = G->Text; copy3f(pos, I->LabelPushPos); } float *TextGetLabelPushPos(PyMOLGlobals * G){ CText *I = G->Text; return I->LabelPushPos; } void TextSetScreenWorldOffset(PyMOLGlobals * G, const float *pos) { CText *I = G->Text; I->ScreenWorldOffset[0] = -pos[0]; I->ScreenWorldOffset[1] = -pos[1]; I->ScreenWorldOffset[2] = -pos[2]; } float *TextGetScreenWorldOffset(PyMOLGlobals * G){ CText *I = G->Text; return I->ScreenWorldOffset; } void TextSetTargetPos(PyMOLGlobals * G, const float *pos){ CText *I = G->Text; copy3f(pos, I->TargetPos); } float *TextGetTargetPos(PyMOLGlobals * G){ CText *I = G->Text; return I->TargetPos; } void TextDrawSubStrFast(PyMOLGlobals * G, const char *c, int x, int y, int start, int n ORTHOCGOARG) { c += start; TextSetPos2i(G, x, y); if(n) while(*c) { n--; TextDrawChar(G, *(c++) ORTHOCGOARGVAR); if(n <= 0) break; } } void TextDrawCharRepeat(PyMOLGlobals * G, char c, int x, int y, int start, int n ORTHOCGOARG) { c += start; TextSetPos2i(G, x, y); while(n) { n--; TextDrawChar(G, c ORTHOCGOARGVAR); } } void TextSetPos2i(PyMOLGlobals * G, int x, int y) { CText *I = G->Text; I->Pos[0] = (float) x; I->Pos[1] = (float) y; I->Pos[2] = 0.0F; I->Pos[3] = 1.0F; } static void TextSetPos3f(PyMOLGlobals * G, float x, float y, float z) { CText *I = G->Text; I->Pos[0] = x; I->Pos[1] = y; I->Pos[2] = z; I->Pos[3] = 1.0F; } void TextSetColor(PyMOLGlobals * G, const float *color) { CText *I = G->Text; copy3f(color, I->Color); I->Color[3] = 1.0F; I->Flat = false; TextUpdateUColor(I); } void TextSetColor3f(PyMOLGlobals * G, float red, float green, float blue) { CText *I = G->Text; I->Flat = false; I->Color[0] = red; I->Color[1] = green; I->Color[2] = blue; I->Color[3] = 1.0F; TextUpdateUColor(I); } void TextSetOutlineColor(PyMOLGlobals * G, int color) { CText *I = G->Text; if(color >= 0) { const float *fcolor = ColorGet(G, color); I->OutlineColor[0] = (unsigned char) (_255 * fcolor[0]); I->OutlineColor[1] = (unsigned char) (_255 * fcolor[1]); I->OutlineColor[2] = (unsigned char) (_255 * fcolor[2]); I->OutlineColor[3] = 0xFF; } else { I->OutlineColor[3] = 0; } } static const float _inv255 = 1.0F / 255.0F; void TextSetPickColor(PyMOLGlobals * G, int first_pass, int index) { CText *I = G->Text; if(!first_pass) index = (index >> 12); /* high order bits */ I->Flat = true; I->UColor[0] = ((unsigned char) ((index & 0xF) << 4)); I->UColor[1] = ((unsigned char) ((index & 0xF0) | 0x8)); I->UColor[2] = ((unsigned char) ((index & 0xF00) >> 4)); I->UColor[3] = 0xFF; I->Color[0] = I->UColor[0] * _inv255; I->Color[1] = I->UColor[1] * _inv255; I->Color[2] = I->UColor[2] * _inv255; I->Color[3] = 1.0F; } void TextSetColorFromUColor(PyMOLGlobals * G) { CText *I = G->Text; I->Color[0] = I->UColor[0] * _inv255; I->Color[1] = I->UColor[1] * _inv255; I->Color[2] = I->UColor[2] * _inv255; I->Color[3] = 1.0F; } float *TextGetPos(PyMOLGlobals * G) { CText *I = G->Text; return I->Pos; } float TextGetWidth(PyMOLGlobals * G) { CText *I = G->Text; return I->Width; } float TextGetHeight(PyMOLGlobals * G) { CText *I = G->Text; return I->Height; } void TextSetIndentFactorX(PyMOLGlobals * G, float factor){ CText *I = G->Text; I->TextIndentFactor[0] = factor; } void TextSetIndentFactorY(PyMOLGlobals * G, float factor){ CText *I = G->Text; I->TextIndentFactor[1] = factor; } float *TextGetIndentFactor(PyMOLGlobals * G){ CText *I = G->Text; return I->TextIndentFactor; } void TextSetWidth(PyMOLGlobals * G, float text_width) { CText *I = G->Text; I->Width = text_width; } void TextSetHeight(PyMOLGlobals * G, float text_height) { CText *I = G->Text; I->Height = text_height; } float *TextGetColor(PyMOLGlobals * G) { CText *I = G->Text; return I->Color; } unsigned char *TextGetColorUChar4uv(PyMOLGlobals * G){ CText *I = G->Text; return I->UColor; } void TextGetColorUChar(PyMOLGlobals * G, unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *alpha) { CText *I = G->Text; *red = I->UColor[0]; *green = I->UColor[1]; *blue = I->UColor[2]; *alpha = I->UColor[3]; } void TextGetOutlineColor(PyMOLGlobals * G, unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *alpha) { CText *I = G->Text; *red = I->OutlineColor[0]; *green = I->OutlineColor[1]; *blue = I->OutlineColor[2]; *alpha = I->OutlineColor[3]; } const char *TextRenderOpenGL(PyMOLGlobals * G, RenderInfo * info, int text_id, const char *st, float size, float *rpos, short needSize, short relativeMode, short shouldRender, CGO *shaderCGO) { CText *I = G->Text; CFont *font; FontRenderOpenGLFn *fn; if((text_id < 0) || (text_id >= I->NActive)) text_id = 0; if(st && (*st)) { if((text_id >= 0) && (text_id < I->NActive)) { if (I->Active[text_id].Font) { font = I->Active[text_id].Font; if(I->Flat) fn = font->fRenderOpenGLFlat; else fn = font->fRenderOpenGL; if(fn) return fn(info, font, st, size, rpos, needSize, relativeMode, shouldRender SHADERCGOARGVAR); } } /* make sure we got to end of string */ if(*st) while(*(st++)); } return st; } void TextDrawStrAt(PyMOLGlobals * G, const char *st, int x, int y ORTHOCGOARG) { CText *I = G->Text; TextSetPos3f(G, (float) x, (float) y, 0.0F); TextRenderOpenGL(G, NULL, I->Default_ID, st, TEXT_DEFAULT_SIZE, NULL, false, 0, 1 ORTHOCGOARGVAR); } void TextDrawStr(PyMOLGlobals * G, const char *st ORTHOCGOARG) { CText *I = G->Text; TextRenderOpenGL(G, NULL, I->Default_ID, st, TEXT_DEFAULT_SIZE, NULL, false, 0, 1 ORTHOCGOARGVAR); } void TextDrawChar(PyMOLGlobals * G, char ch ORTHOCGOARG) { char st[2] = { 0, 0 }; CText *I = G->Text; st[0] = ch; TextRenderOpenGL(G, NULL, I->Default_ID, st, TEXT_DEFAULT_SIZE, NULL, false, 0, 1 ORTHOCGOARGVAR); } const char *TextRenderRay(PyMOLGlobals * G, CRay * ray, int text_id, const char *st, float size, float *rpos, short needSize, short relativeMode) { CText *I = G->Text; CFont *font; FontRenderRayFn *fn; if((text_id < 0) || (text_id >= I->NActive)) text_id = 0; if(st && (*st)) { if((text_id >= 0) && (text_id < I->NActive)) { font = I->Active[text_id].Font; if(size >= 0.0F) size *= ray->Magnified; fn = font->fRenderRay; if(fn) return fn(ray, font, st, size, rpos, needSize, relativeMode); } /* make sure we got to end of string */ if(*st) while(*(st++)); } return st; } int TextInit(PyMOLGlobals * G) { CText *I = NULL; if((I = (G->Text = Calloc(CText, 1)))) { int i = 0; for (; i < NFONTS; i++) { I->XHRFetched[i] = 0; I->XHRFailed[i] = 0; } I->NActive = 0; I->Active = VLACalloc(ActiveRec, 10); I->Default_ID = 0; I->Flat = false; /* font 0 is old reliable GLUT 8x13 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontGLUTNew(G, cFontGLUT8x13); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcGLUT; I->Active[I->NActive].Code = cFontGLUT8x13; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* font 1 is GLUT 9x15 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontGLUTNew(G, cFontGLUT9x15); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcGLUT; I->Active[I->NActive].Code = cFontGLUT9x15; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* font 2 is GLUT Helvetica10 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontGLUTNew(G, cFontGLUTHel10); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcGLUT; I->Active[I->NActive].Code = cFontGLUTHel10; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* font 3 is GLUT Helvetica12 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontGLUTNew(G, cFontGLUTHel12); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcGLUT; I->Active[I->NActive].Code = cFontGLUTHel12; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* font 4 is GLUT Helvetica18 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontGLUTNew(G, cFontGLUTHel18); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcGLUT; I->Active[I->NActive].Code = cFontGLUTHel18; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } #ifdef _PYMOL_FREETYPE /* 5 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSans_dat, TTF_DejaVuSans_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 6 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSans_Oblique_dat, TTF_DejaVuSans_Oblique_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 7 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSans_Bold_dat, TTF_DejaVuSans_Bold_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 8 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSans_BoldOblique_dat, TTF_DejaVuSans_BoldOblique_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 9 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSerif_dat, TTF_DejaVuSerif_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 10 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSerif_Bold_dat, TTF_DejaVuSerif_Bold_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 11 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSansMono_dat, TTF_DejaVuSansMono_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 12 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSansMono_Oblique_dat, TTF_DejaVuSansMono_Oblique_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 13 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSansMono_Bold_dat, TTF_DejaVuSansMono_Bold_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 14 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSansMono_BoldOblique_dat, TTF_DejaVuSansMono_BoldOblique_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* Gentium */ /* 15 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_GenR102_dat, TTF_GenR102_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 16 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_GenI102_dat, TTF_GenI102_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* back to DejaVu for the last two */ /* 17 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSerif_Oblique_dat, TTF_DejaVuSerif_Oblique_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } /* 18 */ VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontTypeNew(G, TTF_DejaVuSerif_BoldOblique_dat, TTF_DejaVuSerif_BoldOblique_len); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcFreeType; I->Active[I->NActive].Font->TextID = I->NActive; I->NActive++; } #endif return 1; } else return 0; } int TextGetFontID(PyMOLGlobals * G, int src, int code, const char *name, int mode, int style) { /* first, return the font code if it is already active */ CText *I = G->Text; { int a; ActiveRec *rec = I->Active; for(a = 0; I->NActive; a++) { if((src == rec->Src) && (code == rec->Code) && (mode == rec->Mode) && (style == rec->Style)) if(((!name) && (!rec->Name[0])) || (name && (strcmp(name, rec->Name) == 0))) { return a; } rec++; } } switch (src) { case cTextSrcGLUT: VLACheck(I->Active, ActiveRec, I->NActive); I->Active[I->NActive].Font = FontGLUTNew(G, code); if(I->Active[I->NActive].Font) { I->Active[I->NActive].Src = cTextSrcGLUT; I->Active[I->NActive].Code = code; I->NActive++; } break; case cTextSrcFreeType: break; } return -1; } void TextFree(PyMOLGlobals * G) { CText *I = G->Text; int a; CFont *fp; for(a = 0; a < I->NActive; a++) { fp = I->Active[a].Font; if(fp && fp->fFree) fp->fFree(fp); } VLAFreeP(I->Active); FreeP(G->Text); } float TextGetSpacing(PyMOLGlobals * G) { CText *I = G->Text; return I->Spacing; } float TextGetJustification(PyMOLGlobals * G) { CText *I = G->Text; return I->Just; } float *TextGetLabelBuffer(PyMOLGlobals * G) { CText *I = G->Text; return I->LabelBuf; } /* * GUI elements like internal menus or the wizard prompt can handle text * color markup in the form "\\RGB" where RGB are three digits (0-9) or * "---" to reset the color. * * Return true if `p` starts with "\\RGB" or "\\---". */ bool TextStartsWithColorCode(const char *p) { if (p[0] != '\\') { return false; } if (p[1] == '-') { return p[2] == '-' && p[3] == '-'; } return ( ('0' <= p[1] && p[1] <= '9') && ('0' <= p[2] && p[2] <= '9') && ('0' <= p[3] && p[3] <= '9')); } /* * Set text color from "\\RGB" code. * * "\\---" -> defaultcolor * * Return false if `p` does not start with a color code. */ bool TextSetColorFromCode(PyMOLGlobals * G, const char *p, const float *defaultcolor) { if (!TextStartsWithColorCode(p)) { return false; } if (p[1] == '-') { TextSetColor(G, defaultcolor); } else { TextSetColor3f(G, (p[1] - '0') / 9.0F, (p[2] - '0') / 9.0F, (p[3] - '0') / 9.0F); } return true; }