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