[gimp-normalmap] / trunk / preview3d.c Repository:
ViewVC logotype

View of /trunk/preview3d.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 41 - (download) (as text) (annotate)
Fri Apr 11 20:16:52 2008 UTC (19 months, 1 week ago) by cocidius
File size: 63702 byte(s)
* Update INSTALL, README
* Update contact information if file headers
    1 /*
    2    normalmap GIMP plugin
    3 
    4    Copyright (C) 2002-2008 Shawn Kirst <skirst@insightbb.com>
    5 
    6    This program is free software; you can redistribute it and/or
    7    modify it under the terms of the GNU General Public
    8    License as published by the Free Software Foundation; either
    9    version 2 of the License, or (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 GNU
   14    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; see the file COPYING.  If not, write to
   18    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   19    Boston, MA 02111-1307, USA.
   20 */
   21 
   22 #include <string.h>
   23 #include <math.h>
   24 #include <ctype.h>
   25 #include <gtk/gtk.h>
   26 #include <gtk/gtkgl.h>
   27 #include <GL/glew.h>
   28 #include <libgimp/gimp.h>
   29 #include <libgimp/gimpui.h>
   30 
   31 #include "scale.h"
   32 
   33 #include "objects/quad.h"
   34 #include "objects/cube.h"
   35 #include "objects/sphere.h"
   36 #include "objects/torus.h"
   37 #include "objects/teapot.h"
   38 
   39 #include "pixmaps/object.xpm"
   40 #include "pixmaps/light.xpm"
   41 #include "pixmaps/scene.xpm"
   42 #include "pixmaps/full.xpm"
   43 
   44 #define IS_POT(x)  (((x) & ((x) - 1)) == 0)
   45 
   46 typedef float matrix[16];
   47 typedef float vec4[4];
   48 typedef float vec3[3];
   49 typedef float vec2[2];
   50 
   51 typedef enum
   52 {
   53    BUMPMAP_NORMAL = 0, BUMPMAP_PARALLAX, BUMPMAP_POM, BUMPMAP_RELIEF,
   54    BUMPMAP_MAX
   55 } BUMPMAP_TYPE;
   56 
   57 typedef enum
   58 {
   59    ROTATE_OBJECT = 0, ROTATE_LIGHT, ROTATE_SCENE,
   60    ROTATE_MAX
   61 } ROTATE_TYPE;
   62 
   63 typedef enum
   64 {
   65    OBJECT_QUAD = 0, OBJECT_CUBE, OBJECT_SPHERE, OBJECT_TORUS, OBJECT_TEAPOT,
   66    OBJECT_MAX
   67 } OBJECT_TYPE;
   68 
   69 static int _active = 0;
   70 static int _gl_error = 0;
   71 static gint32 normalmap_drawable_id = -1;
   72 static GtkWidget *window = 0;
   73 static GtkWidget *glarea = 0;
   74 static GtkWidget *rotate_obj_btn = 0;
   75 static GtkWidget *object_opt = 0;
   76 static GtkWidget *controls_table = 0;
   77 static GtkWidget *bumpmapping_opt = 0;
   78 static GtkWidget *specular_check = 0;
   79 static GtkWidget *gloss_opt = 0;
   80 static GtkWidget *specular_exp_range = 0;
   81 static GtkWidget *ambient_color_btn = 0;
   82 static GtkWidget *diffuse_color_btn = 0;
   83 static GtkWidget *specular_color_btn = 0;
   84 static GtkWidget *uvscale_spin1 = 0;
   85 static GtkWidget *uvscale_spin2 = 0;
   86 
   87 static int fullscreen = 0;
   88 
   89 static GLuint diffuse_tex = 0;
   90 static GLuint gloss_tex = 0;
   91 static GLuint normal_tex = 0;
   92 static GLuint white_tex = 0;
   93 
   94 static struct
   95 {
   96    float *verts;
   97    unsigned short *indices;
   98    unsigned int num_verts;
   99    unsigned int num_indices;
  100    GLuint vbo;
  101 } object_info[OBJECT_MAX] =
  102 {
  103    {quad_verts,   quad_indices,   QUAD_NUM_VERTS,   QUAD_NUM_INDICES,   0},
  104    {cube_verts,   cube_indices,   CUBE_NUM_VERTS,   CUBE_NUM_INDICES,   0},
  105    {sphere_verts, sphere_indices, SPHERE_NUM_VERTS, SPHERE_NUM_INDICES, 0},
  106    {torus_verts,  torus_indices,  TORUS_NUM_VERTS,  TORUS_NUM_INDICES,  0},
  107    {teapot_verts, teapot_indices, TEAPOT_NUM_VERTS, TEAPOT_NUM_INDICES, 0}
  108 };
  109 
  110 static const float anisotropy = 4.0f;
  111 
  112 static int has_glsl = 0;
  113 static int has_npot = 0;
  114 static int has_generate_mipmap = 0;
  115 static int has_aniso = 0;
  116 static int num_mtus = 0;
  117 
  118 static int max_instructions = 0;
  119 static int max_indirections = 0;
  120 
  121 static GLhandleARB programs[BUMPMAP_MAX];
  122 
  123 static const char *vert_source =
  124    "varying vec2 tex;\n"
  125    "varying vec3 vpos;\n"
  126    "varying vec3 normal;\n"
  127    "varying vec3 tangent;\n"
  128    "varying vec3 binormal;\n"
  129    "\n"
  130    "uniform vec2 uvscale;\n"
  131    "\n"
  132    "void main()\n"
  133    "{\n"
  134    "   gl_Position = ftransform();\n"
  135    "   tex = gl_MultiTexCoord0.xy * uvscale;\n"
  136    "   vpos = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
  137    "   tangent  = gl_NormalMatrix * gl_MultiTexCoord3.xyz;\n"
  138    "   binormal = gl_NormalMatrix * gl_MultiTexCoord4.xyz;\n"
  139    "   normal   = gl_NormalMatrix * gl_Normal;\n"
  140    "}\n";
  141 
  142 static const char *normal_frag_source =
  143    "varying vec2 tex;\n"
  144    "varying vec3 vpos;\n"
  145    "varying vec3 normal;\n"
  146    "varying vec3 tangent;\n"
  147    "varying vec3 binormal;\n"
  148 
  149    "uniform sampler2D sNormal;\n"
  150    "uniform sampler2D sDiffuse;\n"
  151    "uniform sampler2D sGloss;\n\n"
  152 
  153    "uniform vec3 lightDir;\n"
  154    "uniform bool specular;\n"
  155    "uniform float specular_exp;\n"
  156    "uniform vec3 ambient_color;\n"
  157    "uniform vec3 diffuse_color;\n"
  158    "uniform vec3 specular_color;\n\n"
  159 
  160    "void main()\n"
  161    "{\n"
  162    "   vec3 V = normalize(vpos);\n"
  163    "   vec3 N = texture2D(sNormal, tex).rgb * 2.0 - 1.0;\n"
  164    "   N = normalize(N.x * tangent + N.y * binormal + N.z * normal);\n"
  165    "   vec3 diffuse = texture2D(sDiffuse, tex).rgb;\n"
  166    "   float NdotL = clamp(dot(N, lightDir), 0.0, 1.0);\n"
  167    "   vec3 color = diffuse * diffuse_color * NdotL;\n"
  168    "   if(specular)\n"
  169    "   {\n"
  170    "      vec3 gloss = texture2D(sGloss, tex).rgb;\n"
  171    "      vec3 R = reflect(V, N);\n"
  172    "      float RdotL = clamp(dot(R, lightDir), 0.0, 1.0);\n"
  173    "      color += gloss * specular_color * pow(RdotL, specular_exp);\n"
  174    "   }\n"
  175    "   gl_FragColor.rgb = ambient_color * diffuse + color;\n"
  176    "}\n";
  177 
  178 static const char *parallax_frag_source =
  179    "varying vec2 tex;\n"
  180    "varying vec3 vpos;\n"
  181    "varying vec3 normal;\n"
  182    "varying vec3 tangent;\n"
  183    "varying vec3 binormal;\n"
  184 
  185    "uniform sampler2D sNormal;\n"
  186    "uniform sampler2D sDiffuse;\n"
  187    "uniform sampler2D sGloss;\n\n"
  188 
  189    "uniform vec3 lightDir;\n"
  190    "uniform bool specular;\n"
  191    "uniform float specular_exp;\n"
  192    "uniform vec3 ambient_color;\n"
  193    "uniform vec3 diffuse_color;\n"
  194    "uniform vec3 specular_color;\n\n"
  195 
  196    "void main()\n"
  197    "{\n"
  198    "   mat3 TBN = mat3(tangent, binormal, normal);\n"
  199    "   vec3 V = normalize(vpos);\n"
  200    "   vec3 V_ts = V * TBN;\n"
  201    "   float height = texture2D(sNormal, tex).a;\n"
  202    "   float offset = height * 0.025 - 0.0125;\n"
  203    "   vec2 tc = tex + offset * V_ts.xy;\n"
  204    "   height += texture2D(sNormal, tc).a;\n"
  205    "   offset = 0.025 * (height - 1.0);\n"
  206    "   tc = tex + offset * V_ts.xy;\n"
  207    "   vec3 N = texture2D(sNormal, tc).rgb * 2.0 - 1.0;\n"
  208    "   N = normalize(N.x * tangent + N.y * binormal + N.z * normal);\n"
  209    "   vec3 diffuse = texture2D(sDiffuse, tc).rgb;\n"
  210    "   float NdotL = clamp(dot(N, lightDir), 0.0, 1.0);\n"
  211    "   vec3 color = diffuse * diffuse_color * NdotL;\n"
  212    "   if(specular)\n"
  213    "   {\n"
  214    "      vec3 gloss = texture2D(sGloss, tc).rgb;\n"
  215    "      vec3 R = reflect(V, N);\n"
  216    "      float RdotL = clamp(dot(R, lightDir), 0.0, 1.0);\n"
  217    "      color += gloss * specular_color * pow(RdotL, specular_exp);\n"
  218    "   }\n"
  219    "   gl_FragColor.rgb = ambient_color * diffuse + color;\n"
  220    "}\n";
  221 
  222 static const char *pom_frag_source =
  223    "varying vec2 tex;\n"
  224    "varying vec3 vpos;\n"
  225    "varying vec3 normal;\n"
  226    "varying vec3 tangent;\n"
  227    "varying vec3 binormal;\n"
  228    "\n"
  229    "uniform sampler2D sNormal;\n"
  230    "uniform sampler2D sDiffuse;\n"
  231    "uniform sampler2D sGloss;\n"
  232    "\n"
  233    "uniform vec3 lightDir;\n"
  234    "uniform bool specular;\n"
  235    "uniform vec3 ambient_color;\n"
  236    "uniform vec3 diffuse_color;\n"
  237    "uniform vec3 specular_color;\n"
  238    "uniform float specular_exp;\n"
  239    "uniform vec2 planes;\n"
  240    "uniform float depth_factor;\n"
  241    "\n"
  242    "void ray_intersect(sampler2D reliefMap, inout vec4 p, inout vec3 v)\n"
  243    "{\n"
  244    "   const int search_steps = 20;\n"
  245    "\n"
  246    "   v /= float(search_steps);\n"
  247    "\n"
  248    "   vec4 pp = p;\n"
  249    "   for(int i = 0; i < search_steps - 1; ++i)\n"
  250    "   {\n"
  251    "      p.w = texture2D(reliefMap, p.xy).w;\n"
  252    "      if(p.w > p.z)\n"
  253    "      {\n"
  254    "         pp = p;\n"
  255    "         p.xyz += v;\n"
  256    "      }\n"
  257    "   }\n"
  258    "\n"
  259    "   float f = (pp.w - pp.z) / (p.z - pp.z - p.w + pp.w);\n"
  260    "   p = mix(pp, p, f);\n"
  261    "}\n"
  262    "\n"
  263    "void ray_intersect_ATI(sampler2D reliefMap, inout vec4 p, inout vec3 v)"
  264    "{\n"
  265    "   float h0 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 1.000).a;\n"
  266    "   float h1 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 0.875).a;\n"
  267    "   float h2 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 0.750).a;\n"
  268    "   float h3 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 0.625).a;\n"
  269    "   float h4 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 0.500).a;\n"
  270    "   float h5 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 0.375).a;\n"
  271    "   float h6 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 0.250).a;\n"
  272    "   float h7 = 1.0 - texture2D(reliefMap, p.xy + v.xy * 0.125).a;\n"
  273    "\n"
  274    "   float x, y, xh, yh;\n"
  275    "   if     (h7 > 0.875) { x = 0.937; y = 0.938; xh = h7; yh = h7; }\n"
  276    "   else if(h6 > 0.750) { x = 0.750; y = 0.875; xh = h6; yh = h7; }\n"
  277    "   else if(h5 > 0.625) { x = 0.625; y = 0.750; xh = h5; yh = h6; }\n"
  278    "   else if(h4 > 0.500) { x = 0.500; y = 0.625; xh = h4; yh = h5; }\n"
  279    "   else if(h3 > 0.375) { x = 0.375; y = 0.500; xh = h3; yh = h4; }\n"
  280    "   else if(h2 > 0.250) { x = 0.250; y = 0.375; xh = h2; yh = h3; }\n"
  281    "   else if(h1 > 0.125) { x = 0.125; y = 0.250; xh = h1; yh = h2; }\n"
  282    "   else                { x = 0.000; y = 0.125; xh = h0; yh = h1; }\n"
  283    "\n"
  284    "   float parallax = (x * (y - yh) - y * (x - xh)) / ((y - yh) - (x - xh));\n"
  285    "   p.xyz += v * (1.0 - parallax);\n"
  286    "}\n"
  287    "\n"
  288    "void main()\n"
  289    "{\n"
  290    "\n"
  291    "   vec3 V = normalize(vpos);\n"
  292    "   float a = dot(normal, -V);\n"
  293    "   vec3 v = vec3(dot(V, tangent), dot(V, binormal), a);\n"
  294    "   vec3 scale = vec3(1.0, 1.0, depth_factor);\n"
  295    "   v *= scale.z / (scale * v.z);\n"
  296    "   vec4 p = vec4(tex, vec2(0.0, 1.0));\n"
  297    "#ifdef ATI\n"
  298    "   ray_intersect_ATI(sNormal, p, v);\n"
  299    "#else\n"
  300    "   ray_intersect(sNormal, p, v);\n"
  301    "#endif\n"
  302    "\n"
  303    "   vec2 uv = p.xy;\n"
  304    "   vec3 N = texture2D(sNormal, uv).xyz * 2.0 - 1.0;\n"
  305    "   vec3 diffuse = texture2D(sDiffuse, uv).rgb;\n"
  306    "\n"
  307    "   N.z = sqrt(1.0 - dot(N.xy, N.xy));\n"
  308    "   N = normalize(N.x * tangent + N.y * binormal + N.z * normal);\n"
  309    "\n"
  310    "   float NdotL = clamp(dot(N, lightDir), 0.0, 1.0);\n"
  311    "\n"
  312    "   vec3 color = diffuse * diffuse_color * NdotL;\n"
  313    "\n"
  314    "   if(specular)\n"
  315    "   {\n"
  316    "      vec3 gloss = texture2D(sGloss, uv).rgb;\n"
  317    "      vec3 R = reflect(V, N);\n"
  318    "      float RdotL = clamp(dot(R, lightDir), 0.0, 1.0);\n"
  319    "      color += gloss * specular_color * pow(RdotL, specular_exp);\n"
  320    "   }\n"
  321    "\n"
  322    "   gl_FragColor.rgb = ambient_color * diffuse + color;\n"
  323    "}\n";
  324 
  325 static const char *relief_frag_source =
  326    "varying vec2 tex;\n"
  327    "varying vec3 vpos;\n"
  328    "varying vec3 normal;\n"
  329    "varying vec3 tangent;\n"
  330    "varying vec3 binormal;\n"
  331    "\n"
  332    "uniform sampler2D sNormal;\n"
  333    "uniform sampler2D sDiffuse;\n"
  334    "uniform sampler2D sGloss;\n"
  335    "\n"
  336    "uniform vec3 lightDir;\n"
  337    "uniform bool specular;\n"
  338    "uniform vec3 ambient_color;\n"
  339    "uniform vec3 diffuse_color;\n"
  340    "uniform vec3 specular_color;\n"
  341    "uniform float specular_exp;\n"
  342    "uniform vec2 planes;\n"
  343    "uniform float depth_factor;\n"
  344    "\n"
  345    "float ray_intersect(sampler2D reliefMap, vec2 dp, vec2 ds)\n"
  346    "{\n"
  347    "   const int linear_search_steps = 20;\n"
  348    "\n"
  349    "   float size = 1.0 / float(linear_search_steps);\n"
  350    "   float depth = 0.0;\n"
  351    "   float best_depth = 1.0;\n"
  352    "\n"
  353    "   for(int i = 0; i < linear_search_steps - 1; ++i)\n"
  354    "   {\n"
  355    "      depth += size;\n"
  356    "      float t = texture2D(reliefMap, dp + ds * depth).a;\n"
  357    "      if(best_depth > 0.996)\n"
  358    "         if(depth >= t)\n"
  359    "            best_depth = depth;\n"
  360    "   }\n"
  361    "   depth = best_depth;\n"
  362    "\n"
  363    "   const int binary_search_steps = 5;\n"
  364    "\n"
  365    "   for(int i = 0; i < binary_search_steps; ++i)\n"
  366    "   {\n"
  367    "      size *= 0.5;\n"
  368    "      float t = texture2D(reliefMap, dp + ds * depth).a;\n"
  369    "      if(depth >= t)\n"
  370    "      {\n"
  371    "         best_depth = depth;\n"
  372    "         depth -= 2.0 * size;\n"
  373    "      }\n"
  374    "      depth += size;\n"
  375    "   }\n"
  376    "\n"
  377    "   return(best_depth);\n"
  378    "}\n"
  379    "\n"
  380    "void main()\n"
  381    "{\n"
  382    "\n"
  383    "   vec3 V = normalize(vpos);\n"
  384    "   float a = dot(normal, -V);\n"
  385    "   vec2 s = vec2(dot(V, tangent), dot(V, binormal));\n"
  386    "   s *= depth_factor / a;\n"
  387    "   vec2 ds = s;\n"
  388    "   vec2 dp = tex;\n"
  389    "   float d = ray_intersect(sNormal, dp, ds);\n"
  390    "\n"
  391    "   vec2 uv = dp + ds * d;\n"
  392    "   vec3 N = texture2D(sNormal, uv).xyz * 2.0 - 1.0;\n"
  393    "   vec3 diffuse = texture2D(sDiffuse, uv).rgb;\n"
  394    "\n"
  395    "   N.z = sqrt(1.0 - dot(N.xy, N.xy));\n"
  396    "   N = normalize(N.x * tangent + N.y * binormal + N.z * normal);\n"
  397    "\n"
  398    "   float NdotL = clamp(dot(N, lightDir), 0.0, 1.0);\n"
  399    "\n"
  400    "   vec3 color = diffuse * diffuse_color * NdotL;\n"
  401    "\n"
  402    "   if(specular)\n"
  403    "   {\n"
  404    "      vec3 gloss = texture2D(sGloss, uv).rgb;\n"
  405    "      vec3 R = reflect(V, N);\n"
  406    "      float RdotL = clamp(dot(R, lightDir), 0.0, 1.0);\n"
  407    "      color += gloss * specular_color * pow(RdotL, specular_exp);\n"
  408    "   }\n"
  409    "\n"
  410    "   gl_FragColor.rgb = ambient_color * diffuse + color;\n"
  411    "}\n";
  412 
  413 static int bumpmapping = BUMPMAP_NORMAL;
  414 static int specular = 0;
  415 static int rotate_type = ROTATE_OBJECT;
  416 static int object_type = OBJECT_QUAD;
  417 
  418 static vec3 ambient_color = {0.2f, 0.2f, 0.2f};
  419 static vec3 diffuse_color = {1, 1, 1};
  420 static vec3 specular_color = {1, 1, 1};
  421 static float specular_exp = 32.0f;
  422 static vec3 uvscale = {1, 1};
  423 
  424 static const float depth_factor = 0.05f;
  425 
  426 static int mx;
  427 static int my;
  428 static vec3 object_rot;
  429 static vec3 light_rot;
  430 static vec3 scene_rot;
  431 static float zoom;
  432 
  433 #define M(r,c) m[(c << 2) + r]
  434 #define T(r,c) t[(c << 2) + r]
  435 
  436 static void mat_invert(matrix m)
  437 {
  438    float invdet;
  439    matrix t;
  440 
  441    invdet = (float)1.0 / (M(0, 0) * (M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1)) -
  442                           M(0, 1) * (M(1, 0) * M(2, 2) - M(1, 2) * M(2, 0)) +
  443                           M(0, 2) * (M(1, 0) * M(2, 1) - M(1, 1) * M(2, 0)));
  444 
  445    T(0,0) =  invdet * (M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1));
  446    T(0,1) = -invdet * (M(0, 1) * M(2, 2) - M(0, 2) * M(2, 1));
  447    T(0,2) =  invdet * (M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1));
  448    T(0,3) = 0;
  449 
  450    T(1,0) = -invdet * (M(1, 0) * M(2, 2) - M(1, 2) * M(2, 0));
  451    T(1,1) =  invdet * (M(0, 0) * M(2, 2) - M(0, 2) * M(2, 0));
  452    T(1,2) = -invdet * (M(0, 0) * M(1, 2) - M(0, 2) * M(1, 0));
  453    T(1,3) = 0;
  454 
  455    T(2,0) =  invdet * (M(1, 0) * M(2, 1) - M(1, 1) * M(2, 0));
  456    T(2,1) = -invdet * (M(0, 0) * M(2, 1) - M(0, 1) * M(2, 0));
  457    T(2,2) =  invdet * (M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0));
  458    T(2,3) = 0;
  459 
  460    T(3,0) = -(M(3, 0) * T(0, 0) + M(3, 1) * T(1, 0) + M(3, 2) * T(2, 0));
  461    T(3,1) = -(M(3, 0) * T(0, 1) + M(3, 1) * T(1, 1) + M(3, 2) * T(2, 1));
  462    T(3,2) = -(M(3, 0) * T(0, 2) + M(3, 1) * T(1, 2) + M(3, 2) * T(2, 2));
  463    T(3,3) = 1;
  464 
  465    memcpy(m, t, 16 * sizeof(float));
  466 }
  467 
  468 static void mat_transpose(matrix m)
  469 {
  470    matrix t;
  471    t[0 ] = m[0 ]; t[1 ] = m[4 ]; t[2 ] = m[8 ]; t[3 ] = m[12];
  472    t[4 ] = m[1 ]; t[5 ] = m[5 ]; t[6 ] = m[9 ]; t[7 ] = m[13];
  473    t[8 ] = m[2 ]; t[9 ] = m[6 ]; t[10] = m[10]; t[11] = m[14];
  474    t[12] = m[3 ]; t[13] = m[7 ]; t[14] = m[11]; t[15] = m[15];
  475    memcpy(m, t, sizeof(matrix));
  476 }
  477 
  478 static void mat_mult_vec(vec3 v, matrix m)
  479 {
  480    vec3 t;
  481    t[0] = M(0, 0) * v[0] + M(0, 1) * v[1] + M(0, 2) * v[2];
  482    t[1] = M(1, 0) * v[0] + M(1, 1) * v[1] + M(1, 2) * v[2];
  483    t[2] = M(2, 0) * v[0] + M(2, 1) * v[1] + M(2, 2) * v[2];
  484 
  485    v[0] = t[0];
  486    v[1] = t[1];
  487    v[2] = t[2];
  488 }
  489 
  490 static inline void vec3_set(vec3 v, float x, float y, float z)
  491 {
  492    v[0] = x;
  493    v[1] = y;
  494    v[2] = z;
  495 }
  496 
  497 static inline void vec3_copy(vec3 r, vec3 v)
  498 {
  499    r[0] = v[0];
  500    r[1] = v[1];
  501    r[2] = v[2];
  502 }
  503 
  504 static void vec4_normalize(vec4 r, vec4 v)
  505 {
  506    float len = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
  507    if(len != 0)
  508    {
  509       float ilen = 1.0f / len;
  510       r[0] = v[0] * ilen;
  511       r[1] = v[1] * ilen;
  512       r[2] = v[2] * ilen;
  513       r[3] = v[3] * ilen;
  514    }
  515    else
  516       r[0] = r[1] = r[2] = r[3] = 0;
  517 }
  518 
  519 static void vec3_normalize(vec3 r, vec3 v)
  520 {
  521    float len = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  522    if(len != 0.0f)
  523    {
  524       float ilen = 1.0f / len;
  525       r[0] = v[0] * ilen;
  526       r[1] = v[1] * ilen;
  527       r[2] = v[2] * ilen;
  528    }
  529    else
  530       r[0] = r[1] = r[2] = 0;
  531 }
  532 
  533 static inline void quat_ident(vec4 q)
  534 {
  535    q[0] = q[1] = q[2] = 0;
  536    q[3] = 1;
  537 }
  538 
  539 static void quat_mul(vec4 r, vec4 a, vec4 b)
  540 {
  541    r[0] = a[0] * b[3] + b[0] * a[3] + a[1] * b[2] - a[2] * b[1];
  542    r[1] = a[1] * b[3] + b[1] * a[3] + a[2] * b[0] - a[0] * b[2];
  543    r[2] = a[2] * b[3] + b[2] * a[3] + a[0] * b[1] - a[1] * b[0];
  544    r[3] = a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2];
  545 }
  546 
  547 static void quat_rotate(vec4 q, float a, float x, float y, float z)
  548 {
  549    float hs, len, ilen;
  550 
  551    len = sqrtf(x * x + y * y + z * z);
  552    if(len == 0) return;
  553    ilen = 1.0f / len;
  554    x *= ilen;
  555    y *= ilen;
  556    z *= ilen;
  557 
  558    a = (a * (M_PI / 180.0f)) * 0.5f;
  559 
  560    hs = sinf(a);
  561    q[0] = x * hs;
  562    q[1] = y * hs;
  563    q[2] = z * hs;
  564    q[3] = cosf(a);
  565 }
  566 
  567 static void quat_get_direction(vec3 v, vec4 q)
  568 {
  569    v[0] = 2.0f * (q[0] * q[2] - q[3] * q[1]);
  570    v[1] = 2.0f * (q[1] * q[2] + q[3] * q[0]);
  571    v[2] = 1.0f - 2.0f * (q[0] * q[0] + q[1] * q[1]);
  572 }
  573 
  574 #undef M
  575 #undef T
  576 
  577 static void init(GtkWidget *widget, gpointer data)
  578 {
  579    int i, err;
  580    unsigned char white[16] = {0xff, 0xff, 0xff, 0xff,
  581                               0xff, 0xff, 0xff, 0xff,
  582                               0xff, 0xff, 0xff, 0xff,
  583                               0xff, 0xff, 0xff, 0xff};
  584    GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
  585    GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
  586    GtkWidget *menu;
  587    GList *curr;
  588 
  589    if(!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
  590       return;
  591 
  592    err = glewInit();
  593    if(err != GLEW_OK)
  594    {
  595       g_message((char*)glewGetErrorString(err));
  596       _gl_error = 1;
  597    }
  598 
  599    glClearColor(0, 0, 0.4f, 0);
  600    glDepthFunc(GL_LEQUAL);
  601    glEnable(GL_DEPTH_TEST);
  602 
  603    glLineWidth(3);
  604 
  605    _gl_error = 0;
  606 
  607    if(!GLEW_ARB_multitexture)
  608    {
  609       g_message("GL_ARB_multitexture is required for the 3D preview");
  610       _gl_error = 1;
  611    }
  612 
  613    if(!GLEW_ARB_texture_env_combine)
  614    {
  615       g_message("GL_ARB_texture_env_combine is required for the 3D preview");
  616       _gl_error = 1;
  617    }
  618 
  619    if(!GLEW_ARB_texture_env_dot3)
  620    {
  621       g_message("GL_ARB_texture_env_dot3 is required for the 3D preview");
  622       _gl_error = 1;
  623    }
  624 
  625    if(_gl_error) return;
  626 
  627    glGenTextures(1, &diffuse_tex);
  628    glGenTextures(1, &gloss_tex);
  629    glGenTextures(1, &normal_tex);
  630    glGenTextures(1, &white_tex);
  631 
  632    glGetIntegerv(GL_MAX_TEXTURE_UNITS, &num_mtus);
  633 
  634    glActiveTexture(GL_TEXTURE0);
  635    glEnable(GL_TEXTURE_2D);
  636    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  637    glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
  638    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
  639    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
  640    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
  641    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
  642 
  643    glActiveTexture(GL_TEXTURE1);
  644    glEnable(GL_TEXTURE_2D);
  645    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  646    glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
  647    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
  648    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
  649    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
  650    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
  651 
  652    glBindTexture(GL_TEXTURE_2D, white_tex);
  653    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  654    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  655    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  656    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  657    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0,
  658                 GL_LUMINANCE, GL_UNSIGNED_BYTE, white);
  659 
  660    if(num_mtus > 2)
  661    {
  662       glActiveTexture(GL_TEXTURE2);
  663       glEnable(GL_TEXTURE_2D);
  664       glBindTexture(GL_TEXTURE_2D, white_tex);
  665    }
  666 
  667    has_glsl = GLEW_ARB_shader_objects && GLEW_ARB_vertex_shader &&
  668       GLEW_ARB_fragment_shader;
  669    has_npot = GLEW_ARB_texture_non_power_of_two;
  670    has_generate_mipmap = GLEW_SGIS_generate_mipmap;
  671    has_aniso = GLEW_EXT_texture_filter_anisotropic;
  672 
  673    if(has_glsl)
  674    {
  675       GLhandleARB prog, vert_shader, frag_shader;
  676       int res, len, loc;
  677       const char *sources[2];
  678       char *info;
  679 
  680       /* Get max # of instructions and indirections supported by the hardware.
  681        * Used to determine if parallax occlusion and relief mapping should be
  682        * enabled and if the "ATI" version of parallax occlusion mapping should
  683        * be used.
  684        */
  685       if(GLEW_ARB_fragment_program)
  686       {
  687          glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 1);
  688          glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
  689                            GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB,
  690                            &max_instructions);
  691          glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
  692                            GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB,
  693                            &max_indirections);
  694          glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
  695       }
  696 
  697       vert_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
  698       glShaderSourceARB(vert_shader, 1, &vert_source, 0);
  699       glCompileShaderARB(vert_shader);
  700       glGetObjectParameterivARB(vert_shader, GL_OBJECT_COMPILE_STATUS_ARB, &res);
  701       if(!res)
  702       {
  703          glGetObjectParameterivARB(vert_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  704          info = g_malloc(len + 1);
  705          glGetInfoLogARB(vert_shader, len, 0, info);
  706          g_message("Vertex shader failed to compile:\n%s\n", info);
  707          g_free(info);
  708       }
  709 
  710       prog = glCreateProgramObjectARB();
  711       glAttachObjectARB(prog, vert_shader);
  712 
  713       frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
  714       glShaderSourceARB(frag_shader, 1, &normal_frag_source, 0);
  715       glCompileShaderARB(frag_shader);
  716       glGetObjectParameterivARB(frag_shader, GL_OBJECT_COMPILE_STATUS_ARB, &res);
  717       if(res)
  718          glAttachObjectARB(prog, frag_shader);
  719       else
  720       {
  721          glGetObjectParameterivARB(frag_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  722          info = g_malloc(len + 1);
  723          glGetInfoLogARB(frag_shader, len, 0, info);
  724          g_message("Normal mapping fragment shader failed to compile:\n%s\n",
  725                    info);
  726          g_free(info);
  727          glDeleteObjectARB(prog);
  728          prog = 0;
  729       }
  730       glDeleteObjectARB(frag_shader);
  731 
  732       if(prog)
  733       {
  734          glLinkProgramARB(prog);
  735          glGetObjectParameterivARB(prog, GL_OBJECT_LINK_STATUS_ARB, &res);
  736 
  737          if(!res)
  738          {
  739             glGetObjectParameterivARB(prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  740             info = g_malloc(len + 1);
  741             glGetInfoLogARB(prog, len, 0, info);
  742             g_message("Normal mapping program failed to link:\n%s\n", info);
  743             g_free(info);
  744             glDeleteObjectARB(prog);
  745             prog = 0;
  746          }
  747       }
  748 
  749       programs[BUMPMAP_NORMAL] = prog;
  750 
  751       prog = glCreateProgramObjectARB();
  752       glAttachObjectARB(prog, vert_shader);
  753 
  754       frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
  755       glShaderSourceARB(frag_shader, 1, &parallax_frag_source, 0);
  756       glCompileShaderARB(frag_shader);
  757       glGetObjectParameterivARB(frag_shader, GL_OBJECT_COMPILE_STATUS_ARB, &res);
  758       if(res)
  759          glAttachObjectARB(prog, frag_shader);
  760       else
  761       {
  762          glGetObjectParameterivARB(frag_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  763          info = g_malloc(len + 1);
  764          glGetInfoLogARB(frag_shader, len, 0, info);
  765          g_message("Parallax mapping fragment shader failed to compile:\n%s\n",
  766                    info);
  767          g_free(info);
  768          glDeleteObjectARB(prog);
  769          prog = 0;
  770       }
  771       glDeleteObjectARB(frag_shader);
  772 
  773       if(prog)
  774       {
  775          glLinkProgramARB(prog);
  776          glGetObjectParameterivARB(prog, GL_OBJECT_LINK_STATUS_ARB, &res);
  777 
  778          if(!res)
  779          {
  780             glGetObjectParameterivARB(prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  781             info = g_malloc(len + 1);
  782             glGetInfoLogARB(prog, len, 0, info);
  783             g_message("Parallax mapping program failed to link:\n%s\n", info);
  784             g_free(info);
  785             glDeleteObjectARB(prog);
  786             prog = 0;
  787          }
  788       }
  789 
  790       programs[BUMPMAP_PARALLAX] = prog;
  791 
  792       if(max_instructions >= 200)
  793       {
  794          prog = glCreateProgramObjectARB();
  795          glAttachObjectARB(prog, vert_shader);
  796 
  797          if(max_indirections < 100)
  798             sources[0] = "#define ATI 1\n";
  799          else
  800             sources[0] = "";
  801 
  802          sources[1] = pom_frag_source;
  803 
  804          frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
  805          glShaderSourceARB(frag_shader, 2, sources, 0);
  806          glCompileShaderARB(frag_shader);
  807          glGetObjectParameterivARB(frag_shader, GL_OBJECT_COMPILE_STATUS_ARB, &res);
  808          if(res)
  809             glAttachObjectARB(prog, frag_shader);
  810          else
  811          {
  812             glGetObjectParameterivARB(frag_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  813             info = g_malloc(len + 1);
  814             glGetInfoLogARB(frag_shader, len, 0, info);
  815             g_message("Parallax Occlusion mapping fragment shader failed to compile:\n%s\n",
  816                       info);
  817             g_free(info);
  818             glDeleteObjectARB(prog);
  819             prog = 0;
  820          }
  821          glDeleteObjectARB(frag_shader);
  822 
  823          if(prog)
  824          {
  825             glLinkProgramARB(prog);
  826             glGetObjectParameterivARB(prog, GL_OBJECT_LINK_STATUS_ARB, &res);
  827 
  828             if(!res)
  829             {
  830                glGetObjectParameterivARB(prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  831                info = g_malloc(len + 1);
  832                glGetInfoLogARB(prog, len, 0, info);
  833                g_message("Parallax Occlusion mapping program failed to link:\n%s\n",
  834                          info);
  835                g_free(info);
  836                glDeleteObjectARB(prog);
  837                prog = 0;
  838             }
  839          }
  840 
  841          programs[BUMPMAP_POM] = prog;
  842       }
  843       else
  844          programs[BUMPMAP_POM] = 0;
  845 
  846       if(max_instructions >= 200 && max_indirections >= 100)
  847       {
  848          prog = glCreateProgramObjectARB();
  849          glAttachObjectARB(prog, vert_shader);
  850 
  851          frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
  852          glShaderSourceARB(frag_shader, 1, &relief_frag_source, 0);
  853          glCompileShaderARB(frag_shader);
  854          glGetObjectParameterivARB(frag_shader, GL_OBJECT_COMPILE_STATUS_ARB, &res);
  855          if(res)
  856             glAttachObjectARB(prog, frag_shader);
  857          else
  858          {
  859             glGetObjectParameterivARB(frag_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  860             info = g_malloc(len + 1);
  861             glGetInfoLogARB(frag_shader, len, 0, info);
  862             g_message("Relief mapping fragment shader failed to compile:\n%s\n",
  863                       info);
  864             g_free(info);
  865             glDeleteObjectARB(prog);
  866             prog = 0;
  867          }
  868          glDeleteObjectARB(frag_shader);
  869 
  870          if(prog)
  871          {
  872             glLinkProgramARB(prog);
  873             glGetObjectParameterivARB(prog, GL_OBJECT_LINK_STATUS_ARB, &res);
  874 
  875             if(!res)
  876             {
  877                glGetObjectParameterivARB(prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len);
  878                info = g_malloc(len + 1);
  879                glGetInfoLogARB(prog, len, 0, info);
  880                g_message("Relief mapping program failed to link:\n%s\n", info);
  881                g_free(info);
  882                glDeleteObjectARB(prog);
  883                prog = 0;
  884             }
  885          }
  886 
  887          programs[BUMPMAP_RELIEF] = prog;
  888       }
  889       else
  890          programs[BUMPMAP_RELIEF] = 0;
  891 
  892       glDeleteObjectARB(vert_shader);
  893 
  894       if(programs[BUMPMAP_NORMAL])
  895       {
  896          glUseProgramObjectARB(programs[BUMPMAP_NORMAL]);
  897          loc = glGetUniformLocationARB(programs[BUMPMAP_NORMAL], "sNormal");
  898          glUniform1iARB(loc, 0);
  899          loc = glGetUniformLocationARB(programs[BUMPMAP_NORMAL], "sDiffuse");
  900          glUniform1iARB(loc, 1);
  901          loc = glGetUniformLocationARB(programs[BUMPMAP_NORMAL], "sGloss");
  902          glUniform1iARB(loc, 2);
  903       }
  904 
  905       if(programs[BUMPMAP_PARALLAX])
  906       {
  907          glUseProgramObjectARB(programs[BUMPMAP_PARALLAX]);
  908          loc = glGetUniformLocationARB(programs[BUMPMAP_PARALLAX], "sNormal");
  909          glUniform1iARB(loc, 0);
  910          loc = glGetUniformLocationARB(programs[BUMPMAP_PARALLAX], "sDiffuse");
  911          glUniform1iARB(loc, 1);
  912          loc = glGetUniformLocationARB(programs[BUMPMAP_PARALLAX], "sGloss");
  913          glUniform1iARB(loc, 2);
  914       }
  915 
  916       if(programs[BUMPMAP_POM])
  917       {
  918          glUseProgramObjectARB(programs[BUMPMAP_POM]);
  919          loc = glGetUniformLocationARB(programs[BUMPMAP_POM], "sNormal");
  920          glUniform1iARB(loc, 0);
  921          loc = glGetUniformLocationARB(programs[BUMPMAP_POM], "sDiffuse");
  922          glUniform1iARB(loc, 1);
  923          loc = glGetUniformLocationARB(programs[BUMPMAP_POM], "sGloss");
  924          glUniform1iARB(loc, 2);
  925          loc = glGetUniformLocationARB(programs[BUMPMAP_POM], "depth_factor");
  926          glUniform1fARB(loc, depth_factor);
  927       }
  928 
  929       if(programs[BUMPMAP_RELIEF])
  930       {
  931          glUseProgramObjectARB(programs[BUMPMAP_RELIEF]);
  932          loc = glGetUniformLocationARB(programs[BUMPMAP_RELIEF], "sNormal");
  933          glUniform1iARB(loc, 0);
  934          loc = glGetUniformLocationARB(programs[BUMPMAP_RELIEF], "sDiffuse");
  935          glUniform1iARB(loc, 1);
  936          loc = glGetUniformLocationARB(programs[BUMPMAP_RELIEF], "sGloss");
  937          glUniform1iARB(loc, 2);
  938          loc = glGetUniformLocationARB(programs[BUMPMAP_RELIEF], "depth_factor");
  939          glUniform1fARB(loc, depth_factor);
  940       }
  941 
  942       glUseProgramObjectARB(0);
  943 
  944       for(i = 0; i < OBJECT_MAX; ++i)
  945       {
  946          glGenBuffersARB(1, &object_info[i].vbo);
  947          glBindBufferARB(GL_ARRAY_BUFFER_ARB, object_info[i].vbo);
  948          glBufferDataARB(GL_ARRAY_BUFFER_ARB,
  949                          object_info[i].num_verts * 16 * sizeof(float),
  950                          object_info[i].verts, GL_STATIC_DRAW_ARB);
  951       }
  952 
  953       glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
  954 
  955       menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(bumpmapping_opt));
  956       curr = gtk_container_get_children(GTK_CONTAINER(menu));
  957       for(i = 0; i < BUMPMAP_MAX && curr; ++i)
  958       {
  959          if(programs[i] == 0)
  960             gtk_widget_set_sensitive(GTK_WIDGET(curr->data), 0);
  961          curr = curr->next;
  962       }
  963    }
  964    else
  965    {
  966       gtk_widget_set_sensitive(gloss_opt, 0);
  967       gtk_widget_set_sensitive(bumpmapping_opt, 0);
  968       gtk_widget_set_sensitive(specular_check, 0);
  969       gtk_widget_set_sensitive(specular_exp_range, 0);
  970       gtk_widget_set_sensitive(ambient_color_btn, 0);
  971       gtk_widget_set_sensitive(diffuse_color_btn, 0);
  972       gtk_widget_set_sensitive(specular_color_btn, 0);
  973    }
  974 
  975    object_rot[0] = object_rot[1] = object_rot[2] = 0;
  976    light_rot[0] = light_rot[1] = light_rot[2] = 0;
  977    scene_rot[0] = scene_rot[1] = scene_rot[2] = 0;
  978    zoom = 2;
  979 
  980    gdk_gl_drawable_gl_end(gldrawable);
  981 }
  982 
  983 static void draw_object(int obj, vec3 l, matrix m)
  984 {
  985    const int vsize = 16 * sizeof(float);
  986    int i;
  987    vec3 c, t, b, n;
  988    vec2 uv;
  989    float *verts;
  990    unsigned short *indices;
  991 
  992    if(obj < 0 || obj >= OBJECT_MAX) return;
  993 
  994    if(has_glsl)
  995    {
  996       glBindBufferARB(GL_ARRAY_BUFFER_ARB, object_info[obj].vbo);
  997 
  998 #define OFFSET(x) ((void*)((x) * sizeof(float)))
  999 
 1000       glVertexPointer(4, GL_FLOAT, vsize, OFFSET(0));
 1001       glNormalPointer(GL_FLOAT, vsize, OFFSET(12));
 1002       glClientActiveTexture(GL_TEXTURE4);
 1003       glTexCoordPointer(3, GL_FLOAT, vsize, OFFSET(9));
 1004       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 1005       glClientActiveTexture(GL_TEXTURE3);
 1006       glTexCoordPointer(3, GL_FLOAT, vsize, OFFSET(6));
 1007       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 1008       glClientActiveTexture(GL_TEXTURE0);
 1009       glTexCoordPointer(2, GL_FLOAT, vsize, OFFSET(4));
 1010       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 1011       glEnableClientState(GL_VERTEX_ARRAY);
 1012       glEnableClientState(GL_NORMAL_ARRAY);
 1013 
 1014 #undef OFFSET
 1015 
 1016       glDrawElements(GL_TRIANGLES, object_info[obj].num_indices,
 1017                      GL_UNSIGNED_SHORT, object_info[obj].indices);
 1018 
 1019       glDisableClientState(GL_VERTEX_ARRAY);
 1020       glDisableClientState(GL_NORMAL_ARRAY);
 1021       glClientActiveTexture(GL_TEXTURE4);
 1022       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 1023       glClientActiveTexture(GL_TEXTURE3);
 1024       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 1025       glClientActiveTexture(GL_TEXTURE0);
 1026       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 1027 
 1028       glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 1029    }
 1030    else
 1031    {
 1032       verts = object_info[obj].verts;
 1033       indices = object_info[obj].indices;
 1034 
 1035       glBegin(GL_TRIANGLES);
 1036       for(i = 0; i < object_info[obj].num_indices; ++i)
 1037       {
 1038          vec3_copy(t, &verts[16 * indices[i] +  6]);
 1039          vec3_copy(b, &verts[16 * indices[i] +  9]);
 1040          vec3_copy(n, &verts[16 * indices[i] + 12]);
 1041          mat_mult_vec(t, m);
 1042          mat_mult_vec(b, m);
 1043          mat_mult_vec(n, m);
 1044          c[0] = (l[0] * t[0] + l[1] * t[1] + l[2] * t[2]);
 1045          c[1] = (l[0] * b[0] + l[1] * b[1] + l[2] * b[2]);
 1046          c[2] = (l[0] * n[0] + l[1] * n[1] + l[2] * n[2]);
 1047          vec3_normalize(c, c);
 1048          c[0] = c[0] * 0.5f + 0.5f;
 1049          c[1] = c[1] * 0.5f + 0.5f;
 1050          c[2] = c[2] * 0.5f + 0.5f;
 1051 
 1052          uv[0] = verts[16 * indices[i] + 4] * uvscale[0];
 1053          uv[1] = verts[16 * indices[i] + 5] * uvscale[1];
 1054 
 1055          glColor3fv(c);
 1056          glNormal3fv(&verts[16 * indices[i] + 12]);
 1057          glMultiTexCoord2fv(GL_TEXTURE0, uv);
 1058          glMultiTexCoord2fv(GL_TEXTURE1, uv);
 1059          if(num_mtus > 2)
 1060             glMultiTexCoord2fv(GL_TEXTURE2, uv);
 1061          glVertex3fv(&verts[16 * indices[i]]);
 1062       }
 1063       glEnd();
 1064    }
 1065 }
 1066 
 1067 static gint expose(GtkWidget *widget, GdkEventExpose *event)
 1068 {
 1069    matrix m;
 1070    vec3 l;
 1071    vec4 qx, qy, qz, qt, qrot;
 1072    int loc;
 1073    GdkGLContext *glcontext = gtk_widget_get_gl_context(widget);
 1074    GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
 1075    GLhandleARB prog = 0;
 1076 
 1077    if(event->count > 0) return(1);
 1078 
 1079    if(!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
 1080       return(1);
 1081 
 1082    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 1083 
 1084    if(_gl_error)
 1085    {
 1086       gdk_gl_drawable_swap_buffers(gldrawable);
 1087       gdk_gl_drawable_gl_end(gldrawable);
 1088       return(1);
 1089    }
 1090 
 1091    glMatrixMode(GL_MODELVIEW);
 1092    glLoadIdentity();
 1093    glRotatef(scene_rot[0], 1, 0, 0);
 1094    glRotatef(scene_rot[1], 0, 1, 0);
 1095    glRotatef(scene_rot[2], 0, 0, 1);
 1096    glTranslatef(0, 0, -zoom);
 1097    glRotatef(object_rot[0], 1, 0, 0);
 1098    glRotatef(object_rot[1], 0, 1, 0);
 1099    glRotatef(object_rot[2], 0, 0, 1);
 1100 
 1101    glGetFloatv(GL_MODELVIEW_MATRIX, m);
 1102    mat_invert(m);
 1103    mat_transpose(m);
 1104 
 1105    quat_ident(qx);
 1106    quat_ident(qy);
 1107    quat_ident(qz);
 1108    quat_rotate(qx, -light_rot[0], 1, 0, 0);
 1109    quat_rotate(qy, -light_rot[1], 0, 1, 0);
 1110    quat_rotate(qz, -light_rot[2], 0, 0, 1);
 1111    quat_mul(qt, qx, qy);
 1112    quat_mul(qrot, qt, qz);
 1113    vec4_normalize(qrot, qrot);
 1114    quat_get_direction(l, qrot);
 1115 
 1116    if(has_glsl)
 1117    {
 1118       prog = programs[bumpmapping];
 1119       glUseProgramObjectARB(prog);
 1120       loc = glGetUniformLocationARB(prog, "specular");
 1121       glUniform1iARB(loc, specular);
 1122       loc = glGetUniformLocationARB(prog, "ambient_color");
 1123       glUniform3fvARB(loc, 1, ambient_color);
 1124       loc = glGetUniformLocationARB(prog, "diffuse_color");
 1125       glUniform3fvARB(loc, 1, diffuse_color);
 1126       loc = glGetUniformLocationARB(prog, "specular_color");
 1127       glUniform3fvARB(loc, 1, specular_color);
 1128       loc = glGetUniformLocationARB(prog, "specular_exp");
 1129       glUniform1fARB(loc, specular_exp);
 1130       loc = glGetUniformLocationARB(prog, "lightDir");
 1131       glUniform3fvARB(loc, 1, l);
 1132       loc = glGetUniformLocationARB(prog, "uvscale");
 1133       glUniform2fvARB(loc, 1, uvscale);
 1134    }
 1135 
 1136    draw_object(object_type, l, m);
 1137 
 1138    if(has_glsl)
 1139       glUseProgramObjectARB(0);
 1140 
 1141    gdk_gl_drawable_swap_buffers(gldrawable);
 1142    gdk_gl_drawable_gl_end(gldrawable);
 1143 
 1144    return(1);
 1145 }
 1146 
 1147 static gint configure(GtkWidget *widget, GdkEventConfigure *event)
 1148 {
 1149    GdkGLContext *glcontext;
 1150    GdkGLDrawable *gldrawable;
 1151    int w, h;
 1152 
 1153    g_return_val_if_fail(widget && event, FALSE);
 1154 
 1155    glcontext = gtk_widget_get_gl_context(widget);
 1156    gldrawable = gtk_widget_get_gl_drawable(widget);
 1157 
 1158    if(!gdk_gl_drawable_gl_begin(gldrawable,glcontext))
 1159       return(1);
 1160 
 1161    w = widget->allocation.width;
 1162    h = widget->allocation.height;
 1163 
 1164    glViewport(0, 0, w, h);
 1165 
 1166    glMatrixMode(GL_PROJECTION);
 1167    glLoadIdentity();
 1168    gluPerspective(60, (float)w / (float)h, 0.1f, 100);
 1169 
 1170    glMatrixMode(GL_MODELVIEW);
 1171    glLoadIdentity();
 1172 
 1173    gdk_gl_drawable_gl_end(gldrawable);
 1174 
 1175    return(1);
 1176 }
 1177 
 1178 static gint button_press(GtkWidget *widget, GdkEventButton *event)
 1179 {
 1180    mx = event->x;
 1181    my = event->y;
 1182    return(1);
 1183 }
 1184 
 1185 static gint motion_notify(GtkWidget *widget, GdkEventMotion *event)
 1186 {
 1187    int x, y;
 1188    float dx, dy;
 1189    float *rot;
 1190    GdkModifierType state;
 1191 
 1192    if(event->is_hint)
 1193    {
 1194 #ifndef WIN32
 1195       gdk_window_get_pointer(event->window, &x, &y, &state);
 1196 #endif
 1197    }
 1198    else
 1199    {
 1200       x = event->x;
 1201       y = event->y;
 1202       state = event->state;
 1203    }
 1204 
 1205    dx = -0.25f * (float)(mx - x);
 1206    dy = -0.25f * (float)(my - y);
 1207 
 1208    rot = object_rot;
 1209    if(rotate_type == ROTATE_LIGHT)
 1210       rot = light_rot;
 1211    else if(rotate_type == ROTATE_SCENE)
 1212       rot = scene_rot;
 1213 
 1214    if(state & GDK_BUTTON1_MASK)
 1215    {
 1216       rot[1] += cosf(rot[0] / 180.0f * M_PI) * dx;
 1217       rot[2] -= sinf(rot[0] / 180.0f * M_PI) * dx;
 1218       rot[0] += dy;
 1219    }
 1220    else if(state & GDK_BUTTON3_MASK)
 1221    {
 1222       zoom += (-dy * 0.2f);
 1223    }
 1224 
 1225    mx = x;
 1226    my = y;
 1227 
 1228    gtk_widget_queue_draw(widget);
 1229 
 1230    return(1);
 1231 }
 1232 
 1233 static void window_destroy(GtkWidget *widget, gpointer data)
 1234 {
 1235    gtk_widget_destroy(glarea);
 1236    _active = 0;
 1237 }
 1238 
 1239 static void get_nearest_pot(int w, int h, int *w_pot, int *h_pot)
 1240 {
 1241    int n, next_pot, prev_pot, d1, d2;
 1242 
 1243    if(!IS_POT(w))
 1244    {
 1245       next_pot = 1;
 1246       for(n = 1; n <= 12; ++n)
 1247       {
 1248          prev_pot = next_pot;
 1249          next_pot = 1 << n;
 1250          if(next_pot >= w) break;
 1251       }
 1252 
 1253       if(next_pot < w)
 1254          *w_pot = next_pot;
 1255       else
 1256       {
 1257          d1 = w - prev_pot;
 1258          d2 = next_pot - w;
 1259          if(d1 < d2)
 1260             *w_pot = prev_pot;
 1261          else
 1262             *w_pot = next_pot;
 1263       }
 1264    }
 1265    else
 1266       *w_pot = w;
 1267 
 1268    if(!IS_POT(h))
 1269    {
 1270       next_pot = 1;
 1271       for(n = 1; n <= 12; ++n)
 1272       {
 1273          prev_pot = next_pot;
 1274          next_pot = 1 << n;
 1275          if(next_pot >= h) break;
 1276       }
 1277 
 1278       if(next_pot < h)
 1279          *h_pot = next_pot;
 1280       else
 1281       {
 1282          d1 = h - prev_pot;
 1283          d2 = next_pot - h;
 1284          if(d1 < d2)
 1285             *h_pot = prev_pot;
 1286          else
 1287             *h_pot = next_pot;
 1288       }
 1289    }
 1290    else
 1291       *h_pot = h;
 1292 }
 1293 
 1294 static void diffusemap_callback(gint32 id, gpointer data)
 1295 {
 1296    GimpDrawable *drawable;
 1297    int w, h, bpp, mipw, miph, n;
 1298    int w_pot, h_pot;
 1299    unsigned char *pixels, *tmp, *mip;
 1300    GimpPixelRgn src_rgn;
 1301    GLenum type = 0;
 1302 
 1303    if(_gl_error) return;
 1304 
 1305    if(id == normalmap_drawable_id)
 1306    {
 1307       if(white_tex != 0)
 1308       {
 1309          glActiveTexture(GL_TEXTURE1);
 1310          glBindTexture(GL_TEXTURE_2D, white_tex);
 1311       }
 1312       gtk_widget_queue_draw(glarea);
 1313       return;
 1314    }
 1315 
 1316    drawable = gimp_drawable_get(id);
 1317 
 1318    w = drawable->width;
 1319    h = drawable->height;
 1320    bpp = drawable->bpp;
 1321 
 1322    switch(bpp)
 1323    {
 1324       case 1: type = GL_LUMINANCE;       break;
 1325       case 2: type = GL_LUMINANCE_ALPHA; break;
 1326       case 3: type = GL_RGB;             break;
 1327       case 4: type = GL_RGBA;            break;
 1328    }
 1329 
 1330    pixels = g_malloc(w * h * bpp);
 1331    gimp_pixel_rgn_init(&src_rgn, drawable, 0, 0, w, h, 0, 0);
 1332    gimp_pixel_rgn_get_rect(&src_rgn, pixels, 0, 0, w, h);
 1333 
 1334    if(!has_npot && !(IS_POT(w) && IS_POT(h)))
 1335    {
 1336       get_nearest_pot(w, h, &w_pot, &h_pot);
 1337       tmp = g_malloc(h_pot * w_pot * bpp);
 1338       scale_pixels(tmp, w_pot, h_pot, pixels, w, h, bpp);
 1339       g_free(pixels);
 1340       pixels = tmp;
 1341       w = w_pot;
 1342       h = h_pot;
 1343    }
 1344 
 1345    glActiveTexture(GL_TEXTURE1);
 1346    glBindTexture(GL_TEXTURE_2D, diffuse_tex);
 1347    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 1348    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 1349    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 1350    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 1351    if(has_aniso)
 1352       glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy);
 1353    if(has_generate_mipmap)
 1354       glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
 1355    glTexImage2D(GL_TEXTURE_2D, 0, type, w, h, 0,
 1356                 type, GL_UNSIGNED_BYTE, pixels);
 1357 
 1358    if(!has_generate_mipmap)
 1359    {
 1360       mipw = w;
 1361       miph = h;
 1362       n = 0;
 1363       while((mipw != 1) && (miph != 1))
 1364       {
 1365          if(mipw > 1) mipw >>= 1;
 1366          if(miph > 1) miph >>= 1;
 1367          ++n;
 1368          mip = g_malloc(mipw * miph * bpp);
 1369          scale_pixels(mip, mipw, miph, pixels, w, h, bpp);
 1370          glTexImage2D(GL_TEXTURE_2D, n, bpp, mipw, miph, 0,
 1371                       (bpp == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
 1372                       mip);
 1373          g_free(mip);
 1374       }
 1375    }
 1376 
 1377    g_free(pixels);
 1378 
 1379    gimp_drawable_detach(drawable);
 1380 
 1381    gtk_widget_queue_draw(glarea);
 1382 }
 1383 
 1384 static void glossmap_callback(gint32 id, gpointer data)
 1385 {
 1386    GimpDrawable *drawable;
 1387    int w, h, bpp, mipw, miph, n;
 1388    int w_pot, h_pot;
 1389    unsigned char *pixels, *tmp, *mip;
 1390    GimpPixelRgn src_rgn;
 1391    GLenum type = 0;
 1392 
 1393    if(_gl_error) return;
 1394    if(num_mtus < 3) return;
 1395 
 1396    if(id == normalmap_drawable_id)
 1397    {
 1398       if(white_tex != 0)
 1399       {
 1400          glActiveTexture(GL_TEXTURE2);
 1401          glBindTexture(GL_TEXTURE_2D, white_tex);
 1402       }
 1403       gtk_widget_queue_draw(glarea);
 1404       return;
 1405    }
 1406 
 1407    drawable = gimp_drawable_get(id);
 1408 
 1409    w = drawable->width;
 1410    h = drawable->height;
 1411    bpp = drawable->bpp;
 1412 
 1413    switch(bpp)
 1414    {
 1415       case 1: type = GL_LUMINANCE;       break;
 1416       case 2: type = GL_LUMINANCE_ALPHA; break;
 1417       case 3: type = GL_RGB;             break;
 1418       case 4: type = GL_RGBA;            break;
 1419    }
 1420 
 1421    pixels = g_malloc(w * h * bpp);
 1422    gimp_pixel_rgn_init(&src_rgn, drawable, 0, 0, w, h, 0, 0);
 1423    gimp_pixel_rgn_get_rect(&src_rgn, pixels, 0, 0, w, h);
 1424 
 1425    if(!has_npot && !(IS_POT(w) && IS_POT(h)))
 1426    {
 1427       get_nearest_pot(w, h, &w_pot, &h_pot);
 1428       tmp = g_malloc(h_pot * w_pot * bpp);
 1429       scale_pixels(tmp, w_pot, h_pot, pixels, w, h, bpp);
 1430       g_free(pixels);
 1431       pixels = tmp;
 1432       w = w_pot;
 1433       h = h_pot;
 1434    }
 1435 
 1436    glActiveTexture(GL_TEXTURE2);
 1437    glBindTexture(GL_TEXTURE_2D, gloss_tex);
 1438    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 1439    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 1440    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 1441    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 1442    if(has_aniso)
 1443       glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy);
 1444    if(has_generate_mipmap)
 1445       glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
 1446    glTexImage2D(GL_TEXTURE_2D, 0, type, w, h, 0,
 1447                 type, GL_UNSIGNED_BYTE, pixels);
 1448 
 1449    if(!has_generate_mipmap)
 1450    {
 1451       mipw = w;
 1452       miph = h;
 1453       n = 0;
 1454       while((mipw != 1) && (miph != 1))
 1455       {
 1456          if(mipw > 1) mipw >>= 1;
 1457          if(miph > 1) miph >>= 1;
 1458          ++n;
 1459          mip = g_malloc(mipw * miph * bpp);
 1460          scale_pixels(mip, mipw, miph, pixels, w, h, bpp);
 1461          glTexImage2D(GL_TEXTURE_2D, n, bpp, mipw, miph, 0,
 1462                       (bpp == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
 1463                       mip);
 1464          g_free(mip);
 1465       }
 1466    }
 1467 
 1468    g_free(pixels);
 1469 
 1470    gimp_drawable_detach(drawable);
 1471 
 1472    gtk_widget_queue_draw(glarea);
 1473 }
 1474 
 1475 static void object_selected(GtkWidget *widget, gpointer data)
 1476 {
 1477    object_type = (int)(long)data;
 1478    gtk_widget_queue_draw(glarea);
 1479 }
 1480 
 1481 static void bumpmapping_clicked(GtkWidget *widget, gpointer data)
 1482 {
 1483    bumpmapping = (int)(long)data;
 1484    gtk_widget_queue_draw(glarea);
 1485 }
 1486 
 1487 static void toggle_fullscreen(GtkWidget *widget, gpointer data)
 1488 {
 1489    fullscreen = !fullscreen;
 1490    if(fullscreen)
 1491    {
 1492       gtk_window_fullscreen(GTK_WINDOW(window));
 1493       gtk_widget_hide(controls_table);
 1494    }
 1495    else
 1496    {
 1497       gtk_window_unfullscreen(GTK_WINDOW(window));
 1498       gtk_widget_show(controls_table);
 1499    }
 1500 }
 1501 
 1502 static void toggle_clicked(GtkWidget *widget, gpointer data)
 1503 {
 1504    *((int*)data) = !(*((int*)data));
 1505    gtk_widget_queue_draw(glarea);
 1506 }
 1507 
 1508 static void specular_exp_changed(GtkWidget *widget, gpointer data)
 1509 {
 1510    specular_exp = gtk_range_get_value(GTK_RANGE(widget));
 1511    gtk_widget_queue_draw(glarea);
 1512 }
 1513 
 1514 static void color_changed(GtkWidget *widget, gpointer data)
 1515 {
 1516    float *c = (float*)data;
 1517    GimpRGB color;
 1518 
 1519    gimp_color_button_get_color(GIMP_COLOR_BUTTON(widget), &color);
 1520    c[0] = color.r;
 1521    c[1] = color.g;
 1522    c[2] = color.b;
 1523 
 1524    gtk_widget_queue_draw(glarea);
 1525 }
 1526 
 1527 static void rotate_type_toggled(GtkWidget *widget, gpointer data)
 1528 {
 1529    if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(widget)))
 1530       rotate_type = (int)(long)data;
 1531 }
 1532 
 1533 static void uvscale_changed(GtkWidget *widget, gpointer data)
 1534 {
 1535    int n = (int)(long)data;
 1536    float v = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
 1537    GtkWidget *btn = g_object_get_data(G_OBJECT(widget), "chain");
 1538 
 1539    uvscale[n] = v;
 1540    if(gimp_chain_button_get_active(GIMP_CHAIN_BUTTON(btn)))
 1541    {
 1542       if(n == 0)
 1543       {
 1544          uvscale[1] = v;
 1545          gtk_spin_button_set_value(GTK_SPIN_BUTTON(uvscale_spin2), v);
 1546       }
 1547       else
 1548       {
 1549          uvscale[0] = v;
 1550          gtk_spin_button_set_value(GTK_SPIN_BUTTON(uvscale_spin1), v);
 1551       }
 1552    }
 1553 
 1554    gtk_widget_queue_draw(glarea);
 1555 }
 1556 
 1557 static void reset_view_clicked(GtkWidget *widget, gpointer data)
 1558 {
 1559    GimpRGB c;
 1560 
 1561    object_rot[0] = object_rot[1] = object_rot[2] = 0;
 1562    light_rot[0] = light_rot[1] = light_rot[2] = 0;
 1563    scene_rot[0] = scene_rot[1] = scene_rot[2] = 0;
 1564    zoom = 2;
 1565 
 1566    specular_exp = 32.0f;
 1567    ambient_color[0] = ambient_color[1] = ambient_color[2] = 0.2f;
 1568    diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0f;
 1569    specular_color[0] = specular_color[1] = specular_color[2] = 1.0f;
 1570    uvscale[0] = uvscale[1] = 1;
 1571 
 1572    gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(rotate_obj_btn), 1);
 1573    gtk_option_menu_set_history(GTK_OPTION_MENU(object_opt), 0);
 1574    gtk_option_menu_set_history(GTK_OPTION_MENU(bumpmapping_opt), 0);
 1575    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(specular_check), 0);
 1576    gtk_range_set_value(GTK_RANGE(specular_exp_range), specular_exp);
 1577    gtk_spin_button_set_value(GTK_SPIN_BUTTON(uvscale_spin1), uvscale[0]);
 1578    gtk_spin_button_set_value(GTK_SPIN_BUTTON(uvscale_spin2), uvscale[1]);
 1579 
 1580    gimp_rgb_set(&c, ambient_color[0], ambient_color[1], ambient_color[2]);
 1581    gimp_color_button_set_color(GIMP_COLOR_BUTTON(ambient_color_btn), &c);
 1582    gimp_rgb_set(&c, diffuse_color[0], diffuse_color[1], diffuse_color[2]);
 1583    gimp_color_button_set_color(GIMP_COLOR_BUTTON(diffuse_color_btn), &c);
 1584    gimp_rgb_set(&c, specular_color[0], specular_color[1], specular_color[2]);
 1585    gimp_color_button_set_color(GIMP_COLOR_BUTTON(specular_color_btn), &c);
 1586 
 1587    bumpmapping = 0;
 1588    specular = 0;
 1589    rotate_type = ROTATE_OBJECT;
 1590    object_type = OBJECT_QUAD;
 1591 
 1592    gtk_widget_queue_draw(glarea);
 1593 }
 1594 
 1595 void show_3D_preview(GimpDrawable *drawable)
 1596 {
 1597    int i;
 1598    GtkWidget *vbox;
 1599    GtkWidget *table, *table2;
 1600    GtkWidget *opt;
 1601    GtkWidget *menu;
 1602    GtkWidget *menuitem;
 1603    GtkWidget *check;
 1604    GtkWidget *btn;
 1605    GtkWidget *hscale;
 1606    GtkWidget *label;
 1607    GtkObject *adj;
 1608    GtkWidget *spin;
 1609    GtkWidget *toolbar;
 1610    GtkToolItem *toolbtn;
 1611    GtkTooltips *tooltips;
 1612    GtkWidget *icon;
 1613    GdkPixbuf *pixbuf;
 1614    GSList *group = 0;
 1615    GdkGLConfig *glconfig;
 1616    GimpRGB color;
 1617    const char *object_strings[OBJECT_MAX] =
 1618    {
 1619       "Quad", "Cube", "Sphere", "Torus", "Teapot"
 1620    };
 1621    const char *bumpmap_strings[BUMPMAP_MAX] =
 1622    {
 1623       "Normal", "Parallax", "Parallax Occlusion", "Relief"
 1624    };
 1625 
 1626    bumpmapping = 0;
 1627    specular = 0;
 1628    specular_exp = 32.0f;
 1629    ambient_color[0] = ambient_color[1] = ambient_color[2] = 0.2f;
 1630    diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0f;
 1631    specular_color[0] = specular_color[1] = specular_color[2] = 1.0f;
 1632    uvscale[0] = uvscale[1] = 1;
 1633 
 1634    if(_active) return;
 1635 
 1636    normalmap_drawable_id = drawable->drawable_id;
 1637 
 1638    glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGBA |
 1639                                         GDK_GL_MODE_DEPTH |
 1640                                         GDK_GL_MODE_DOUBLE);
 1641    if(glconfig == 0)
 1642    {
 1643       g_message("Could not initialize OpenGL context!");
 1644       return;
 1645    }
 1646 
 1647    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 1648    gtk_window_set_title(GTK_WINDOW(window), "Normalmap - 3D Preview");
 1649    gtk_container_set_resize_mode(GTK_CONTAINER(window), GTK_RESIZE_QUEUE);
 1650    gtk_container_set_reallocate_redraws(GTK_CONTAINER(window), TRUE);
 1651    gtk_signal_connect(GTK_OBJECT(window), "destroy",
 1652                       GTK_SIGNAL_FUNC(window_destroy), 0);
 1653 
 1654    vbox = gtk_vbox_new(0, 0);
 1655    gtk_container_add(GTK_CONTAINER(window), vbox);
 1656    gtk_widget_show(vbox);
 1657 
 1658    tooltips = gtk_tooltips_new();
 1659 
 1660    toolbar = gtk_toolbar_new();
 1661    gtk_widget_show(toolbar);
 1662    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
 1663    gtk_box_pack_start(GTK_BOX(vbox), toolbar, 0, 0, 0);
 1664 
 1665    group = NULL;
 1666 
 1667    toolbtn = gtk_radio_tool_button_new(group);
 1668    rotate_obj_btn = (GtkWidget*)toolbtn;
 1669    gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbtn), "");
 1670    pixbuf = gdk_pixbuf_new_from_xpm_data(object_xpm);
 1671    icon = gtk_image_new_from_pixbuf(pixbuf);
 1672    gtk_widget_show(icon);
 1673    gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbtn), icon);
 1674    gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(toolbtn), tooltips, "Rotate object", 0);
 1675    gtk_widget_show(GTK_WIDGET(toolbtn));
 1676    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1677    gtk_signal_connect(GTK_OBJECT(toolbtn), "toggled",
 1678                       GTK_SIGNAL_FUNC(rotate_type_toggled),
 1679                       (gpointer)ROTATE_OBJECT);
 1680    group = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(toolbtn));
 1681 
 1682    toolbtn = gtk_radio_tool_button_new(group);
 1683    gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbtn), "");
 1684    pixbuf = gdk_pixbuf_new_from_xpm_data(light_xpm);
 1685    icon = gtk_image_new_from_pixbuf(pixbuf);
 1686    gtk_widget_show(icon);
 1687    gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbtn), icon);
 1688    gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(toolbtn), tooltips, "Rotate light", 0);
 1689    gtk_widget_show(GTK_WIDGET(toolbtn));
 1690    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1691    gtk_signal_connect(GTK_OBJECT(toolbtn), "toggled",
 1692                       GTK_SIGNAL_FUNC(rotate_type_toggled),
 1693                       (gpointer)ROTATE_LIGHT);
 1694    group = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(toolbtn));
 1695 
 1696    toolbtn = gtk_radio_tool_button_new(group);
 1697    gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbtn), "");
 1698    pixbuf = gdk_pixbuf_new_from_xpm_data(scene_xpm);
 1699    icon = gtk_image_new_from_pixbuf(pixbuf);
 1700    gtk_widget_show(icon);
 1701    gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbtn), icon);
 1702    gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(toolbtn), tooltips, "Rotate scene", 0);
 1703    gtk_widget_show(GTK_WIDGET(toolbtn));
 1704    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1705    gtk_signal_connect(GTK_OBJECT(toolbtn), "toggled",
 1706                       GTK_SIGNAL_FUNC(rotate_type_toggled),
 1707                       (gpointer)ROTATE_SCENE);
 1708    group = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(toolbtn));
 1709 
 1710    toolbtn = gtk_separator_tool_item_new();
 1711    gtk_widget_show(GTK_WIDGET(toolbtn));
 1712    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1713 
 1714    toolbtn = gtk_toggle_tool_button_new();
 1715    gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbtn), "");
 1716    pixbuf = gdk_pixbuf_new_from_xpm_data(full_xpm);
 1717    icon = gtk_image_new_from_pixbuf(pixbuf);
 1718    gtk_widget_show(icon);
 1719    gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbtn), icon);
 1720    gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(toolbtn), tooltips, "Toggle fullscreen", 0);
 1721    gtk_widget_show(GTK_WIDGET(toolbtn));
 1722    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1723    gtk_signal_connect(GTK_OBJECT(toolbtn), "clicked",
 1724                       GTK_SIGNAL_FUNC(toggle_fullscreen), 0);
 1725 
 1726    toolbtn = gtk_separator_tool_item_new();
 1727    gtk_widget_show(GTK_WIDGET(toolbtn));
 1728    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1729 
 1730    toolbtn = gtk_tool_item_new();
 1731    gtk_widget_show(GTK_WIDGET(toolbtn));
 1732    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1733    label = gtk_label_new("Object type: ");
 1734    gtk_widget_show(label);
 1735    gtk_container_add(GTK_CONTAINER(toolbtn), label);
 1736 
 1737    toolbtn = gtk_tool_item_new();
 1738    gtk_widget_show(GTK_WIDGET(toolbtn));
 1739    gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbtn));
 1740 
 1741    opt = gtk_option_menu_new();
 1742    object_opt = opt;
 1743    gtk_widget_show(opt);
 1744    gtk_container_add(GTK_CONTAINER(toolbtn), opt);
 1745 
 1746    menu = gtk_menu_new();
 1747 
 1748    for(i = 0; i < OBJECT_MAX; ++i)
 1749    {
 1750       menuitem = gtk_menu_item_new_with_label(object_strings[i]);
 1751       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1752                          GTK_SIGNAL_FUNC(object_selected),
 1753                          (gpointer)(long)i);
 1754       gtk_widget_show(menuitem);
 1755       gtk_menu_append(GTK_MENU(menu), menuitem);
 1756    }
 1757 
 1758    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1759 
 1760    glarea = gtk_drawing_area_new();
 1761    gtk_widget_set_usize(glarea, 500, 300);
 1762    gtk_widget_set_gl_capability(glarea, glconfig, 0, 1, GDK_GL_RGBA_TYPE);
 1763    gtk_widget_set_events(glarea, GDK_EXPOSURE_MASK |
 1764                          GDK_BUTTON_PRESS_MASK |
 1765                          GDK_POINTER_MOTION_MASK);
 1766    gtk_signal_connect(GTK_OBJECT(glarea), "realize",
 1767                       GTK_SIGNAL_FUNC(init), 0);
 1768    gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
 1769                       GTK_SIGNAL_FUNC(expose), 0);
 1770    gtk_signal_connect(GTK_OBJECT(glarea), "motion_notify_event",
 1771                       GTK_SIGNAL_FUNC(motion_notify), 0);
 1772    gtk_signal_connect(GTK_OBJECT(glarea), "button_press_event",
 1773                       GTK_SIGNAL_FUNC(button_press), 0);
 1774    gtk_signal_connect(GTK_OBJECT(glarea), "configure_event",
 1775                       GTK_SIGNAL_FUNC(configure), 0);
 1776 
 1777    gtk_box_pack_start(GTK_BOX(vbox), glarea, 1, 1, 0);
 1778 
 1779    table = gtk_table_new(11, 2, 0);
 1780    controls_table = table;
 1781    gtk_container_set_border_width(GTK_CONTAINER(table), 5);
 1782    gtk_table_set_col_spacings(GTK_TABLE(table), 5);
 1783    gtk_table_set_row_spacings(GTK_TABLE(table), 5);
 1784    gtk_box_pack_start(GTK_BOX(vbox), table, 0, 0, 0);
 1785    gtk_widget_show(table);
 1786 
 1787    opt = gtk_option_menu_new();
 1788    gtk_widget_show(opt);
 1789    menu = gimp_drawable_menu_new(0, diffusemap_callback, 0, normalmap_drawable_id);
 1790    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1791    gimp_table_attach_aligned(GTK_TABLE(table), 0, 0, "Diffuse map:", 0, 0.5,
 1792                              opt, 1, 0);
 1793 
 1794    opt = gtk_option_menu_new();
 1795    gloss_opt = opt;
 1796    gtk_widget_show(opt);
 1797    menu = gimp_drawable_menu_new(0, glossmap_callback, 0, normalmap_drawable_id);
 1798    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1799    gimp_table_attach_aligned(GTK_TABLE(table), 0, 1, "Gloss map:", 0, 0.5,
 1800                              opt, 1, 0);
 1801 
 1802    opt = gtk_option_menu_new();
 1803    bumpmapping_opt = opt;
 1804    gtk_widget_show(opt);
 1805 
 1806    gimp_table_attach_aligned(GTK_TABLE(table), 0, 2,
 1807                              "Bump mapping:", 0, 0.5,
 1808                              opt, 1, 0);
 1809 
 1810    menu = gtk_menu_new();
 1811 
 1812    for(i = 0; i < BUMPMAP_MAX; ++i)
 1813    {
 1814       menuitem = gtk_menu_item_new_with_label(bumpmap_strings[i]);
 1815       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1816                          GTK_SIGNAL_FUNC(bumpmapping_clicked),
 1817                          (gpointer)(long)i);
 1818       gtk_widget_show(menuitem);
 1819       gtk_menu_append(GTK_MENU(menu), menuitem);
 1820    }
 1821 
 1822    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1823 
 1824    check = gtk_check_button_new_with_label("Specular lighting");
 1825    specular_check = check;
 1826    gtk_widget_show(check);
 1827    gtk_table_attach(GTK_TABLE(table), check, 1, 2, 3, 4,
 1828                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1829                     (GtkAttachOptions)(0), 0, 0);
 1830    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1831                       GTK_SIGNAL_FUNC(toggle_clicked), &specular);
 1832 
 1833    specular_exp_range = hscale = gtk_hscale_new(GTK_ADJUSTMENT(gtk_adjustment_new(32, 0, 256, 1, 8, 0)));
 1834    gtk_widget_show(hscale);
 1835    gtk_scale_set_value_pos(GTK_SCALE(hscale), GTK_POS_RIGHT);
 1836    gimp_table_attach_aligned(GTK_TABLE(table), 0, 4, "Specular exponent:", 0, 0.5,
 1837                              hscale, 1, 0);
 1838    gtk_signal_connect(GTK_OBJECT(hscale), "value_changed",
 1839                       GTK_SIGNAL_FUNC(specular_exp_changed), 0);
 1840 
 1841 
 1842    gimp_rgb_set(&color, ambient_color[0], ambient_color[1], ambient_color[2]);
 1843    ambient_color_btn = btn = gimp_color_button_new("Ambient color", 0, 15, &color, GIMP_COLOR_AREA_FLAT);
 1844    gtk_widget_show(btn);
 1845    gimp_color_button_set_color(GIMP_COLOR_BUTTON(btn), &color);
 1846    gimp_table_attach_aligned(GTK_TABLE(table), 0, 5, "Ambient color:", 0, 0.5,
 1847                              btn, 1, 0);
 1848    gtk_signal_connect(GTK_OBJECT(btn), "color_changed",
 1849                       GTK_SIGNAL_FUNC(color_changed), (gpointer)ambient_color);
 1850 
 1851    gimp_rgb_set(&color, diffuse_color[0], diffuse_color[1], diffuse_color[2]);
 1852    diffuse_color_btn = btn = gimp_color_button_new("Diffuse color", 0, 15, &color, GIMP_COLOR_AREA_FLAT);
 1853    gtk_widget_show(btn);
 1854    gimp_color_button_set_color(GIMP_COLOR_BUTTON(btn), &color);
 1855    gimp_table_attach_aligned(GTK_TABLE(table), 0, 6, "Diffuse color:", 0, 0.5,
 1856                              btn, 1, 0);
 1857    gtk_signal_connect(GTK_OBJECT(btn), "color_changed",
 1858                       GTK_SIGNAL_FUNC(color_changed), (gpointer)diffuse_color);
 1859 
 1860    gimp_rgb_set(&color, specular_color[0], specular_color[1], specular_color[2]);
 1861    specular_color_btn = btn = gimp_color_button_new("Specular color", 0, 15, &color, GIMP_COLOR_AREA_FLAT);
 1862    gtk_widget_show(btn);
 1863    gimp_color_button_set_color(GIMP_COLOR_BUTTON(btn), &color);
 1864    gimp_table_attach_aligned(GTK_TABLE(table), 0, 7, "Specular color:", 0, 0.5,
 1865                              btn, 1, 0);
 1866    gtk_signal_connect(GTK_OBJECT(btn), "color_changed",
 1867                       GTK_SIGNAL_FUNC(color_changed), (gpointer)specular_color);
 1868 
 1869    table2 = gtk_table_new(2, 2, 0);
 1870    gtk_widget_show(table2);
 1871    gtk_table_set_col_spacings(GTK_TABLE(table2), 5);
 1872    gtk_table_set_row_spacings(GTK_TABLE(table2), 5);
 1873    gimp_table_attach_aligned(GTK_TABLE(table), 0, 8, "UV scale:", 0, 0.5,
 1874                              table2, 1, 0);
 1875 
 1876    adj = gtk_adjustment_new(1, 0, 1000, 1, 10, 10);
 1877    spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 4);
 1878    uvscale_spin1 = spin;
 1879    gtk_widget_show(spin);
 1880    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_IF_VALID);
 1881    gtk_signal_connect(GTK_OBJECT(spin), "value_changed",
 1882                       GTK_SIGNAL_FUNC(uvscale_changed), (gpointer)0);
 1883    gtk_table_attach(GTK_TABLE(table2), spin, 0, 1, 0, 1,
 1884                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1885                     (GtkAttachOptions)(0), 0, 0);
 1886 
 1887    adj = gtk_adjustment_new(1, 0, 1000, 1, 10, 10);
 1888    spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 4);
 1889    uvscale_spin2 = spin;
 1890    gtk_widget_show(spin);
 1891    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_IF_VALID);
 1892    gtk_signal_connect(GTK_OBJECT(spin), "value_changed",
 1893                       GTK_SIGNAL_FUNC(uvscale_changed), (gpointer)1);
 1894    gtk_table_attach(GTK_TABLE(table2), spin, 0, 1, 1, 2,
 1895                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1896                     (GtkAttachOptions)(0), 0, 0);
 1897 
 1898    btn = gimp_chain_button_new(GIMP_CHAIN_RIGHT);
 1899    gtk_widget_show(btn);
 1900    gimp_chain_button_set_active(GIMP_CHAIN_BUTTON(btn), 1);
 1901    gtk_table_attach(GTK_TABLE(table2), btn, 1, 2, 0, 2,
 1902                     (GtkAttachOptions)(0),
 1903                     (GtkAttachOptions)(0), 0, 0);
 1904 
 1905    g_object_set_data(G_OBJECT(uvscale_spin1), "chain", btn);
 1906    g_object_set_data(G_OBJECT(uvscale_spin2), "chain", btn);
 1907 
 1908    btn = gtk_button_new_with_label("Reset view");
 1909    gtk_widget_show(btn);
 1910    gtk_table_attach(GTK_TABLE(table), btn, 0, 2, 10, 11,
 1911                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1912                     (GtkAttachOptions)(0), 0, 0);
 1913    gtk_signal_connect(GTK_OBJECT(btn), "clicked",
 1914                       GTK_SIGNAL_FUNC(reset_view_clicked), 0);
 1915 
 1916    gtk_widget_show(glarea);
 1917    gtk_widget_show(window);
 1918 
 1919    _active = 1;
 1920 }
 1921 
 1922 void destroy_3D_preview(void)
 1923 {
 1924    if(!_active) return;
 1925    gtk_widget_destroy(window);
 1926    _active = 0;
 1927 }
 1928 
 1929 void update_3D_preview(unsigned int w, unsigned int h, int bpp,
 1930                        unsigned char *image)
 1931 {
 1932    int w_pot, h_pot, mipw, miph, n;
 1933    unsigned char *pixels = image;
 1934    unsigned char *mip;
 1935 
 1936    if(!_active) return;
 1937    if(_gl_error) return;
 1938 
 1939    if(!has_npot && !(IS_POT(w) && IS_POT(h)))
 1940    {
 1941       get_nearest_pot(w, h, &w_pot, &h_pot);
 1942       pixels = g_malloc(h_pot * w_pot * bpp);
 1943       scale_pixels(pixels, w_pot, h_pot, image, w, h, bpp);
 1944       w = w_pot;
 1945       h = h_pot;
 1946    }
 1947 
 1948    glActiveTexture(GL_TEXTURE0);
 1949    glBindTexture(GL_TEXTURE_2D, normal_tex);
 1950    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 1951    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 1952    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 1953    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 1954    if(has_aniso)
 1955       glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy);
 1956    if(has_generate_mipmap)
 1957       glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
 1958    glTexImage2D(GL_TEXTURE_2D, 0, bpp, w, h, 0,
 1959                 (bpp == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
 1960 
 1961    if(!has_generate_mipmap)
 1962    {
 1963       mipw = w;
 1964       miph = h;
 1965       n = 0;
 1966       while((mipw != 1) && (miph != 1))
 1967       {
 1968          if(mipw > 1) mipw >>= 1;
 1969          if(miph > 1) miph >>= 1;
 1970          ++n;
 1971          mip = g_malloc(mipw * miph * bpp);
 1972          scale_pixels(mip, mipw, miph, pixels, w, h, bpp);
 1973          glTexImage2D(GL_TEXTURE_2D, n, bpp, mipw, miph, 0,
 1974                       (bpp == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
 1975                       mip);
 1976          g_free(mip);
 1977       }
 1978    }
 1979 
 1980    if(pixels != image)
 1981       g_free(pixels);
 1982 
 1983    gtk_widget_queue_draw(glarea);
 1984 }
 1985 
 1986 int is_3D_preview_active(void)
 1987 {
 1988    return(_active);
 1989 }

ViewVC Help
Powered by ViewVC 1.0.4