mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
276 lines
8.2 KiB
C++
276 lines
8.2 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 <memory>
|
|
#include <unordered_set>
|
|
|
|
#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"
|
|
#include "GenericBuffer.h"
|
|
|
|
#define POS_START 2
|
|
|
|
/**
|
|
* Texture unit assigned to the global text texture.
|
|
* See ShaderMgr.cpp for more details.
|
|
*/
|
|
constexpr std::uint8_t GlobalTextTextureUnit = 3;
|
|
|
|
struct CTexture {
|
|
std::unordered_set<int> texturedCharIDs; // set of char ids that have been textured
|
|
std::unique_ptr<TextureGL> texture;
|
|
int xpos{};
|
|
int ypos{};
|
|
int maxypos{};
|
|
int text_texture_dim{};
|
|
};
|
|
|
|
void TextureBindTexture(PyMOLGlobals* G) {
|
|
auto I = G->Texture;
|
|
if (I->texture) {
|
|
I->texture->bind();
|
|
}
|
|
}
|
|
|
|
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 = 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->texture) {
|
|
I->texturedCharIDs.clear();
|
|
I->texture.reset();
|
|
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->texture) {
|
|
using namespace tex;
|
|
I->texture =
|
|
std::make_unique<TextureGL>(format::RGBA, data_type::UBYTE,
|
|
filter::NEAREST, filter::NEAREST, wrap::CLAMP, wrap::CLAMP);
|
|
is_new = true;
|
|
}
|
|
if (I->texture) {
|
|
if (is_new) {
|
|
int tex_dim = textureSize;
|
|
int buff_total = tex_dim * tex_dim;
|
|
std::vector<unsigned char> temp_buffer(
|
|
buff_total * GetSizeOfVertexFormat(VertexFormat::UByte4), 0);
|
|
I->texture->bindToTextureUnit(GlobalTextTextureUnit);
|
|
I->texture->texture_data_2D(tex_dim, tex_dim, temp_buffer.data());
|
|
I->text_texture_dim = textureSize;
|
|
I->xpos = POS_START; I->ypos = 0; I->maxypos = POS_START;
|
|
}
|
|
}
|
|
}
|
|
|
|
#include "Rep.h"
|
|
bool TextureIsCharTextured(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->texturedCharIDs.find(char_id);
|
|
if (it != I->texturedCharIDs.end()) {
|
|
if (I->texture) {
|
|
return true;
|
|
}
|
|
else {
|
|
I->texturedCharIDs.erase(char_id);
|
|
}
|
|
}
|
|
{
|
|
unsigned char *buffer = nullptr;
|
|
if (!I->texture) {
|
|
is_new = true;
|
|
}
|
|
buffer = CharacterGetPixmapBuffer(G, char_id);
|
|
if(buffer) {
|
|
int w = CharacterGetWidth(G, char_id);
|
|
int h = CharacterGetHeight(G, char_id);
|
|
int buff_incr = is_new ? tex_dim : w;
|
|
int buff_total = is_new ? tex_dim * tex_dim : w * h;
|
|
std::vector<unsigned char> temp_buffer(
|
|
buff_total * GetSizeOfVertexFormat(VertexFormat::UByte4), 0);
|
|
|
|
{
|
|
int a, b;
|
|
unsigned char *p = buffer, *q;
|
|
int fa = 0, ta = w;
|
|
if (is_new){
|
|
fa += I->xpos; ta += I->xpos;
|
|
}
|
|
for(b = 0; b < h; b++) {
|
|
for(a = fa; a < ta; a++) {
|
|
q = temp_buffer.data() + (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->texturedCharIDs.clear();
|
|
/* 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;
|
|
I->texture.reset();
|
|
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 false;
|
|
}
|
|
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->texture) {
|
|
using namespace tex;
|
|
I->texture =
|
|
std::make_unique<TextureGL>(format::RGBA, data_type::UBYTE,
|
|
filter::NEAREST, filter::NEAREST, wrap::CLAMP, wrap::CLAMP);
|
|
}
|
|
if (I->texture) {
|
|
I->texturedCharIDs.emplace(char_id);
|
|
if (is_new) {
|
|
I->text_texture_dim = tex_dim;
|
|
I->texture->bindToTextureUnit(GlobalTextTextureUnit);
|
|
I->texture->texture_data_2D(tex_dim, tex_dim, temp_buffer.data());
|
|
} else {
|
|
int xoff = 0, yoff = 0;
|
|
xoff = I->xpos;
|
|
yoff = I->ypos;
|
|
I->texture->texture_subdata_2D(xoff, yoff, w, h, temp_buffer.data());
|
|
#ifdef _WEBGL
|
|
static bool error_flag = false;
|
|
if ((glGetError()) != 0 && error_flag) {
|
|
PRINTFB(G, FB_OpenGL, FB_Output)
|
|
" IE11 texSubImage2D bug detected, supressing...\n" ENDFB(G);
|
|
error_flag = true;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
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)
|
|
}
|
|
return I->texture != nullptr;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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 TextureFillNewSubtexture(PyMOLGlobals* G, int width, int height, int x, int y, const void* data)
|
|
{
|
|
CTexture *I = G->Texture;
|
|
if (I->texture) {
|
|
I->texture->texture_subdata_2D(x, y, width, height, data);
|
|
}
|
|
}
|
|
|
|
void TextureFree(PyMOLGlobals * G)
|
|
{
|
|
/* TODO -- free all the resident textures */
|
|
DeleteP(G->Texture);
|
|
}
|