1 
2 
3 /*
4 A* -------------------------------------------------------------------
5 B* This file contains source code for the PyMOL computer program
6 C* Copyright (c) Schrodinger, LLC.
7 D* -------------------------------------------------------------------
8 E* It is unlawful to modify or remove this copyright notice.
9 F* -------------------------------------------------------------------
10 G* Please see the accompanying LICENSE file for further information.
11 H* --------------------------------------------------\-----------------
12 I* Additional authors of this source file include:
13 -*
14 -*
15 -*
16 Z* -------------------------------------------------------------------
17 */
18 #include"os_python.h"
19 #include"os_gl.h"
20 
21 #include "Base.h"
22 #include "PyMOLGlobals.h"
23 #include "Texture.h"
24 #include "OOMac.h"
25 
26 #include "OVContext.h"
27 #include "OVOneToOne.h"
28 #include "OVHeapArray.h"
29 
30 #include "Setting.h"
31 #include "Character.h"
32 #include "Util.h"
33 #include "Feedback.h"
34 
35 #include "Executive.h"
36 #include "Ortho.h"
37 #include "ShaderMgr.h"
38 
39 #define POS_START  2
40 
41 typedef struct  {
42   int id,dim;
43 } texture_info;
44 
45 struct _CTexture {
46   OVOneToOne *ch2tex;
47   GLuint text_texture_id;
48   int xpos, ypos, maxypos;
49   int num_chars;
50   int text_texture_dim;
51 };
52 
TextureGetTextTextureID(PyMOLGlobals * G)53 GLuint TextureGetTextTextureID(PyMOLGlobals * G){
54   CTexture *I = G->Texture;
55   return I->text_texture_id;
56 }
TextureGetTextTextureSize(PyMOLGlobals * G)57 int TextureGetTextTextureSize(PyMOLGlobals * G){
58   CTexture *I = G->Texture;
59   return I->text_texture_dim;
60 }
61 
62 #define INIT_TEXTURE_SIZE 512
63 
TextureInit(PyMOLGlobals * G)64 int TextureInit(PyMOLGlobals * G)
65 {
66   OOAlloc(G, CTexture);
67 
68   G->Texture = I;
69 
70   I->ch2tex = OVOneToOne_New(G->Context->heap);
71   I->text_texture_dim = INIT_TEXTURE_SIZE;
72   I->text_texture_id = 0;
73   I->ypos = I->maxypos = I->num_chars = 0;
74   I->xpos = POS_START;
75   return (I ? 1 : 0);
76 }
77 
78 static
79 void TextureInitTextTextureImpl(PyMOLGlobals *G, int textureSize);
80 
TextureInitTextTexture(PyMOLGlobals * G)81 void TextureInitTextTexture(PyMOLGlobals *G){
82   TextureInitTextTextureImpl(G, INIT_TEXTURE_SIZE);
83 }
TextureInvalidateTextTexture(PyMOLGlobals * G)84 void TextureInvalidateTextTexture(PyMOLGlobals * G){
85   CTexture *I = G->Texture;
86   if (I->text_texture_id){
87     OVOneToOne_Reset(I->ch2tex);
88     I->num_chars = 0;
89     glDeleteTextures(1, &I->text_texture_id);
90     I->text_texture_id = 0;
91     I->text_texture_dim = INIT_TEXTURE_SIZE;
92     I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
93   }
94 }
95 
TextureInitTextTextureImpl(PyMOLGlobals * G,int textureSizeArg)96 void TextureInitTextTextureImpl(PyMOLGlobals *G, int textureSizeArg){
97   short is_new = 0;
98   CTexture *I = G->Texture;
99   int textureSize = textureSizeArg;
100   if (!textureSize)
101     textureSize = INIT_TEXTURE_SIZE;
102   if (!I->text_texture_id){
103     glGenTextures(1, &I->text_texture_id);
104     is_new = 1;
105   }
106   if(I->text_texture_id){
107     if (G->ShaderMgr->ShadersPresent()){
108       glActiveTexture(GL_TEXTURE3);
109     }
110     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
111     glBindTexture(GL_TEXTURE_2D, I->text_texture_id);
112     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
113     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
114     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
115     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
116     if (is_new){
117       int tex_dim = textureSize;
118       int buff_total = tex_dim * tex_dim;
119       unsigned char *temp_buffer = pymol::malloc<unsigned char>(buff_total * 4);
120       UtilZeroMem(temp_buffer, buff_total * 4);
121       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
122 		   tex_dim, tex_dim, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)temp_buffer);
123       I->text_texture_dim = textureSize;
124       FreeP(temp_buffer);
125       I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
126     }
127   }
128 }
129 
130 #include "Rep.h"
TextureGetFromChar(PyMOLGlobals * G,int char_id,float * extent)131 int TextureGetFromChar(PyMOLGlobals * G, int char_id, float *extent)
132 {
133   OVreturn_word result;
134   CTexture *I = G->Texture;
135   int is_new = false;
136   int tex_dim = I->text_texture_dim;
137   short use_shader = (short) SettingGetGlobal_b(G, cSetting_use_shaders);
138 
139   if(G->HaveGUI && G->ValidContext) {
140     if(OVreturn_IS_OK(result = OVOneToOne_GetForward(I->ch2tex, char_id))) {
141       if(glIsTexture(I->text_texture_id))
142         return I->text_texture_id;
143       else {
144         OVOneToOne_DelReverse(I->ch2tex, result.word);
145       }
146     }
147     {
148       unsigned char *buffer = NULL;
149       if (!I->text_texture_id){
150           is_new = true;
151       }
152       buffer = CharacterGetPixmapBuffer(G, char_id);
153       if(buffer) {
154         int w = CharacterGetWidth(G, char_id);
155         int h = CharacterGetHeight(G, char_id);
156         GLuint texture_id = 0;
157         int buff_incr = is_new ? tex_dim : w;
158         int buff_total = is_new ? tex_dim * tex_dim : w * h;
159         unsigned char *temp_buffer = pymol::malloc<unsigned char>(buff_total * 4);
160 
161         {
162           int a, b;
163           unsigned char *p = buffer, *q;
164 	  int fa = 0, ta = w;
165 	  if (is_new){
166 	    fa += I->xpos; ta += I->xpos;
167 	  }
168           UtilZeroMem(temp_buffer, buff_total * 4);
169           for(b = 0; b < h; b++) {
170 	    for(a = fa; a < ta; a++) {
171               q = temp_buffer + (4 * buff_incr * b) + 4 * a;
172               *(q++) = *(p++);
173               *(q++) = *(p++);
174               *(q++) = *(p++);
175               *(q++) = *(p++);
176             }
177           }
178 	  if (I->xpos + w > tex_dim){
179 	    // if the size of the texture goes off the side, go to next row
180 	    I->xpos = 0;
181 	    I->ypos = I->maxypos;
182 	  }
183 	  if ((I->ypos + h) >= I->text_texture_dim){ // only need to check y since x gets reset above
184 	    int nrefreshes;
185 	    I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
186 	    OVOneToOne_Reset(I->ch2tex);
187 	    I->num_chars = 0;
188 	    /* Also need to reload the selection markers into the texture, since
189 	       we are wiping everything out from the texture and starting from the origin */
190 	    if ((nrefreshes=SceneIncrementTextureRefreshes(G)) > 1){
191 	      /* Texture was refreshed more than once for this frame, increase size of texture */
192 	      int newDim = I->text_texture_dim * 2;
193 	      glDeleteTextures(1, &I->text_texture_id);
194 	      I->text_texture_id = 0;
195 	      TextureInitTextTextureImpl(G, newDim);
196 	      PRINTFB(G, FB_OpenGL, FB_Output)
197 		" Texture OpenGL: nrefreshes=%d newDim=%d\n", nrefreshes, newDim ENDFB(G);
198 
199 	      //	      printf("nrefreshes=%d newDim=%d\n", nrefreshes, newDim);
200 	      I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
201 	      SceneResetTextureRefreshes(G);
202 	    }
203 	    ExecutiveInvalidateRep(G, "all", cRepLabel, cRepInvRep);
204 	    ExecutiveInvalidateSelectionIndicators(G);
205 	    OrthoInvalidateDoDraw(G);
206 	    return 0;
207 	  }
208           extent[0] = (I->xpos / (float) tex_dim);
209           extent[1] = (I->ypos / (float) tex_dim);
210           extent[2] = ((I->xpos + w) / (float) tex_dim);
211           extent[3] = ((I->ypos + h) / (float) tex_dim);
212         }
213 
214 	if (!I->text_texture_id){
215           glGenTextures(1, &I->text_texture_id);
216 	}
217 	texture_id = I->text_texture_id;
218 	if(I->text_texture_id && OVreturn_IS_OK(OVOneToOne_Set(I->ch2tex, char_id, I->num_chars++))) {
219 
220 	  if (use_shader && G->ShaderMgr->ShadersPresent()){
221 	    glActiveTexture(GL_TEXTURE3);
222 	  }
223           glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
224           glBindTexture(GL_TEXTURE_2D, texture_id);
225           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
226           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
227           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
228           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
229           if(is_new) {
230 	    I->text_texture_dim = tex_dim;
231 	      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
232 			   tex_dim, tex_dim, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)temp_buffer);
233           } else {
234 	    int xoff = 0, yoff = 0;
235 	    xoff = I->xpos;
236 	    yoff = I->ypos;
237 	      glTexSubImage2D(GL_TEXTURE_2D, 0, xoff, yoff,
238 			      w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_buffer);
239           }
240         }
241 	if (I->ypos + h > I->maxypos){
242 	  I->maxypos = I->ypos + h + 1;  // added space for running on Ipad/Iphone (weird artifacts)
243 	}
244 	if (I->xpos + w > tex_dim){
245 	  I->xpos = 0;
246 	  I->ypos = I->maxypos;
247 	} else {
248 	  I->xpos += w + 1; // added space for running on Ipad/Iphone (weird artifacts)
249 	}
250           FreeP(temp_buffer);
251         return texture_id;
252       }
253     }
254   }
255   return 0;
256 }
257 
TextureGetPlacementForNewSubtexture(PyMOLGlobals * G,int new_texture_width,int new_texture_height,int * new_texture_posx,int * new_texture_posy)258 void TextureGetPlacementForNewSubtexture(PyMOLGlobals * G, int new_texture_width, int new_texture_height, int *new_texture_posx, int *new_texture_posy){
259   CTexture *I = G->Texture;
260   if (I->xpos + new_texture_width > I->text_texture_dim){
261     I->xpos = 0;
262     I->ypos = I->maxypos;
263   }
264   if (I->ypos + new_texture_height > I->maxypos){
265     I->maxypos = I->ypos + new_texture_height + 1;  // added space for running on Ipad/Iphone (weird artifacts)
266   }
267   *new_texture_posx = I->xpos;
268   *new_texture_posy = I->ypos;
269   I->xpos += new_texture_width + 1; // added space for running on Ipad/Iphone (weird artifacts)
270 }
271 
TextureFree(PyMOLGlobals * G)272 void TextureFree(PyMOLGlobals * G)
273 {
274   CTexture *I = G->Texture;
275   /* TODO -- free all the resident textures */
276   OVOneToOne_DEL_AUTO_NULL(I->ch2tex);
277   OOFreeP(I);
278 }
279