mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
271 lines
8.4 KiB
C++
271 lines
8.4 KiB
C++
|
|
|
|
/*
|
|
A* -------------------------------------------------------------------
|
|
B* This file contains source code for the PyMOL computer program
|
|
C* Copyright (c) Schrodinger, LLC.
|
|
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"os_gl.h"
|
|
|
|
#include "Base.h"
|
|
#include "PyMOLGlobals.h"
|
|
#include "Texture.h"
|
|
|
|
#include "Setting.h"
|
|
#include "Character.h"
|
|
#include "Util.h"
|
|
#include "Feedback.h"
|
|
|
|
#include "Executive.h"
|
|
#include "Ortho.h"
|
|
#include "ShaderMgr.h"
|
|
|
|
#define POS_START 2
|
|
|
|
typedef struct {
|
|
int id,dim;
|
|
} texture_info;
|
|
|
|
struct CTexture {
|
|
std::unordered_map<int, int> ch2tex;
|
|
GLuint text_texture_id{};
|
|
int xpos{};
|
|
int ypos{};
|
|
int maxypos{};
|
|
int num_chars{};
|
|
int text_texture_dim{};
|
|
};
|
|
|
|
GLuint TextureGetTextTextureID(PyMOLGlobals * G){
|
|
CTexture *I = G->Texture;
|
|
return I->text_texture_id;
|
|
}
|
|
int TextureGetTextTextureSize(PyMOLGlobals * G){
|
|
CTexture *I = G->Texture;
|
|
return I->text_texture_dim;
|
|
}
|
|
|
|
#define INIT_TEXTURE_SIZE 512
|
|
|
|
int TextureInit(PyMOLGlobals * G)
|
|
{
|
|
auto I = new CTexture();
|
|
G->Texture = I;
|
|
|
|
I->text_texture_dim = INIT_TEXTURE_SIZE;
|
|
I->ypos = I->maxypos = I->num_chars = 0;
|
|
I->xpos = POS_START;
|
|
return (I ? 1 : 0);
|
|
}
|
|
|
|
static
|
|
void TextureInitTextTextureImpl(PyMOLGlobals *G, int textureSize);
|
|
|
|
void TextureInitTextTexture(PyMOLGlobals *G){
|
|
TextureInitTextTextureImpl(G, INIT_TEXTURE_SIZE);
|
|
}
|
|
void TextureInvalidateTextTexture(PyMOLGlobals * G){
|
|
CTexture *I = G->Texture;
|
|
if (I->text_texture_id){
|
|
I->ch2tex.clear();
|
|
I->num_chars = 0;
|
|
glDeleteTextures(1, &I->text_texture_id);
|
|
I->text_texture_id = 0;
|
|
I->text_texture_dim = INIT_TEXTURE_SIZE;
|
|
I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
|
|
}
|
|
}
|
|
|
|
void TextureInitTextTextureImpl(PyMOLGlobals *G, int textureSizeArg){
|
|
short is_new = 0;
|
|
CTexture *I = G->Texture;
|
|
int textureSize = textureSizeArg;
|
|
if (!textureSize)
|
|
textureSize = INIT_TEXTURE_SIZE;
|
|
if (!I->text_texture_id){
|
|
glGenTextures(1, &I->text_texture_id);
|
|
is_new = 1;
|
|
}
|
|
if(I->text_texture_id){
|
|
if (G->ShaderMgr->ShadersPresent()){
|
|
glActiveTexture(GL_TEXTURE3);
|
|
}
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
glBindTexture(GL_TEXTURE_2D, I->text_texture_id);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
if (is_new){
|
|
int tex_dim = textureSize;
|
|
int buff_total = tex_dim * tex_dim;
|
|
unsigned char *temp_buffer = pymol::malloc<unsigned char>(buff_total * 4);
|
|
UtilZeroMem(temp_buffer, buff_total * 4);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
|
tex_dim, tex_dim, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)temp_buffer);
|
|
I->text_texture_dim = textureSize;
|
|
FreeP(temp_buffer);
|
|
I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
|
|
}
|
|
}
|
|
}
|
|
|
|
#include "Rep.h"
|
|
int TextureGetFromChar(PyMOLGlobals * G, int char_id, float *extent)
|
|
{
|
|
CTexture *I = G->Texture;
|
|
int is_new = false;
|
|
int tex_dim = I->text_texture_dim;
|
|
short use_shader = (short) SettingGetGlobal_b(G, cSetting_use_shaders);
|
|
|
|
if(G->HaveGUI && G->ValidContext) {
|
|
auto it = I->ch2tex.find(char_id);
|
|
if (it != I->ch2tex.end()) {
|
|
if(glIsTexture(I->text_texture_id))
|
|
return I->text_texture_id;
|
|
else {
|
|
I->ch2tex.erase(it);
|
|
}
|
|
}
|
|
{
|
|
unsigned char *buffer = NULL;
|
|
if (!I->text_texture_id){
|
|
is_new = true;
|
|
}
|
|
buffer = CharacterGetPixmapBuffer(G, char_id);
|
|
if(buffer) {
|
|
int w = CharacterGetWidth(G, char_id);
|
|
int h = CharacterGetHeight(G, char_id);
|
|
GLuint texture_id = 0;
|
|
int buff_incr = is_new ? tex_dim : w;
|
|
int buff_total = is_new ? tex_dim * tex_dim : w * h;
|
|
unsigned char *temp_buffer = pymol::malloc<unsigned char>(buff_total * 4);
|
|
|
|
{
|
|
int a, b;
|
|
unsigned char *p = buffer, *q;
|
|
int fa = 0, ta = w;
|
|
if (is_new){
|
|
fa += I->xpos; ta += I->xpos;
|
|
}
|
|
UtilZeroMem(temp_buffer, buff_total * 4);
|
|
for(b = 0; b < h; b++) {
|
|
for(a = fa; a < ta; a++) {
|
|
q = temp_buffer + (4 * buff_incr * b) + 4 * a;
|
|
*(q++) = *(p++);
|
|
*(q++) = *(p++);
|
|
*(q++) = *(p++);
|
|
*(q++) = *(p++);
|
|
}
|
|
}
|
|
if (I->xpos + w > tex_dim){
|
|
// if the size of the texture goes off the side, go to next row
|
|
I->xpos = 0;
|
|
I->ypos = I->maxypos;
|
|
}
|
|
if ((I->ypos + h) >= I->text_texture_dim){ // only need to check y since x gets reset above
|
|
int nrefreshes;
|
|
I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
|
|
I->ch2tex.clear();
|
|
I->num_chars = 0;
|
|
/* Also need to reload the selection markers into the texture, since
|
|
we are wiping everything out from the texture and starting from the origin */
|
|
if ((nrefreshes=SceneIncrementTextureRefreshes(G)) > 1){
|
|
/* Texture was refreshed more than once for this frame, increase size of texture */
|
|
int newDim = I->text_texture_dim * 2;
|
|
glDeleteTextures(1, &I->text_texture_id);
|
|
I->text_texture_id = 0;
|
|
TextureInitTextTextureImpl(G, newDim);
|
|
PRINTFB(G, FB_OpenGL, FB_Output)
|
|
" Texture OpenGL: nrefreshes=%d newDim=%d\n", nrefreshes, newDim ENDFB(G);
|
|
|
|
// printf("nrefreshes=%d newDim=%d\n", nrefreshes, newDim);
|
|
I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
|
|
SceneResetTextureRefreshes(G);
|
|
}
|
|
ExecutiveInvalidateRep(G, "all", cRepLabel, cRepInvRep);
|
|
ExecutiveInvalidateSelectionIndicators(G);
|
|
OrthoInvalidateDoDraw(G);
|
|
return 0;
|
|
}
|
|
extent[0] = (I->xpos / (float) tex_dim);
|
|
extent[1] = (I->ypos / (float) tex_dim);
|
|
extent[2] = ((I->xpos + w) / (float) tex_dim);
|
|
extent[3] = ((I->ypos + h) / (float) tex_dim);
|
|
}
|
|
|
|
if (!I->text_texture_id){
|
|
glGenTextures(1, &I->text_texture_id);
|
|
}
|
|
texture_id = I->text_texture_id;
|
|
if (I->text_texture_id) {
|
|
I->ch2tex[char_id] = I->num_chars++;
|
|
if (use_shader && G->ShaderMgr->ShadersPresent()){
|
|
glActiveTexture(GL_TEXTURE3);
|
|
}
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
if(is_new) {
|
|
I->text_texture_dim = tex_dim;
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
|
tex_dim, tex_dim, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)temp_buffer);
|
|
} else {
|
|
int xoff = 0, yoff = 0;
|
|
xoff = I->xpos;
|
|
yoff = I->ypos;
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, xoff, yoff,
|
|
w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_buffer);
|
|
}
|
|
}
|
|
if (I->ypos + h > I->maxypos){
|
|
I->maxypos = I->ypos + h + 1; // added space for running on Ipad/Iphone (weird artifacts)
|
|
}
|
|
if (I->xpos + w > tex_dim){
|
|
I->xpos = 0;
|
|
I->ypos = I->maxypos;
|
|
} else {
|
|
I->xpos += w + 1; // added space for running on Ipad/Iphone (weird artifacts)
|
|
}
|
|
FreeP(temp_buffer);
|
|
return texture_id;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void TextureGetPlacementForNewSubtexture(PyMOLGlobals * G, int new_texture_width, int new_texture_height, int *new_texture_posx, int *new_texture_posy){
|
|
CTexture *I = G->Texture;
|
|
if (I->xpos + new_texture_width > I->text_texture_dim){
|
|
I->xpos = 0;
|
|
I->ypos = I->maxypos;
|
|
}
|
|
if (I->ypos + new_texture_height > I->maxypos){
|
|
I->maxypos = I->ypos + new_texture_height + 1; // added space for running on Ipad/Iphone (weird artifacts)
|
|
}
|
|
*new_texture_posx = I->xpos;
|
|
*new_texture_posy = I->ypos;
|
|
I->xpos += new_texture_width + 1; // added space for running on Ipad/Iphone (weird artifacts)
|
|
}
|
|
|
|
void TextureFree(PyMOLGlobals * G)
|
|
{
|
|
/* TODO -- free all the resident textures */
|
|
DeleteP(G->Texture);
|
|
}
|