1160 lines
27 KiB
C
1160 lines
27 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
*
|
|
* 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. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* 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.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include "BLI_winstuff.h"
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_lamp_types.h"
|
|
#include "DNA_material_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_property_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "BKE_bmfont.h"
|
|
#include "BKE_displist.h"
|
|
#include "BKE_effect.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_image.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_material.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_property.h"
|
|
|
|
#include "BIF_resources.h"
|
|
#include "BIF_gl.h"
|
|
#include "BIF_glutil.h"
|
|
#include "BIF_mywindow.h"
|
|
#include "BIF_resources.h"
|
|
|
|
#include "BDR_editface.h"
|
|
#include "BDR_vpaint.h"
|
|
#include "BDR_drawmesh.h"
|
|
|
|
#include "BSE_drawview.h"
|
|
|
|
#include "blendef.h"
|
|
#include "nla.h"
|
|
|
|
//#include "glext.h"
|
|
/* some local functions */
|
|
#if defined(GL_EXT_texture_object) && (!defined(__sun__) || (!defined(__sun))) && !defined(__APPLE__) && !defined(__linux__) && !defined(WIN32)
|
|
#define glBindTexture(A,B) glBindTextureEXT(A,B)
|
|
#define glGenTextures(A,B) glGenTexturesEXT(A,B)
|
|
#define glDeleteTextures(A,B) glDeleteTexturesEXT(A,B)
|
|
#define glPolygonOffset(A,B) glPolygonOffsetEXT(A,B)
|
|
|
|
#else
|
|
|
|
/* #define GL_FUNC_ADD_EXT GL_FUNC_ADD */
|
|
/* #define GL_FUNC_REVERSE_SUBTRACT_EXT GL_FUNC_REVERSE_SUBTRACT */
|
|
/* #define GL_POLYGON_OFFSET_EXT GL_POLYGON_OFFSET */
|
|
|
|
#endif
|
|
|
|
/* (n&(n-1)) zeros the least significant bit of n */
|
|
static int is_pow2(int num) {
|
|
return ((num)&(num-1))==0;
|
|
}
|
|
static int smaller_pow2(int num) {
|
|
while (!is_pow2(num))
|
|
num= num&(num-1);
|
|
return num;
|
|
}
|
|
|
|
static int fCurtile=0, fCurmode=0,fCurtileXRep=0,fCurtileYRep=0;
|
|
static Image *fCurpage=0;
|
|
static short fTexwindx, fTexwindy, fTexwinsx, fTexwinsy;
|
|
static int fDoMipMap = 1;
|
|
static int fLinearMipMap = 0;
|
|
|
|
/* static int source, dest; also not used */
|
|
|
|
/**
|
|
* Enables or disable mipmapping for realtime images.
|
|
* @param mipmap Turn mipmapping on (mipmap!=0) or off (mipmap==0).
|
|
*/
|
|
void set_mipmap(int mipmap)
|
|
{
|
|
if (fDoMipMap != (mipmap != 0)) {
|
|
free_all_realtime_images();
|
|
fDoMipMap = mipmap != 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the current setting for mipmapping.
|
|
*/
|
|
int get_mipmap(void)
|
|
{
|
|
return fDoMipMap;
|
|
}
|
|
|
|
/**
|
|
* Enables or disable linear mipmap setting for realtime images (textures).
|
|
* Note that this will will destroy all texture bindings in OpenGL.
|
|
* @see free_realtime_image()
|
|
* @param mipmap Turn linear mipmapping on (linear!=0) or off (linear==0).
|
|
*/
|
|
void set_linear_mipmap(int linear)
|
|
{
|
|
if (fLinearMipMap != (linear != 0)) {
|
|
free_all_realtime_images();
|
|
fLinearMipMap = linear != 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the current setting for linear mipmapping.
|
|
*/
|
|
int get_linear_mipmap(void)
|
|
{
|
|
return fLinearMipMap;
|
|
}
|
|
|
|
|
|
/**
|
|
* Resets the realtime image cache variables.
|
|
*/
|
|
void clear_realtime_image_cache()
|
|
{
|
|
fCurpage = NULL;
|
|
fCurtile = 0;
|
|
fCurmode = 0;
|
|
fCurtileXRep = 0;
|
|
fCurtileYRep = 0;
|
|
}
|
|
|
|
/* REMEMBER! Changes here must go into my_set_tpage() as well */
|
|
int set_tpage(TFace *tface)
|
|
{
|
|
static int alphamode= -1;
|
|
static TFace *lasttface= 0;
|
|
Image *ima;
|
|
unsigned int *rect=NULL, *bind;
|
|
int tpx=0, tpy=0, tilemode, tileXRep,tileYRep;
|
|
|
|
/* disable */
|
|
if(tface==0) {
|
|
if(lasttface==0) return 0;
|
|
|
|
lasttface= 0;
|
|
fCurtile= 0;
|
|
fCurpage= 0;
|
|
if(fCurmode!=0) {
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
fCurmode= 0;
|
|
fCurtileXRep=0;
|
|
fCurtileYRep=0;
|
|
alphamode= -1;
|
|
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
|
|
return 0;
|
|
}
|
|
lasttface= tface;
|
|
|
|
if( alphamode != tface->transp) {
|
|
alphamode= tface->transp;
|
|
|
|
if(alphamode) {
|
|
glEnable(GL_BLEND);
|
|
|
|
if(alphamode==TF_ADD) {
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
/* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
|
|
}
|
|
else if(alphamode==TF_ALPHA) {
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
/* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
|
|
}
|
|
/* else { */
|
|
/* glBlendFunc(GL_ONE, GL_ONE); */
|
|
/* glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */
|
|
/* } */
|
|
}
|
|
else glDisable(GL_BLEND);
|
|
}
|
|
|
|
ima= tface->tpage;
|
|
|
|
/* Enable or disable reflection mapping */
|
|
if (ima && (ima->flag & IMA_REFLECT)){
|
|
|
|
// glActiveTextureARB(GL_TEXTURE0_ARB);
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
|
|
/* Handle multitexturing here */
|
|
}
|
|
else{
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
}
|
|
|
|
tilemode= tface->mode & TF_TILES;
|
|
tileXRep = 0;
|
|
tileYRep = 0;
|
|
if (ima)
|
|
{
|
|
tileXRep = ima->xrep;
|
|
tileYRep = ima->yrep;
|
|
}
|
|
|
|
|
|
if(ima==fCurpage && fCurtile==tface->tile && tilemode==fCurmode && fCurtileXRep==tileXRep && fCurtileYRep == tileYRep) return ima!=0;
|
|
|
|
if(tilemode!=fCurmode || fCurtileXRep!=tileXRep || fCurtileYRep != tileYRep)
|
|
{
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
|
|
if(tilemode && ima!=0)
|
|
glScalef(ima->xrep, ima->yrep, 1.0);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
|
|
if(ima==0 || ima->ok==0) {
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
fCurtile= tface->tile;
|
|
fCurpage= 0;
|
|
fCurmode= tilemode;
|
|
fCurtileXRep = tileXRep;
|
|
fCurtileYRep = tileYRep;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if(ima->ibuf==0) {
|
|
load_image(ima, IB_rect, G.sce, G.scene->r.cfra);
|
|
|
|
if(ima->ibuf==0) {
|
|
ima->ok= 0;
|
|
|
|
fCurtile= tface->tile;
|
|
fCurpage= 0;
|
|
fCurmode= tilemode;
|
|
fCurtileXRep = tileXRep;
|
|
fCurtileYRep = tileYRep;
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
if(ima->tpageflag & IMA_TWINANIM) fCurtile= ima->lastframe;
|
|
else fCurtile= tface->tile;
|
|
|
|
if(tilemode) {
|
|
|
|
if(ima->repbind==0) make_repbind(ima);
|
|
|
|
if(fCurtile>=ima->totbind) fCurtile= 0;
|
|
|
|
/* this happens when you change repeat buttons */
|
|
if(ima->repbind) bind= ima->repbind+fCurtile;
|
|
else bind= &ima->bindcode;
|
|
|
|
if(*bind==0) {
|
|
|
|
fTexwindx= ima->ibuf->x/ima->xrep;
|
|
fTexwindy= ima->ibuf->y/ima->yrep;
|
|
|
|
if(fCurtile>=ima->xrep*ima->yrep) fCurtile= ima->xrep*ima->yrep-1;
|
|
|
|
fTexwinsy= fCurtile / ima->xrep;
|
|
fTexwinsx= fCurtile - fTexwinsy*ima->xrep;
|
|
|
|
fTexwinsx*= fTexwindx;
|
|
fTexwinsy*= fTexwindy;
|
|
|
|
tpx= fTexwindx;
|
|
tpy= fTexwindy;
|
|
|
|
rect= ima->ibuf->rect + fTexwinsy*ima->ibuf->x + fTexwinsx;
|
|
}
|
|
}
|
|
else {
|
|
bind= &ima->bindcode;
|
|
|
|
if(*bind==0) {
|
|
tpx= ima->ibuf->x;
|
|
tpy= ima->ibuf->y;
|
|
rect= ima->ibuf->rect;
|
|
}
|
|
}
|
|
|
|
if(*bind==0) {
|
|
int rectw= tpx, recth= tpy;
|
|
unsigned int *tilerect= NULL, *scalerect= NULL;
|
|
|
|
/*
|
|
* Maarten:
|
|
* According to Ton this code is not needed anymore. It was used only
|
|
* in really old Blenders.
|
|
* Reevan:
|
|
* Actually it is needed for backwards compatibility. Simpledemo 6 does not display correctly without it.
|
|
*/
|
|
#if 1
|
|
if (tilemode) {
|
|
int y;
|
|
|
|
tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
|
|
for (y=0; y<recth; y++) {
|
|
unsigned int *rectrow= &rect[y*ima->ibuf->x];
|
|
unsigned int *tilerectrow= &tilerect[y*rectw];
|
|
|
|
memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
|
|
}
|
|
|
|
rect= tilerect;
|
|
}
|
|
#endif
|
|
if (!is_pow2(rectw) || !is_pow2(recth)) {
|
|
rectw= smaller_pow2(rectw);
|
|
recth= smaller_pow2(recth);
|
|
|
|
scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
|
|
gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
|
|
rect= scalerect;
|
|
}
|
|
|
|
glGenTextures(1, (GLuint *)bind);
|
|
|
|
if((G.f & G_DEBUG) || !*bind) {
|
|
GLenum error = glGetError();
|
|
printf("Texture: %s\n", ima->id.name+2);
|
|
printf("name: %d, tpx: %d\n", *bind, tpx);
|
|
printf("tile: %d, mode: %d\n", fCurtile, tilemode);
|
|
if (error)
|
|
printf("error: %s\n", gluErrorString(error));
|
|
}
|
|
glBindTexture( GL_TEXTURE_2D, *bind);
|
|
|
|
if (!fDoMipMap)
|
|
{
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
} else
|
|
{
|
|
int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
|
|
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
}
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
if (tilerect)
|
|
MEM_freeN(tilerect);
|
|
if (scalerect)
|
|
MEM_freeN(scalerect);
|
|
}
|
|
else glBindTexture( GL_TEXTURE_2D, *bind);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
fCurpage= ima;
|
|
fCurmode= tilemode;
|
|
fCurtileXRep = tileXRep;
|
|
fCurtileYRep = tileYRep;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void free_realtime_image(Image *ima)
|
|
{
|
|
if(ima->bindcode) {
|
|
glDeleteTextures(1, (GLuint *)&ima->bindcode);
|
|
ima->bindcode= 0;
|
|
}
|
|
if(ima->repbind) {
|
|
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
|
|
|
|
MEM_freeN(ima->repbind);
|
|
ima->repbind= 0;
|
|
}
|
|
}
|
|
|
|
void free_all_realtime_images(void)
|
|
{
|
|
Image* ima;
|
|
|
|
ima= G.main->image.first;
|
|
while(ima) {
|
|
free_realtime_image(ima);
|
|
ima= ima->id.next;
|
|
}
|
|
}
|
|
|
|
void make_repbind(Image *ima)
|
|
{
|
|
if(ima==0 || ima->ibuf==0) return;
|
|
|
|
if(ima->repbind) {
|
|
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
|
|
MEM_freeN(ima->repbind);
|
|
ima->repbind= 0;
|
|
}
|
|
ima->totbind= ima->xrep*ima->yrep;
|
|
if(ima->totbind>1) {
|
|
ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
|
|
}
|
|
}
|
|
|
|
void update_realtime_textures()
|
|
{
|
|
Image *ima;
|
|
|
|
ima= G.main->image.first;
|
|
while(ima) {
|
|
if(ima->tpageflag & IMA_TWINANIM) {
|
|
if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
|
|
|
|
/* check: is bindcode not in the array? Free. (to do) */
|
|
|
|
ima->lastframe++;
|
|
if(ima->lastframe > ima->twend) ima->lastframe= ima->twsta;
|
|
|
|
}
|
|
ima= ima->id.next;
|
|
}
|
|
}
|
|
|
|
|
|
void spack(unsigned int ucol)
|
|
{
|
|
char *cp= (char *)&ucol;
|
|
|
|
glColor3ub(cp[3], cp[2], cp[1]);
|
|
}
|
|
|
|
void draw_tfaces3D(Object *ob, Mesh *me)
|
|
{
|
|
MFace *mface;
|
|
TFace *tface;
|
|
DispList *dl;
|
|
float *v1, *v2, *v3, *v4;
|
|
float *av1= NULL, *av2= NULL, *av3= NULL, *av4= NULL, *extverts= NULL;
|
|
int a, activeFaceInSelection= 0;
|
|
|
|
if(me==0 || me->tface==0) return;
|
|
|
|
dl= find_displist(&ob->disp, DL_VERTS);
|
|
if (dl) extverts= dl->verts;
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
bglPolygonOffset(1.0);
|
|
|
|
/* Draw (Hidden) Edges */
|
|
if(G.f & G_DRAWEDGES || G.f & G_HIDDENEDGES){
|
|
BIF_ThemeColor(TH_EDGE_FACESEL);
|
|
|
|
mface= me->mface;
|
|
tface= me->tface;
|
|
for(a=me->totface; a>0; a--, mface++, tface++) {
|
|
if(mface->v3==0) continue;
|
|
if(tface->flag & TF_HIDE) {
|
|
if(!(G.f & G_HIDDENEDGES)) continue;
|
|
}
|
|
else if(!(G.f & G_DRAWEDGES)) continue;
|
|
|
|
if(extverts) {
|
|
v1= extverts+3*mface->v1;
|
|
v2= extverts+3*mface->v2;
|
|
v3= extverts+3*mface->v3;
|
|
v4= mface->v4?(extverts+3*mface->v4):NULL;
|
|
} else {
|
|
v1= (me->mvert+mface->v1)->co;
|
|
v2= (me->mvert+mface->v2)->co;
|
|
v3= (me->mvert+mface->v3)->co;
|
|
v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
|
|
}
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3fv(v1);
|
|
glVertex3fv(v2);
|
|
glVertex3fv(v3);
|
|
if(v4) glVertex3fv(v4);
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
if(G.f & G_DRAWSEAMS) {
|
|
BIF_ThemeColor(TH_EDGE_SEAM);
|
|
glLineWidth(2);
|
|
|
|
glBegin(GL_LINES);
|
|
mface= me->mface;
|
|
tface= me->tface;
|
|
for(a=me->totface; a>0; a--, mface++, tface++) {
|
|
if(mface->v3==0) continue;
|
|
if(tface->flag & TF_HIDE) continue;
|
|
|
|
if(extverts) {
|
|
v1= extverts+3*mface->v1;
|
|
v2= extverts+3*mface->v2;
|
|
v3= extverts+3*mface->v3;
|
|
v4= mface->v4?(extverts+3*mface->v4):NULL;
|
|
} else {
|
|
v1= (me->mvert+mface->v1)->co;
|
|
v2= (me->mvert+mface->v2)->co;
|
|
v3= (me->mvert+mface->v3)->co;
|
|
v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
|
|
}
|
|
|
|
if(tface->unwrap & TF_SEAM1) {
|
|
glVertex3fv(v1);
|
|
glVertex3fv(v2);
|
|
}
|
|
|
|
if(tface->unwrap & TF_SEAM2) {
|
|
glVertex3fv(v2);
|
|
glVertex3fv(v3);
|
|
}
|
|
|
|
if(tface->unwrap & TF_SEAM3) {
|
|
glVertex3fv(v3);
|
|
if(v4) glVertex3fv(v4);
|
|
else glVertex3fv(v1);
|
|
}
|
|
|
|
if(v4 && tface->unwrap & TF_SEAM4) {
|
|
glVertex3fv(v4);
|
|
glVertex3fv(v1);
|
|
}
|
|
}
|
|
glEnd();
|
|
|
|
glLineWidth(1);
|
|
}
|
|
|
|
/* Draw Selected Faces in transparent purple */
|
|
if(G.f & G_DRAWFACES) {
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
BIF_ThemeColor4(TH_FACE_SELECT);
|
|
|
|
mface= me->mface;
|
|
tface= me->tface;
|
|
for(a=me->totface; a>0; a--, mface++, tface++) {
|
|
if(mface->v3==0) continue;
|
|
if(tface->flag & TF_HIDE) continue;
|
|
|
|
if(tface->flag & TF_SELECT) {
|
|
if(extverts) {
|
|
v1= extverts+3*mface->v1;
|
|
v2= extverts+3*mface->v2;
|
|
v3= extverts+3*mface->v3;
|
|
v4= mface->v4?(extverts+3*mface->v4):NULL;
|
|
} else {
|
|
v1= (me->mvert+mface->v1)->co;
|
|
v2= (me->mvert+mface->v2)->co;
|
|
v3= (me->mvert+mface->v3)->co;
|
|
v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
|
|
}
|
|
|
|
glBegin(v4?GL_QUADS:GL_TRIANGLES);
|
|
glVertex3fv( v1 );
|
|
glVertex3fv( v2 );
|
|
glVertex3fv( v3 );
|
|
if(v4) glVertex3fv( v4 );
|
|
glEnd();
|
|
}
|
|
}
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
/* Draw Stippled Outline for selected faces */
|
|
mface= me->mface;
|
|
tface= me->tface;
|
|
bglPolygonOffset(1.0);
|
|
for(a=me->totface; a>0; a--, mface++, tface++) {
|
|
if(mface->v3==0) continue;
|
|
if(tface->flag & TF_HIDE) continue;
|
|
|
|
if(tface->flag & (TF_ACTIVE|TF_SELECT) ) {
|
|
if(extverts) {
|
|
v1= extverts+3*mface->v1;
|
|
v2= extverts+3*mface->v2;
|
|
v3= extverts+3*mface->v3;
|
|
v4= mface->v4?(extverts+3*mface->v4):NULL;
|
|
} else {
|
|
v1= (me->mvert+mface->v1)->co;
|
|
v2= (me->mvert+mface->v2)->co;
|
|
v3= (me->mvert+mface->v3)->co;
|
|
v4= mface->v4?(me->mvert+mface->v4)->co:NULL;
|
|
}
|
|
|
|
if(tface->flag & TF_ACTIVE) {
|
|
activeFaceInSelection= (tface->flag & TF_SELECT);
|
|
av1= v1; av2= v2; av3= v3; av4= v4;
|
|
}
|
|
else {
|
|
cpack(0x0);
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3fv( v1 );
|
|
glVertex3fv( v2 );
|
|
glVertex3fv( v3 );
|
|
if(v4) glVertex3fv( v4 );
|
|
glEnd();
|
|
}
|
|
|
|
if(tface->flag & TF_SELECT) {
|
|
cpack(0xFFFFFF);
|
|
setlinestyle(1);
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3fv( v1 );
|
|
glVertex3fv( v2 );
|
|
glVertex3fv( v3 );
|
|
if(v4) glVertex3fv( v4 );
|
|
glEnd();
|
|
setlinestyle(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Draw Active Face on top */
|
|
/* colors: R=x G=y */
|
|
if(av1) {
|
|
cpack(0xFF);
|
|
glBegin(GL_LINE_STRIP);
|
|
glVertex3fv(av1);
|
|
if(av4) glVertex3fv(av4);
|
|
else glVertex3fv(av3);
|
|
glEnd();
|
|
|
|
cpack(0xFF00);
|
|
glBegin(GL_LINE_STRIP);
|
|
glVertex3fv(av1);
|
|
glVertex3fv(av2);
|
|
glEnd();
|
|
|
|
if(activeFaceInSelection) cpack(0x00FFFF);
|
|
else cpack(0xFF00FF);
|
|
|
|
glBegin(GL_LINE_STRIP);
|
|
glVertex3fv(av2);
|
|
glVertex3fv(av3);
|
|
if(av4) glVertex3fv(av4);
|
|
glEnd();
|
|
setlinestyle(0);
|
|
}
|
|
|
|
bglPolygonOffset(0.0); // resets correctly now, even after calling accumulated offsets
|
|
}
|
|
|
|
static int set_gl_light(Object *ob)
|
|
{
|
|
Base *base;
|
|
Lamp *la;
|
|
int count;
|
|
/* float zero[4]= {0.0, 0.0, 0.0, 0.0}; */
|
|
float vec[4];
|
|
|
|
vec[3]= 1.0;
|
|
|
|
for(count=0; count<8; count++) glDisable(GL_LIGHT0+count);
|
|
|
|
count= 0;
|
|
|
|
base= FIRSTBASE;
|
|
while(base) {
|
|
if(base->object->type==OB_LAMP ) {
|
|
if(base->lay & G.vd->lay) {
|
|
if(base->lay & ob->lay)
|
|
{
|
|
la= base->object->data;
|
|
|
|
glPushMatrix();
|
|
glLoadMatrixf((float *)G.vd->viewmat);
|
|
|
|
where_is_object_simul(base->object);
|
|
VECCOPY(vec, base->object->obmat[3]);
|
|
|
|
if(la->type==LA_SUN) {
|
|
vec[0]= base->object->obmat[2][0];
|
|
vec[1]= base->object->obmat[2][1];
|
|
vec[2]= base->object->obmat[2][2];
|
|
vec[3]= 0.0;
|
|
glLightfv(GL_LIGHT0+count, GL_POSITION, vec);
|
|
}
|
|
else {
|
|
vec[3]= 1.0;
|
|
glLightfv(GL_LIGHT0+count, GL_POSITION, vec);
|
|
glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
|
|
glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
|
|
/* post 2.25 engine supports quad lights */
|
|
glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
|
|
|
|
if(la->type==LA_SPOT) {
|
|
vec[0]= -base->object->obmat[2][0];
|
|
vec[1]= -base->object->obmat[2][1];
|
|
vec[2]= -base->object->obmat[2][2];
|
|
glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, vec);
|
|
glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, la->spotsize/2.0);
|
|
glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0*la->spotblend);
|
|
}
|
|
else glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
|
|
}
|
|
|
|
vec[0]= la->energy*la->r;
|
|
vec[1]= la->energy*la->g;
|
|
vec[2]= la->energy*la->b;
|
|
vec[3]= 1.0;
|
|
glLightfv(GL_LIGHT0+count, GL_DIFFUSE, vec);
|
|
glLightfv(GL_LIGHT0+count, GL_SPECULAR, vec);//zero);
|
|
glEnable(GL_LIGHT0+count);
|
|
|
|
glPopMatrix();
|
|
|
|
count++;
|
|
if(count>7) break;
|
|
}
|
|
}
|
|
}
|
|
base= base->next;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static Material *give_current_material_or_def(Object *ob, int matnr)
|
|
{
|
|
extern Material defmaterial;
|
|
Material *ma= give_current_material(ob, matnr);
|
|
|
|
return ma?ma:&defmaterial;
|
|
}
|
|
|
|
static int set_draw_settings_cached(int clearcache, int textured, TFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
|
|
{
|
|
static int c_textured;
|
|
static int c_lit;
|
|
static int c_doublesided;
|
|
static TFace *c_texface;
|
|
static Object *c_litob;
|
|
static int c_litmatnr;
|
|
static int c_badtex;
|
|
|
|
if (clearcache) {
|
|
c_textured= c_lit= c_doublesided= -1;
|
|
c_texface= (TFace*) -1;
|
|
c_litob= (Object*) -1;
|
|
c_litmatnr= -1;
|
|
c_badtex= 0;
|
|
}
|
|
|
|
if (doublesided!=c_doublesided) {
|
|
if (doublesided) glDisable(GL_CULL_FACE);
|
|
else glEnable(GL_CULL_FACE);
|
|
|
|
c_doublesided= doublesided;
|
|
}
|
|
|
|
if (textured!=c_textured || texface!=c_texface) {
|
|
if (textured) {
|
|
c_badtex= !set_tpage(texface);
|
|
} else {
|
|
set_tpage(0);
|
|
c_badtex= 0;
|
|
}
|
|
c_textured= textured;
|
|
c_texface= texface;
|
|
}
|
|
|
|
if (c_badtex) lit= 0;
|
|
if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
|
|
if (lit) {
|
|
Material *ma= give_current_material_or_def(litob, litmatnr);
|
|
float spec[4];
|
|
|
|
spec[0]= ma->spec*ma->specr;
|
|
spec[1]= ma->spec*ma->specg;
|
|
spec[2]= ma->spec*ma->specb;
|
|
spec[3]= 1.0;
|
|
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
|
|
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
}
|
|
else {
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
}
|
|
c_lit= lit;
|
|
c_litob= litob;
|
|
c_litmatnr= litmatnr;
|
|
}
|
|
|
|
return c_badtex;
|
|
}
|
|
|
|
void draw_tface_mesh(Object *ob, Mesh *me, int dt)
|
|
/* maximum dt (drawtype): exactly according values that have been set */
|
|
{
|
|
TFace *tface=NULL;
|
|
MFace *mface=NULL;
|
|
float *extverts= NULL;
|
|
unsigned char obcol[4];
|
|
int a, mode;
|
|
short islight, istex;
|
|
|
|
if(me==NULL) return;
|
|
|
|
|
|
glShadeModel(GL_SMOOTH);
|
|
|
|
islight= set_gl_light(ob);
|
|
|
|
obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255);
|
|
obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255);
|
|
obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255);
|
|
obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
|
|
|
|
/* first all texture polys */
|
|
|
|
if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
|
|
else glFrontFace(GL_CCW);
|
|
|
|
glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
|
|
if(G.vd->drawtype==OB_TEXTURE) istex= 1;
|
|
else istex= 0;
|
|
|
|
set_draw_settings_cached(1, 0, 0, 0, 0, 0, 0);
|
|
|
|
if(dt > OB_SOLID) {
|
|
bProperty *prop = get_property(ob, "Text");
|
|
int editing= (G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) && (ob==((G.scene->basact) ? (G.scene->basact->object) : 0));
|
|
MVert *mvert=NULL;
|
|
int start=0, totface;
|
|
|
|
if(mesh_uses_displist(me) && editing==0) {
|
|
DispList *dl= find_displist(&me->disp, DL_MESH);
|
|
DispListMesh *dlm= NULL;
|
|
|
|
if (!dl)
|
|
totface= 0;
|
|
else {
|
|
dlm = dl->mesh;
|
|
totface= dlm->totface;
|
|
mvert= dlm->mvert;
|
|
mface= dlm->mface;
|
|
tface= dlm->tface;
|
|
}
|
|
}
|
|
else {
|
|
DispList *dl= find_displist(&ob->disp, DL_VERTS);
|
|
if (dl) extverts= dl->verts;
|
|
|
|
/* although buildvars are not supported in engine, they're in Blender... */
|
|
totface= me->totface;
|
|
set_buildvars(ob, &start, &totface);
|
|
|
|
mvert= me->mvert;
|
|
mface= me->mface;
|
|
tface= me->tface;
|
|
}
|
|
|
|
// tface can be NULL
|
|
if(tface==NULL) {
|
|
|
|
for (a=start; a<totface; a++) {
|
|
int v1idx, v2idx, v3idx, v4idx, mf_smooth, matnr;
|
|
float *v1, *v2, *v3, *v4;
|
|
MFace *mf= &mface[a];
|
|
|
|
v1idx= mf->v1;
|
|
v2idx= mf->v2;
|
|
v3idx= mf->v3;
|
|
v4idx= mf->v4;
|
|
mf_smooth= mf->flag & ME_SMOOTH;
|
|
matnr= mf->mat_nr;
|
|
|
|
if(v3idx==0) continue;
|
|
|
|
set_draw_settings_cached(0, 0, NULL, islight, ob, matnr, TF_TWOSIDE);
|
|
|
|
if (extverts) {
|
|
v1= extverts+3*v1idx;
|
|
v2= extverts+3*v2idx;
|
|
v3= extverts+3*v3idx;
|
|
v4= v4idx?(extverts+3*v4idx):NULL;
|
|
} else {
|
|
v1= (mvert+v1idx)->co;
|
|
v2= (mvert+v2idx)->co;
|
|
v3= (mvert+v3idx)->co;
|
|
v4= v4idx?(mvert+v4idx)->co:NULL;
|
|
}
|
|
|
|
{
|
|
Material *ma= give_current_material(ob, matnr);
|
|
if(ma) glColor3f(ma->r, ma->g, ma->b);
|
|
else glColor3f(0.5, 0.5, 0.5);
|
|
}
|
|
|
|
glBegin(v4?GL_QUADS:GL_TRIANGLES);
|
|
|
|
if (!mf_smooth) {
|
|
float nor[3];
|
|
CalcNormFloat(v1, v2, v3, nor);
|
|
glNormal3fv(nor);
|
|
}
|
|
|
|
if (mf_smooth) glNormal3sv(mvert[v1idx].no);
|
|
glVertex3fv(v1);
|
|
|
|
if (mf_smooth) glNormal3sv(mvert[v2idx].no);
|
|
glVertex3fv(v2);
|
|
|
|
if (mf_smooth) glNormal3sv(mvert[v3idx].no);
|
|
glVertex3fv(v3);
|
|
|
|
if(v4) {
|
|
if (mf_smooth) glNormal3sv(mvert[v4idx].no);
|
|
glVertex3fv(v4);
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
else { // has tfaces
|
|
tface+= start;
|
|
for (a=start; a<totface; a++, tface++) {
|
|
int v1idx, v2idx, v3idx, v4idx, mf_smooth, matnr, badtex;
|
|
float *v1, *v2, *v3, *v4;
|
|
MFace *mf= &mface[a];
|
|
|
|
v1idx= mf->v1;
|
|
v2idx= mf->v2;
|
|
v3idx= mf->v3;
|
|
v4idx= mf->v4;
|
|
mf_smooth= mf->flag & ME_SMOOTH;
|
|
matnr= mf->mat_nr;
|
|
|
|
if(v3idx==0) continue;
|
|
if(tface->flag & TF_HIDE) continue;
|
|
if(tface->mode & TF_INVISIBLE) continue;
|
|
|
|
mode= tface->mode;
|
|
|
|
if (extverts) {
|
|
v1= extverts+3*v1idx;
|
|
v2= extverts+3*v2idx;
|
|
v3= extverts+3*v3idx;
|
|
v4= v4idx?(extverts+3*v4idx):NULL;
|
|
} else {
|
|
v1= (mvert+v1idx)->co;
|
|
v2= (mvert+v2idx)->co;
|
|
v3= (mvert+v3idx)->co;
|
|
v4= v4idx?(mvert+v4idx)->co:NULL;
|
|
}
|
|
|
|
badtex= set_draw_settings_cached(0, istex && (mode&TF_TEX), tface, islight && (mode&TF_LIGHT), ob, matnr, mode&TF_TWOSIDE);
|
|
|
|
if (prop && !badtex && !editing && (mode & TF_BMFONT)) {
|
|
char string[MAX_PROPSTRING];
|
|
int characters, index;
|
|
Image *ima;
|
|
float curpos;
|
|
|
|
// The BM_FONT handling code is duplicated in the gameengine
|
|
// Search for 'Frank van Beek' ;-)
|
|
// string = "Frank van Beek";
|
|
|
|
set_property_valstr(prop, string);
|
|
characters = strlen(string);
|
|
|
|
ima = tface->tpage;
|
|
if (ima == NULL) {
|
|
characters = 0;
|
|
}
|
|
|
|
if (1 || !mf_smooth) {
|
|
float nor[3];
|
|
|
|
CalcNormFloat(v1, v2, v3, nor);
|
|
|
|
glNormal3fv(nor);
|
|
}
|
|
|
|
curpos= 0.0;
|
|
glBegin(v4?GL_QUADS:GL_TRIANGLES);
|
|
for (index = 0; index < characters; index++) {
|
|
float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
|
|
int character = string[index];
|
|
char *cp= NULL;
|
|
|
|
// lets calculate offset stuff
|
|
// space starts at offset 1
|
|
// character = character - ' ' + 1;
|
|
|
|
matrixGlyph(ima->ibuf, character, & centerx, ¢ery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
|
|
movex+= curpos;
|
|
|
|
if (mode & TF_OBCOL) glColor3ubv(obcol);
|
|
else cp= (char *)&(tface->col[0]);
|
|
|
|
glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
|
|
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
|
|
glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
|
|
|
|
glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy);
|
|
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
|
|
glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
|
|
|
|
glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy);
|
|
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
|
|
glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
|
|
|
|
if(v4) {
|
|
glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
|
|
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
|
|
glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
|
|
}
|
|
|
|
curpos+= advance;
|
|
}
|
|
glEnd();
|
|
}
|
|
else {
|
|
char *cp= NULL;
|
|
|
|
if (badtex) glColor3ub(0xFF, 0x00, 0xFF);
|
|
else if (mode & TF_OBCOL) glColor3ubv(obcol);
|
|
else cp= (char *)&(tface->col[0]);
|
|
|
|
if (!mf_smooth) {
|
|
float nor[3];
|
|
|
|
CalcNormFloat(v1, v2, v3, nor);
|
|
|
|
glNormal3fv(nor);
|
|
}
|
|
|
|
glBegin(v4?GL_QUADS:GL_TRIANGLES);
|
|
|
|
glTexCoord2fv(tface->uv[0]);
|
|
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
|
|
if (mf_smooth) glNormal3sv(mvert[v1idx].no);
|
|
glVertex3fv(v1);
|
|
|
|
glTexCoord2fv(tface->uv[1]);
|
|
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
|
|
if (mf_smooth) glNormal3sv(mvert[v2idx].no);
|
|
glVertex3fv(v2);
|
|
|
|
glTexCoord2fv(tface->uv[2]);
|
|
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
|
|
if (mf_smooth) glNormal3sv(mvert[v3idx].no);
|
|
glVertex3fv(v3);
|
|
|
|
if(v4) {
|
|
glTexCoord2fv(tface->uv[3]);
|
|
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
|
|
if (mf_smooth) glNormal3sv(mvert[v4idx].no);
|
|
glVertex3fv(v4);
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
/* switch off textures */
|
|
set_tpage(0);
|
|
}
|
|
}
|
|
glShadeModel(GL_FLAT);
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
if(ob==OBACT && (G.f & G_FACESELECT)) {
|
|
draw_tfaces3D(ob, me);
|
|
}
|
|
|
|
/* XXX, bad patch - default_gl_light() calls
|
|
* glLightfv(GL_LIGHT_POSITION, ...) which
|
|
* is transformed by the current matrix... we
|
|
* need to make sure that matrix is identity.
|
|
*
|
|
* It would be better if drawmesh.c kept track
|
|
* of and restored the light settings it changed.
|
|
* - zr
|
|
*/
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
default_gl_light();
|
|
glPopMatrix();
|
|
}
|
|
|
|
void init_realtime_GL(void)
|
|
{
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
}
|
|
|