1 /*******************************************************************************
2 *                         Goggles Music Manager                                *
3 ********************************************************************************
4 *           Copyright (C) 2009-2021 by Sander Jansen. All Rights Reserved      *
5 *                               ---                                            *
6 * This program is free software: you can redistribute it and/or modify         *
7 * it under the terms of the GNU General Public License as published by         *
8 * the Free Software Foundation, either version 3 of the License, or            *
9 * (at your option) any later version.                                          *
10 *                                                                              *
11 * This program is distributed in the hope that it will be useful,              *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of               *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                *
14 * GNU General Public License for more details.                                 *
15 *                                                                              *
16 * You should have received a copy of the GNU General Public License            *
17 * along with this program.  If not, see http://www.gnu.org/licenses.           *
18 ********************************************************************************/
19 #include "gmdefs.h"
20 #ifdef HAVE_OPENGL
21 #include "GMImageView.h"
22 #include <GL/glu.h>
23 
GMImageTexture()24 GMImageTexture::GMImageTexture() :
25   id(0),
26   cw(1.0f),
27   ch(1.0f),
28   aspect(1.0f) {}
29 
~GMImageTexture()30 GMImageTexture::~GMImageTexture() {
31   FXASSERT(id==0);
32   }
33 
setImage(FXImage * image)34 FXbool GMImageTexture::setImage(FXImage* image) {
35   if (image) {
36     FXint image_width  = image->getWidth();
37     FXint image_height = image->getHeight();
38     FXint texture_width,texture_height;
39     FXint texture_max;
40 
41 
42     /// Query Maximum Texture Size
43     glGetIntegerv(GL_MAX_TEXTURE_SIZE,&texture_max);
44 
45     /// Prescale to maximum texture size if necessary
46     if((image_width>texture_max) || (image_height>texture_max)){
47 
48       if(image_width>image_height)
49         image->scale(texture_max,(texture_max*image_height)/image_width,FOX_SCALE_BEST);
50       else
51         image->scale((texture_max*image_width)/image_height,texture_max,FOX_SCALE_BEST);
52 
53       image_width=image->getWidth();
54       image_height=image->getHeight();
55       }
56 
57     // aspect ratio
58     aspect = image->getWidth() / (FXfloat) image->getHeight();
59 
60 
61     /// Get a nice texture size
62     if (epoxy_has_gl_extension("GL_ARB_texture_non_power_of_two")) {
63       texture_width=image_width;
64       texture_height=image_height;
65       }
66     else {
67       texture_width=1;
68       texture_height=1;
69       while(image_width>texture_width) texture_width<<=1;
70       while(image_height>texture_height) texture_height<<=1;
71       }
72 
73     FXASSERT(texture_width<=texture_max);
74     FXASSERT(texture_height<=texture_max);
75 
76     /// Generate a new texture if required.
77     if (id==0) {
78       glGenTextures(1,&id);
79       }
80 
81     glBindTexture(GL_TEXTURE_2D,id);
82     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
83     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
84 
85     FXbool use_mipmap = (epoxy_gl_version()>=30);
86 
87     if (use_mipmap) {
88       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
89       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
90       }
91     else {
92       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
93       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
94       }
95 
96    if (texture_width==image_width && texture_height==image_height) {
97       glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,texture_width,texture_height,0,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8_REV,image->getData());
98       cw=ch=1.0f;
99       }
100     else {
101       glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,texture_width,texture_height,0,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8_REV,nullptr);
102       glTexSubImage2D(GL_TEXTURE_2D,0,0,0,image_width,image_height,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8_REV,image->getData());
103       cw = (1.0f / (FXfloat)(texture_width))  * image_width;
104       ch = (1.0f / (FXfloat)(texture_height)) * image_height;
105       }
106     if (use_mipmap)
107       glGenerateMipmap(GL_TEXTURE_2D);
108     }
109   else {
110     if (id) {
111       glDeleteTextures(1,&id);
112       id=0;
113       }
114     }
115   return true;
116   }
117 
118 
drawQuad(FXfloat x,FXfloat y,FXfloat width,FXfloat height,FXColor background)119 void GMImageTexture::drawQuad(FXfloat x,FXfloat y,FXfloat width,FXfloat height,FXColor background) {
120   const FXfloat coordinates[8] = { x,y,
121                                    x,y+height,
122                                    x+width,y,
123                                    x+width,y+height
124                                    };
125 
126   const FXfloat tex[8] = { 0.0f,ch,
127                            0.0f,0.0f,
128                            cw,ch,
129                            cw,0.0f
130                             };
131 
132   const FXuchar colors[16] = { FXREDVAL(background),FXBLUEVAL(background),FXGREENVAL(background),
133                                FXREDVAL(background),FXBLUEVAL(background),FXGREENVAL(background),
134                                FXREDVAL(background),FXBLUEVAL(background),FXGREENVAL(background),
135                                FXREDVAL(background),FXBLUEVAL(background),FXGREENVAL(background) };
136 
137 
138   glEnable(GL_TEXTURE_2D);
139   glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
140   glBindTexture(GL_TEXTURE_2D,id);
141   glEnableClientState(GL_VERTEX_ARRAY);
142   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
143   glEnableClientState(GL_COLOR_ARRAY);
144   glColorPointer(3,GL_UNSIGNED_BYTE,0,colors);
145   glVertexPointer(2,GL_FLOAT,0,coordinates);
146   glTexCoordPointer(2,GL_FLOAT,0,tex);
147   glDrawArrays(GL_TRIANGLE_STRIP,0,4);
148   glDisableClientState(GL_COLOR_ARRAY);
149   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
150   glDisableClientState(GL_VERTEX_ARRAY);
151   }
152 
153 
154 
155 FXDEFMAP(GMImageView) GMImageViewMap[]={
156   FXMAPFUNC(SEL_PAINT,0,GMImageView::onPaint)
157   };
158 
159 FXIMPLEMENT(GMImageView,FXGLCanvas,GMImageViewMap,ARRAYNUMBER(GMImageViewMap));
160 
161 
GMImageView()162 GMImageView::GMImageView(){
163   texture=nullptr;
164   }
165 
GMImageView(FXComposite * p,FXGLContext * ctx,FXuint opts,FXint x,FXint y,FXint w,FXint h)166 GMImageView::GMImageView(FXComposite* p,FXGLContext *ctx,FXuint opts,FXint x,FXint y,FXint w,FXint h) : FXGLCanvas(p,ctx,nullptr,0,opts,x,y,w,h){
167   texture=nullptr;
168   }
169 
~GMImageView()170 GMImageView::~GMImageView(){
171   delete texture;
172   }
173 
setImage(FXImage * image)174 void GMImageView::setImage(FXImage * image) {
175   if (makeCurrent()) {
176     if (texture==nullptr && image) {
177       texture = new GMImageTexture();
178       }
179     if (texture) texture->setImage(image);
180     makeNonCurrent();
181     }
182   recalc();
183   update();
184   }
185 
186 
getDefaultWidth()187 FXint GMImageView::getDefaultWidth() {
188   return 256;
189   }
190 
getDefaultHeight()191 FXint GMImageView::getDefaultHeight() {
192   return 256;
193   }
194 
195 // Repaint the GL window
onPaint(FXObject *,FXSelector,void *)196 long GMImageView::onPaint(FXObject*,FXSelector,void*){
197   FXGLVisual *vis=(FXGLVisual*)getVisual();
198   FXfloat aspect = getWidth() / (float)getHeight();
199   FXfloat xwidth = 1.0f*aspect;
200   FXfloat size;
201 
202   FXVec4f background=colorToVec4f(backColor);
203   FXASSERT(xid);
204   if(makeCurrent()){
205     glViewport(0,0,getWidth(),getHeight());
206     glClearColor(background.x,background.y,background.z,background.w);
207     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
208 
209     if (texture && texture->id) {
210       glMatrixMode(GL_MODELVIEW);
211       glLoadIdentity();
212       gluOrtho2D(0,xwidth,0.0f,1.0f);
213 
214       if (aspect>=texture->aspect) {
215         size = 1.0f*texture->aspect;
216         texture->drawQuad(0.5f*(xwidth-size),0.0f,size,1.0f,backColor);
217         }
218       else {
219         size = xwidth / texture->aspect;
220         texture->drawQuad(0.0f,0.5f * (1.0f-size),xwidth,size,backColor);
221         }
222       }
223     if(vis->isDoubleBuffer()) swapBuffers();
224     makeNonCurrent();
225     }
226   return 1;
227   }
228 #endif
229