quakeforge/tools/texpaint/main.c

424 lines
9.2 KiB
C

/* Texture Paint
* Plug-in for the GIMP
*
* Copyright (C) 1998 Uwe Maurer <uwe_maurer@t-online.de>
*
* Based on GiMd2Viewer-0.1 (Quake2 model viewer) by
* Copyright (C) 1998 Lionel ULMER <bbrox@mygale.org>
* Copyright (C) 1997-1998 Janne Löf <jlof@student.oulu.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "texturepaint.h"
void begingl(GtkWidget *glarea)
{
if (!gtk_gl_area_begingl(GTK_GL_AREA(glarea)))
{
gimp_message("gtk_gl_area_begingl failed()!");
gtk_main_quit();
}
}
void endgl(GtkWidget *glarea)
{
gtk_gl_area_endgl(GTK_GL_AREA(glarea));
}
gint expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
model_draw((ModelInfo*)data);
return TRUE;
}
gint resize(GtkWidget *widget, GdkEventConfigure *event,gpointer data)
{
if (!GTK_WIDGET_REALIZED(widget))
return TRUE;
begingl(widget);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,
(float) widget->allocation.width / widget->allocation.height,
0.1, 200.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, widget->allocation.width, widget->allocation.height);
model_draw((ModelInfo *)data);
endgl(widget);
return TRUE;
}
void BindTexture(ModelInfo *mdl,char *texdata,int w,int h)
{
DEBUG("%s %i",mdl->name,mdl->tex_image);
glBindTexture(GL_TEXTURE_2D, mdl->texture);
set_parameter(mdl);
glTexImage2D(GL_TEXTURE_2D, 0, 3, w, h, 0,
GL_RGB, GL_UNSIGNED_BYTE, texdata);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D,mdl->texture);
}
gint button_press_event(GtkWidget *widget, GdkEventButton *event,gpointer data)
{
ModelInfo *mdl;
mdl=(ModelInfo *)data;
if (event->type==GDK_2BUTTON_PRESS)
{
if (event->button==1)
on_paint_clicked(NULL,mdl);
else if (event->button==3)
on_generate_clicked(NULL,mdl);
}
if (event->button == 1)
{
mdl->M1_beginx = event->x;
mdl->M1_beginy = event->y;
trackball(mdl->lastquat,0,0,0,0);
} else if (event->button == 2)
{
mdl->M2_beginx = event->x;
mdl->M2_beginy = event->y;
} else if (event->button == 3)
{
mdl->M3_beginy = event->y;
}
return TRUE;
}
gint motion_notify_event(GtkWidget *widget, GdkEventMotion *event,
gpointer data)
{
int x, y;
int width,height;
GdkModifierType state;
ModelInfo *mdl;
mdl=(ModelInfo *)data;
width=widget->allocation.width;
height=widget->allocation.height;
if (event->is_hint)
{
gdk_window_get_pointer(event->window, &x, &y, &state);
} else
{
x=event->x;
y=event->y;
state = event->state;
}
if ((state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK))==0)
return TRUE;
if (state & GDK_BUTTON1_MASK)
{
trackball(mdl->lastquat,
(2.0 * mdl->M1_beginx - width) / width,
(height- 2.0 * mdl->M1_beginy) / height,
(2.0 * x - width) / width,
(height- 2.0 * y) / height);
mdl->M1_beginx = x;
mdl->M1_beginy = y;
add_quats(mdl->lastquat,mdl->curquat,mdl->curquat);
} else if (state & GDK_BUTTON2_MASK)
{
mdl->obj_Xpos += (mdl->obj_Zpos / -width) * (x - mdl->M2_beginx);
mdl->obj_Ypos -= (mdl->obj_Zpos / -height) * (y - mdl->M2_beginy);
mdl->M2_beginx = x;
mdl->M2_beginy = y;
} else if (state & GDK_BUTTON3_MASK)
{
mdl->obj_Zpos += (mdl->obj_Zpos / -height) * (y - mdl->M3_beginy);
mdl->M3_beginy = y;
}
model_draw(mdl);
return TRUE;
}
static void initgl(ModelInfo *mdl)
{
static int first_initgl=1;
GtkWidget *widget;
GLint data[4];
widget=mdl->glarea;
if (first_initgl)
{
glGetIntegerv(GL_MAX_TEXTURE_SIZE,data);
max_tex_size=data[0];
glGetIntegerv(GL_RED_BITS,data);
red_bits=data[0];
glGetIntegerv(GL_GREEN_BITS,data);
green_bits=data[0];
glGetIntegerv(GL_BLUE_BITS,data);
blue_bits=data[0];
red_shift = 8-red_bits;
green_shift = 8-green_bits;
blue_shift = 8-blue_bits;
first_initgl=0;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,
(float) widget->allocation.width / widget->allocation.height,
0.1, 200.0);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glShadeModel(GL_FLAT);
glEnable(GL_TEXTURE_2D);
glGenTextures(1,&mdl->texture);
get_texture(mdl);
glViewport(0, 0, widget->allocation.width, widget->allocation.height);
}
void on_center_clicked(GtkButton *button, gpointer data)
{
ModelInfo *mdl;
if (data)
mdl=(ModelInfo *)data;
else
mdl=dialog->mdl;
if (mdl)
{
mdl->obj_Xpos = 0.0;
mdl->obj_Ypos = 0.0;
mdl->obj_Zpos = -2.0;
trackball(mdl->curquat,0,0,0,0);
trackball(mdl->lastquat,0,0,0,0);
model_draw(mdl);
}
}
void model_new(char *name,Model *model)
{
int attrList[]=
{ GDK_GL_RGBA, GDK_GL_DOUBLEBUFFER, GDK_GL_DEPTH_SIZE, 1, GDK_GL_NONE};
GtkWidget *glarea;
ModelInfo *mdl_info;
char str[256];
mdl_info=g_malloc(sizeof(ModelInfo));
memset(mdl_info,0,sizeof(ModelInfo));
mdl_info->name=strdup(name);
mdl_info->model=model;
mdl_info->tex_image=-1;
mdl_info->paint_image=-1;
mdl_info->idle=-1;
trackball(mdl_info->curquat,0,0,0,0);
trackball(mdl_info->lastquat,0,0,0,0);
mdl_info->obj_Zpos=-2;
mdl_info->first=0;
mdl_info->last=mdl_info->model->numframes-1;
mdl_info->frame=0;
mdl_info->timer=g_timer_new();
mdl_info->glwindow=create_glwindow();
strcpy(str,"3D Window - ");
strncat(str,name,200);
gtk_window_set_title(GTK_WINDOW(mdl_info->glwindow),str);
gtk_object_set_data(GTK_OBJECT(mdl_info->glwindow),MODEL_KEY,mdl_info);
glarea = gtk_gl_area_new(attrList);
mdl_info->glarea=glarea;
if (glarea == NULL) {
g_print("Can't create GtkGLArea widget\n");
gtk_exit(1);
}
gtk_widget_set_usize(glarea, 200, 200); /* Minimum size */
gtk_widget_set_events(glarea,
GDK_EXPOSURE_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK);
gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
GTK_SIGNAL_FUNC(expose), mdl_info);
/* when widgets size changes we want to change glViewport size to match it */
gtk_signal_connect(GTK_OBJECT(glarea), "configure_event",
GTK_SIGNAL_FUNC(resize), mdl_info);
/* virtual trackball */
gtk_signal_connect(GTK_OBJECT(glarea), "motion_notify_event",
GTK_SIGNAL_FUNC(motion_notify_event), mdl_info);
gtk_signal_connect(GTK_OBJECT(glarea), "button_press_event",
GTK_SIGNAL_FUNC(button_press_event), mdl_info);
gtk_container_add(GTK_CONTAINER(mdl_info->glwindow), glarea);
gtk_widget_show(mdl_info->glwindow);
gtk_widget_show(glarea);
gtk_widget_realize(glarea);
dialog->models_list=g_list_append(dialog->models_list,mdl_info);
update_models_menu(mdl_info);
}
void add_anim_button(GtkWidget *container,int num,char **pix)
{
GtkStyle *style;
GdkBitmap *mask;
GdkPixmap *gdkpix;
GtkWidget *gtkpix,*button;
button=gtk_button_new();
gtk_container_add(GTK_CONTAINER(container),button);
gtk_widget_realize(button);
style = gtk_widget_get_style(button);
gdkpix = gdk_pixmap_create_from_xpm_d(button->window,
&mask,
&style->bg[GTK_STATE_NORMAL],
pix);
gtkpix = gtk_pixmap_new(gdkpix, mask);
gtk_widget_show(gtkpix);
gtk_container_add(GTK_CONTAINER(button),gtkpix);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(on_anim_clicked),GINT_TO_POINTER(num));
gtk_widget_show(button);
}
void display_model(ModelInfo *mdl,int mode)
{
GLfloat m[4][4];
int nextframe;
int frame;
float interp;
DEBUG("%s",mdl->name);
if (!GTK_WIDGET_REALIZED(mdl->glarea)) return;
if (mdl->model==NULL) return;
begingl(mdl->glarea);
if (!mdl->init)
{
initgl(mdl);
mdl->init = 1;
}
if (mode==DRAW_NORMAL)
{
glClearColor(.3,.4,.6,0);
}
else
{
glClearColor(0,0,0,0);
}
if (mode==DRAW_WHITE) glDisable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(mdl->obj_Xpos,mdl->obj_Ypos,mdl->obj_Zpos);
build_rotmatrix(m,mdl->curquat);
glMultMatrixf(&m[0][0]);
glRotatef(-90,1,0,0);
if (mode==DRAW_COORD_S)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,mdl->texture_s);
}
else if (mode==DRAW_COORD_T)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,mdl->texture_t);
}
if (mdl->last>mdl->first)
{
frame=(int)mdl->frame;
nextframe=(int)mdl->frame+1;
if (nextframe>=mdl->model->numframes) nextframe=frame;
}
else
{
nextframe=(int)mdl->frame;
frame=(int)mdl->frame-1;
if (frame<0) frame=0;
}
interp=mdl->frame-floor(mdl->frame);
mdl->model->draw(mdl->model,frame,nextframe,interp);
if (mode!=DRAW_NORMAL)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,mdl->texture);
}
endgl(mdl->glarea);
gtk_gl_area_swapbuffers(GTK_GL_AREA(mdl->glarea));
}