causing weird results on camera moves or object rotations. Added: support for "normal maps". See for example: http://members.shaw.ca/jimht03/normal.html The Image panel in Texture buttons has new option "Normal Map" for it. When this is used, normals are read straight from RGB values, and blended with the current normal.
1568 lines
33 KiB
C
1568 lines
33 KiB
C
/* image.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 *****
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <math.h>
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "DNA_texture_types.h"
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_packedFile_types.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BKE_bad_level_calls.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BKE_global.h"
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_image.h"
|
|
#include "BKE_bmfont.h"
|
|
#include "BKE_screen.h"
|
|
#include "BKE_texture.h"
|
|
#include "BKE_packedFile.h"
|
|
#include "BKE_library.h"
|
|
|
|
void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2);
|
|
void clipy_rctf_swap(rctf *stack, short *count, float y1, float y2);
|
|
float square_rctf(rctf *rf);
|
|
float clipx_rctf(rctf *rf, float x1, float x2);
|
|
float clipy_rctf(rctf *rf, float y1, float y2);
|
|
void boxsample(struct ImBuf *ibuf,
|
|
float minx, float miny, float maxx, float maxy,
|
|
float *rcol, float *gcol, float *bcol, float *acol);
|
|
void boxsampleclip(struct ImBuf *ibuf, rctf *rf, float *rcol,
|
|
float *gcol, float *bcol, float *acol);
|
|
void filtersample(struct ImBuf *ibuf,
|
|
float fx, float fy,
|
|
float *rcol, float *gcol, float *bcol, float *acol);
|
|
|
|
|
|
|
|
/* If defined: check arguments on call */
|
|
/* #define IMAGE_C_ARG_CHECK */
|
|
|
|
/* Communicate with texture channels. */
|
|
extern float Tin, Tr, Tg, Tb, Ta;
|
|
|
|
int Talpha;
|
|
int imaprepeat, imapextend;
|
|
|
|
|
|
/*
|
|
*
|
|
* Talpha==TRUE means: read alpha from image. This does not mean that Ta
|
|
* should not be used, here info can be stored about outside edge of an image!
|
|
*
|
|
*/
|
|
|
|
void free_image_buffers(Image *ima)
|
|
{
|
|
int a;
|
|
|
|
if(ima->ibuf) {
|
|
if (ima->ibuf->userdata) {
|
|
MEM_freeN(ima->ibuf->userdata);
|
|
ima->ibuf->userdata = 0;
|
|
}
|
|
IMB_freeImBuf(ima->ibuf);
|
|
ima->ibuf= 0;
|
|
}
|
|
if(ima->anim) IMB_free_anim(ima->anim);
|
|
ima->anim= 0;
|
|
|
|
for(a=0; a<BLI_ARRAY_NELEMS(ima->mipmap); a++) {
|
|
if(ima->mipmap[a]) IMB_freeImBuf(ima->mipmap[a]);
|
|
ima->mipmap[a]= 0;
|
|
}
|
|
|
|
free_realtime_image(ima);
|
|
}
|
|
|
|
|
|
void free_image(Image *ima)
|
|
{
|
|
|
|
free_image_buffers(ima);
|
|
if (ima->packedfile) {
|
|
freePackedFile(ima->packedfile);
|
|
ima->packedfile = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
Image *add_image(char *name)
|
|
{
|
|
Image *ima;
|
|
int file, len;
|
|
char *libname, str[256], strtest[256];
|
|
|
|
strcpy(str, name);
|
|
BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
|
|
|
|
file= open(str, O_BINARY|O_RDONLY);
|
|
if(file== -1) return 0;
|
|
close(file);
|
|
|
|
/* first search an identical image */
|
|
ima= G.main->image.first;
|
|
while(ima) {
|
|
strcpy(strtest, ima->name);
|
|
BLI_convertstringcode(strtest, G.sce, G.scene->r.cfra);
|
|
if( strcmp(strtest, str)==0 ) {
|
|
if(ima->anim==0 || ima->id.us==0) {
|
|
strcpy(ima->name, name); /* for stringcode */
|
|
ima->id.us++;
|
|
ima->ok= 1;
|
|
return ima;
|
|
}
|
|
}
|
|
ima= ima->id.next;
|
|
}
|
|
|
|
len= strlen(name);
|
|
|
|
while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') len--;
|
|
libname= name+len;
|
|
|
|
ima= alloc_libblock(&G.main->image, ID_IM, libname);
|
|
strcpy(ima->name, name);
|
|
ima->ok= 1;
|
|
|
|
ima->xrep= ima->yrep= 1;
|
|
|
|
return ima;
|
|
}
|
|
|
|
void free_unused_animimages()
|
|
{
|
|
Image *ima, *nima;
|
|
|
|
ima= G.main->image.first;
|
|
while(ima) {
|
|
nima= ima->id.next;
|
|
if(ima->id.us==0) {
|
|
if(ima->flag & IMA_FROMANIM) free_libblock(&G.main->image, ima);
|
|
}
|
|
ima= nima;
|
|
}
|
|
}
|
|
|
|
|
|
/* *********** READ AND WRITE ************** */
|
|
|
|
void makepicstring(char *string, int frame)
|
|
{
|
|
short i,len;
|
|
char num[10], *extension;
|
|
|
|
if (string==0) return;
|
|
|
|
extension= "";
|
|
|
|
strcpy(string, G.scene->r.pic);
|
|
BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
|
|
|
|
len= strlen(string);
|
|
|
|
/* can also: sprintf(num, "%04d", frame); */
|
|
|
|
i=4-sprintf(num,"%d",frame);
|
|
for(;i>0;i--){
|
|
string[len]='0';
|
|
len++;
|
|
}
|
|
string[len]=0;
|
|
strcat(string,num);
|
|
|
|
if(G.scene->r.imtype== R_IRIS) {
|
|
extension= ".rgb";
|
|
}
|
|
else if(G.scene->r.imtype==R_IRIZ) {
|
|
extension= ".rgb";
|
|
}
|
|
else if(G.scene->r.imtype==R_PNG) {
|
|
extension= ".png";
|
|
}
|
|
else if(G.scene->r.imtype==R_TARGA) {
|
|
extension= ".tga";
|
|
}
|
|
else if(G.scene->r.imtype==R_RAWTGA) {
|
|
extension= ".tga";
|
|
}
|
|
else if(G.scene->r.imtype==R_JPEG90) {
|
|
extension= ".jpg";
|
|
}
|
|
|
|
if(G.scene->r.scemode & R_EXTENSION) strcat(string, extension);
|
|
|
|
}
|
|
|
|
/* ******** IMAGE WRAPPING INIT ************* */
|
|
|
|
void converttopremul(struct ImBuf *ibuf)
|
|
{
|
|
int x, y, val;
|
|
char *cp;
|
|
|
|
if(ibuf==0) return;
|
|
if(ibuf->depth==24) { /* put alpha at 255 */
|
|
|
|
cp= (char *)(ibuf->rect);
|
|
for(y=0; y<ibuf->y; y++) {
|
|
for(x=0; x<ibuf->x; x++, cp+=4) {
|
|
cp[3]= 255;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
cp= (char *)(ibuf->rect);
|
|
for(y=0; y<ibuf->y; y++) {
|
|
for(x=0; x<ibuf->x; x++, cp+=4) {
|
|
if(cp[3]==0) {
|
|
cp[0]= cp[1]= cp[2]= 0;
|
|
}
|
|
else if(cp[3]!=255) {
|
|
val= cp[3];
|
|
cp[0]= (cp[0]*val)>>8;
|
|
cp[1]= (cp[1]*val)>>8;
|
|
cp[2]= (cp[2]*val)>>8;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void makemipmap(Image *ima)
|
|
{
|
|
struct ImBuf *ibuf;
|
|
int minsize, curmap=0;
|
|
|
|
ibuf= ima->ibuf;
|
|
minsize= MIN2(ibuf->x, ibuf->y);
|
|
|
|
while(minsize>3 && curmap<BLI_ARRAY_NELEMS(ima->mipmap)) {
|
|
|
|
ibuf= IMB_dupImBuf(ibuf);
|
|
IMB_filter(ibuf);
|
|
ima->mipmap[curmap]= (struct ImBuf *)IMB_onehalf(ibuf);
|
|
IMB_freeImBuf(ibuf);
|
|
ibuf= ima->mipmap[curmap];
|
|
|
|
curmap++;
|
|
minsize= MIN2(ibuf->x, ibuf->y);
|
|
}
|
|
}
|
|
|
|
struct anim *openanim(char * name, int flags)
|
|
{
|
|
struct anim * anim;
|
|
struct ImBuf * ibuf;
|
|
|
|
anim = IMB_open_anim(name, flags);
|
|
if (anim == 0) return(0);
|
|
|
|
|
|
ibuf = IMB_anim_absolute(anim, 0);
|
|
if (ibuf == 0) {
|
|
printf("anim_absolute 0 failed\n");
|
|
IMB_free_anim(anim);
|
|
return(0);
|
|
}
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
return(anim);
|
|
}
|
|
|
|
int calcimanr(int cfra, Tex *tex)
|
|
{
|
|
int imanr, len, a, fra, dur;
|
|
|
|
/* here (+fie_ima/2-1) makes sure that division happens correctly */
|
|
|
|
if(tex->frames==0) return 1;
|
|
|
|
cfra= cfra-tex->sfra+1;
|
|
|
|
/* cyclic */
|
|
if(tex->len==0) len= (tex->fie_ima*tex->frames)/2;
|
|
else len= tex->len;
|
|
|
|
if(tex->imaflag & TEX_ANIMCYCLIC) {
|
|
cfra= ( (cfra) % len );
|
|
if(cfra < 0) cfra+= len;
|
|
if(cfra==0) cfra= len;
|
|
}
|
|
|
|
if(cfra<1) cfra= 1;
|
|
else if(cfra>len) cfra= len;
|
|
|
|
/* convert current frame to current field */
|
|
cfra= 2*(cfra);
|
|
if(R.flag & R_SEC_FIELD) cfra++;
|
|
|
|
/* transform to images space */
|
|
imanr= (cfra+tex->fie_ima-2)/tex->fie_ima;
|
|
if(imanr>tex->frames) imanr= tex->frames;
|
|
imanr+= tex->offset;
|
|
|
|
if(tex->imaflag & TEX_ANIMCYCLIC) {
|
|
imanr= ( (imanr) % len );
|
|
while(imanr < 0) imanr+= len;
|
|
if(imanr==0) imanr= len;
|
|
}
|
|
|
|
/* are there images that last longer? */
|
|
for(a=0; a<4; a++) {
|
|
if(tex->fradur[a][0]) {
|
|
|
|
fra= tex->fradur[a][0];
|
|
dur= tex->fradur[a][1]-1;
|
|
|
|
while(dur>0 && imanr>fra) {
|
|
imanr--;
|
|
dur--;
|
|
}
|
|
}
|
|
}
|
|
|
|
return imanr;
|
|
}
|
|
|
|
void do_laseroptics_patch(ImBuf *ibuf)
|
|
{
|
|
char *rt;
|
|
float fac;
|
|
int a, val;
|
|
|
|
rt= (char *)ibuf->rect;
|
|
a= ibuf->x*ibuf->y;
|
|
|
|
if(ibuf->flags & IB_fields) a+= a;
|
|
|
|
while(a--) {
|
|
|
|
fac= (rt[1]+rt[2]+rt[3])/765.0f;
|
|
val= (int)((255.0/0.8)*(fac-0.1));
|
|
|
|
if(val<0) val= 0; else if(val>255) val= 255;
|
|
|
|
rt[0]= rt[1]= rt[2]= rt[3]= val;
|
|
|
|
rt+= 4;
|
|
}
|
|
}
|
|
|
|
void de_interlace_ng(struct ImBuf *ibuf) /* neogeo fields */
|
|
{
|
|
struct ImBuf * tbuf1, * tbuf2;
|
|
|
|
if (ibuf == 0) return;
|
|
if (ibuf->flags & IB_fields) return;
|
|
ibuf->flags |= IB_fields;
|
|
|
|
if (ibuf->rect) {
|
|
/* make copies */
|
|
tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect, (unsigned char)0);
|
|
tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect, (unsigned char)0);
|
|
|
|
ibuf->x *= 2;
|
|
/* These rectop calls are broken!!! I added a trailing 0 arg... */
|
|
IMB_rectop(tbuf1, ibuf, 0, 0, 0, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
IMB_rectop(tbuf2, ibuf, 0, 0, tbuf2->x, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
|
|
ibuf->x /= 2;
|
|
IMB_rectop(ibuf, tbuf1, 0, 0, 0, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
IMB_rectop(ibuf, tbuf2, 0, tbuf2->y, 0, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
|
|
IMB_freeImBuf(tbuf1);
|
|
IMB_freeImBuf(tbuf2);
|
|
}
|
|
ibuf->y /= 2;
|
|
}
|
|
|
|
void de_interlace_st(struct ImBuf *ibuf) /* standard fields */
|
|
{
|
|
struct ImBuf * tbuf1, * tbuf2;
|
|
|
|
if (ibuf == 0) return;
|
|
if (ibuf->flags & IB_fields) return;
|
|
ibuf->flags |= IB_fields;
|
|
|
|
if (ibuf->rect) {
|
|
/* make copies */
|
|
tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect, 0);
|
|
tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect, 0);
|
|
|
|
ibuf->x *= 2;
|
|
/* These are brolenm as well... */
|
|
IMB_rectop(tbuf1, ibuf, 0, 0, 0, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
IMB_rectop(tbuf2, ibuf, 0, 0, tbuf2->x, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
|
|
ibuf->x /= 2;
|
|
IMB_rectop(ibuf, tbuf2, 0, 0, 0, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
IMB_rectop(ibuf, tbuf1, 0, tbuf2->y, 0, 0, 32767, 32767, IMB_rectcpy, 0);
|
|
|
|
IMB_freeImBuf(tbuf1);
|
|
IMB_freeImBuf(tbuf2);
|
|
}
|
|
ibuf->y /= 2;
|
|
}
|
|
|
|
/*
|
|
load_image handles reading the image from disk or from the packedfile.
|
|
*/
|
|
|
|
void load_image(Image * ima, int flags, char *relabase, int framenum)
|
|
{
|
|
char name[FILE_MAXDIR + FILE_MAXFILE];
|
|
|
|
if (ima->ibuf == NULL) {
|
|
|
|
// is there a PackedFile with this image ?;
|
|
if (ima->packedfile) {
|
|
ima->ibuf = IMB_ibImageFromMemory((int *) ima->packedfile->data, ima->packedfile->size, flags);
|
|
} else {
|
|
strcpy(name, ima->name);
|
|
BLI_convertstringcode(name, relabase, framenum);
|
|
|
|
ima->ibuf = IMB_loadiffname(name , flags);
|
|
}
|
|
// check if the image is a font image...
|
|
// printf("Checking for font\n");
|
|
|
|
if (ima->ibuf) {
|
|
detectBitmapFont(ima->ibuf);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ima_ibuf_is_nul(Tex *tex)
|
|
{
|
|
void (*de_interlacefunc)(struct ImBuf *ibuf);
|
|
Image *ima;
|
|
int a, fra, dur;
|
|
char str[FILE_MAXDIR+FILE_MAXFILE], *cp;
|
|
|
|
ima= tex->ima;
|
|
if(ima==0) return;
|
|
|
|
waitcursor(1);
|
|
|
|
strcpy(str, ima->name);
|
|
BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
|
|
|
|
if(tex->imaflag & TEX_STD_FIELD) de_interlacefunc= de_interlace_st;
|
|
else de_interlacefunc= de_interlace_ng;
|
|
|
|
if(tex->imaflag & TEX_ANIM5) {
|
|
|
|
if(ima->anim==0) ima->anim = openanim(str, IB_cmap | IB_rect);
|
|
if (ima->anim) {
|
|
dur = IMB_anim_get_duration(ima->anim);
|
|
|
|
ima->lastquality= R.osa;
|
|
fra= ima->lastframe-1;
|
|
|
|
if(fra<0) fra = 0;
|
|
if(fra>(dur-1)) fra= dur-1;
|
|
ima->ibuf = IMB_anim_absolute(ima->anim, fra);
|
|
|
|
/* patch for textbutton with name ima (B_NAMEIMA) */
|
|
if(ima->ibuf) {
|
|
strcpy(ima->ibuf->name, ima->name);
|
|
if (tex->imaflag & TEX_FIELDS) de_interlacefunc(ima->ibuf);
|
|
}
|
|
}
|
|
else error("Not an anim");
|
|
|
|
} else {
|
|
// create a packedfile for this image when autopack is on
|
|
// for performance (IMB_loadiffname uses mmap) we don't do this by default
|
|
if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK)) {
|
|
ima->packedfile = newPackedFile(str);
|
|
}
|
|
|
|
load_image(ima, IB_rect, G.sce, G.scene->r.cfra);
|
|
|
|
if (tex->imaflag & TEX_FIELDS) de_interlacefunc(ima->ibuf);
|
|
|
|
ima->lastquality= R.osa;
|
|
}
|
|
|
|
if(ima->ibuf) {
|
|
|
|
/* stringcodes also in ibuf. ibuf->name is used as 'undo' (buttons.c) */
|
|
strcpy(ima->ibuf->name, ima->name);
|
|
|
|
if(ima->ibuf->cmap) {
|
|
|
|
if(tex->imaflag & TEX_ANIM5) {
|
|
|
|
if(tex->imaflag & TEX_MORKPATCH) {
|
|
/**** PATCH TO SET COLOR 2 RIGHT (neogeo..) */
|
|
if(ima->ibuf->maxcol > 4) {
|
|
cp= (char *)(ima->ibuf->cmap+2);
|
|
cp[0]= 0x80;
|
|
}
|
|
}
|
|
|
|
IMB_applycmap(ima->ibuf);
|
|
IMB_convert_rgba_to_abgr(ima->ibuf->x*ima->ibuf->y, ima->ibuf->rect);
|
|
|
|
}
|
|
|
|
converttopremul(ima->ibuf);
|
|
}
|
|
|
|
if(R.osa) {
|
|
|
|
if(tex->imaflag & TEX_ANTISCALE) {
|
|
IMB_clever_double(ima->ibuf);
|
|
IMB_antialias(ima->ibuf);
|
|
}
|
|
else if(tex->imaflag & TEX_ANTIALI) IMB_antialias(ima->ibuf);
|
|
}
|
|
}
|
|
|
|
if(ima->ibuf==0) ima->ok= 0;
|
|
|
|
for(a=0; a<BLI_ARRAY_NELEMS(ima->mipmap); a++) {
|
|
if(ima->mipmap[a]) IMB_freeImBuf(ima->mipmap[a]);
|
|
ima->mipmap[a]= 0;
|
|
}
|
|
|
|
if((R.flag & R_RENDERING)==0) waitcursor(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* *********** IMAGEWRAPPING ****************** */
|
|
|
|
|
|
int imagewrap(Tex *tex, float *texvec)
|
|
{
|
|
Image *ima;
|
|
struct ImBuf *ibuf;
|
|
float fx, fy, val1, val2, val3;
|
|
int ofs, x, y;
|
|
char *rect;
|
|
|
|
Tin= Ta= Tr= Tg= Tb= 0.0;
|
|
ima= tex->ima;
|
|
if(ima==0 || ima->ok== 0) {
|
|
return 0;
|
|
}
|
|
|
|
if(ima->ibuf==0) ima_ibuf_is_nul(tex);
|
|
|
|
if (ima->ok) {
|
|
ibuf = ima->ibuf;
|
|
|
|
if(tex->imaflag & TEX_IMAROT) {
|
|
fy= texvec[0];
|
|
fx= texvec[1];
|
|
}
|
|
else {
|
|
fx= texvec[0];
|
|
fy= texvec[1];
|
|
}
|
|
|
|
if(tex->extend == TEX_CHECKER) {
|
|
int xs, ys;
|
|
|
|
xs= (int)floor(fx);
|
|
ys= (int)floor(fy);
|
|
fx-= xs;
|
|
fy-= ys;
|
|
|
|
if( (tex->flag & TEX_CHECKER_ODD)==0) {
|
|
if((xs+ys) & 1);else return 0;
|
|
}
|
|
if( (tex->flag & TEX_CHECKER_EVEN)==0) {
|
|
if((xs+ys) & 1) return 0;
|
|
}
|
|
/* scale around center, (0.5, 0.5) */
|
|
if(tex->checkerdist<1.0) {
|
|
fx= (fx-0.5)/(1.0-tex->checkerdist) +0.5;
|
|
fy= (fy-0.5)/(1.0-tex->checkerdist) +0.5;
|
|
}
|
|
}
|
|
|
|
x = (int)(fx*ibuf->x);
|
|
y = (int)(fy*ibuf->y);
|
|
|
|
if(tex->extend == TEX_CLIPCUBE) {
|
|
if(x<0 || y<0 || x>=ibuf->x || y>=ibuf->y || texvec[2]<-1.0 || texvec[2]>1.0) {
|
|
return 0;
|
|
}
|
|
}
|
|
else if( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
|
|
if(x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
if(tex->extend==TEX_EXTEND) {
|
|
if(x>=ibuf->x) x = ibuf->x-1;
|
|
else if(x<0) x= 0;
|
|
}
|
|
else {
|
|
x= x % ibuf->x;
|
|
if(x<0) x+= ibuf->x;
|
|
}
|
|
if(tex->extend==TEX_EXTEND) {
|
|
if(y>=ibuf->y) y = ibuf->y-1;
|
|
else if(y<0) y= 0;
|
|
}
|
|
else {
|
|
y= y % ibuf->y;
|
|
if(y<0) y+= ibuf->y;
|
|
}
|
|
}
|
|
|
|
/* warning, no return before setting back! */
|
|
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
|
|
ibuf->rect+= (ibuf->x*ibuf->y);
|
|
}
|
|
|
|
ofs = y * ibuf->x + x;
|
|
rect = (char *)( ibuf->rect+ ofs);
|
|
|
|
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
|
|
ibuf->rect-= (ibuf->x*ibuf->y);
|
|
}
|
|
|
|
Talpha= 0;
|
|
if(tex->imaflag & TEX_USEALPHA) {
|
|
if(tex->imaflag & TEX_CALCALPHA);
|
|
else Talpha= 1;
|
|
}
|
|
|
|
Tr = ((float)rect[0])/255.0f;
|
|
Tg = ((float)rect[1])/255.0f;
|
|
Tb = ((float)rect[2])/255.0f;
|
|
|
|
if(tex->nor) {
|
|
if(tex->imaflag & TEX_NORMALMAP) {
|
|
tex->nor[0]= 0.5-Tr;
|
|
tex->nor[1]= 0.5-Tg;
|
|
tex->nor[2]= 0.5-Tb;
|
|
}
|
|
else {
|
|
/* bump: take three samples */
|
|
val1= Tr+Tg+Tb;
|
|
|
|
if(x<ibuf->x-1) {
|
|
rect+=4;
|
|
val2= ((float)(rect[0]+rect[1]+rect[2]))/255.0f;
|
|
rect-=4;
|
|
}
|
|
else val2= val1;
|
|
|
|
if(y<ibuf->y-1) {
|
|
rect+= 4*ibuf->x;
|
|
val3= ((float)(rect[0]+rect[1]+rect[2]))/255.0f;
|
|
}
|
|
else val3= val1;
|
|
|
|
/* do not mix up x and y here! */
|
|
tex->nor[0]= (val1-val2);
|
|
tex->nor[1]= (val1-val3);
|
|
}
|
|
}
|
|
|
|
BRICONRGB;
|
|
|
|
if(Talpha) Ta= Tin= ((float)rect[3])/255.0f;
|
|
else if(tex->imaflag & TEX_CALCALPHA) {
|
|
Ta= Tin= MAX3(Tr, Tg, Tb);
|
|
}
|
|
else Ta= Tin= 1.0;
|
|
|
|
if(tex->flag & TEX_NEGALPHA) Ta= 1.0f-Ta;
|
|
|
|
}
|
|
|
|
if(tex->nor) return 3;
|
|
else return 1;
|
|
}
|
|
|
|
void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2)
|
|
/* rctf *stack; */
|
|
/* short *count; */
|
|
/* float x1, x2; */
|
|
{
|
|
rctf *rf, *newrct;
|
|
short a;
|
|
|
|
a= *count;
|
|
rf= stack;
|
|
for(;a>0;a--) {
|
|
if(rf->xmin<x1) {
|
|
if(rf->xmax<x1) {
|
|
rf->xmin+= (x2-x1);
|
|
rf->xmax+= (x2-x1);
|
|
}
|
|
else {
|
|
if(rf->xmax>x2) rf->xmax= x2;
|
|
newrct= stack+ *count;
|
|
(*count)++;
|
|
|
|
newrct->xmax= x2;
|
|
newrct->xmin= rf->xmin+(x2-x1);
|
|
newrct->ymin= rf->ymin;
|
|
newrct->ymax= rf->ymax;
|
|
|
|
if(newrct->xmin==newrct->xmax) (*count)--;
|
|
|
|
rf->xmin= x1;
|
|
}
|
|
}
|
|
else if(rf->xmax>x2) {
|
|
if(rf->xmin>x2) {
|
|
rf->xmin-= (x2-x1);
|
|
rf->xmax-= (x2-x1);
|
|
}
|
|
else {
|
|
if(rf->xmin<x1) rf->xmin= x1;
|
|
newrct= stack+ *count;
|
|
(*count)++;
|
|
|
|
newrct->xmin= x1;
|
|
newrct->xmax= rf->xmax-(x2-x1);
|
|
newrct->ymin= rf->ymin;
|
|
newrct->ymax= rf->ymax;
|
|
|
|
if(newrct->xmin==newrct->xmax) (*count)--;
|
|
|
|
rf->xmax= x2;
|
|
}
|
|
}
|
|
rf++;
|
|
}
|
|
|
|
}
|
|
|
|
void clipy_rctf_swap(rctf *stack, short *count, float y1, float y2)
|
|
/* rctf *stack; */
|
|
/* short *count; */
|
|
/* float y1, y2; */
|
|
{
|
|
rctf *rf, *newrct;
|
|
short a;
|
|
|
|
a= *count;
|
|
rf= stack;
|
|
for(;a>0;a--) {
|
|
if(rf->ymin<y1) {
|
|
if(rf->ymax<y1) {
|
|
rf->ymin+= (y2-y1);
|
|
rf->ymax+= (y2-y1);
|
|
}
|
|
else {
|
|
if(rf->ymax>y2) rf->ymax= y2;
|
|
newrct= stack+ *count;
|
|
(*count)++;
|
|
|
|
newrct->ymax= y2;
|
|
newrct->ymin= rf->ymin+(y2-y1);
|
|
newrct->xmin= rf->xmin;
|
|
newrct->xmax= rf->xmax;
|
|
|
|
if(newrct->ymin==newrct->ymax) (*count)--;
|
|
|
|
rf->ymin= y1;
|
|
}
|
|
}
|
|
else if(rf->ymax>y2) {
|
|
if(rf->ymin>y2) {
|
|
rf->ymin-= (y2-y1);
|
|
rf->ymax-= (y2-y1);
|
|
}
|
|
else {
|
|
if(rf->ymin<y1) rf->ymin= y1;
|
|
newrct= stack+ *count;
|
|
(*count)++;
|
|
|
|
newrct->ymin= y1;
|
|
newrct->ymax= rf->ymax-(y2-y1);
|
|
newrct->xmin= rf->xmin;
|
|
newrct->xmax= rf->xmax;
|
|
|
|
if(newrct->ymin==newrct->ymax) (*count)--;
|
|
|
|
rf->ymax= y2;
|
|
}
|
|
}
|
|
rf++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float square_rctf(rctf *rf)
|
|
/* rctf *rf; */
|
|
{
|
|
float x, y;
|
|
|
|
x= rf->xmax- rf->xmin;
|
|
y= rf->ymax- rf->ymin;
|
|
return (x*y);
|
|
}
|
|
|
|
float clipx_rctf(rctf *rf, float x1, float x2)
|
|
/* rctf *rf; */
|
|
/* float x1, x2; */
|
|
{
|
|
float size;
|
|
|
|
size= rf->xmax - rf->xmin;
|
|
|
|
if(rf->xmin<x1) {
|
|
rf->xmin= x1;
|
|
}
|
|
if(rf->xmax>x2) {
|
|
rf->xmax= x2;
|
|
}
|
|
if(rf->xmin > rf->xmax) {
|
|
rf->xmin = rf->xmax;
|
|
return 0.0;
|
|
}
|
|
else if(size!=0.0) {
|
|
return (rf->xmax - rf->xmin)/size;
|
|
}
|
|
return 1.0;
|
|
}
|
|
|
|
float clipy_rctf(rctf *rf, float y1, float y2)
|
|
/* rctf *rf; */
|
|
/* float y1, y2; */
|
|
{
|
|
float size;
|
|
|
|
size= rf->ymax - rf->ymin;
|
|
/* PRINT(f, size); */
|
|
if(rf->ymin<y1) {
|
|
rf->ymin= y1;
|
|
}
|
|
if(rf->ymax>y2) {
|
|
rf->ymax= y2;
|
|
}
|
|
/* PRINT(f, size); */
|
|
if(rf->ymin > rf->ymax) {
|
|
rf->ymin = rf->ymax;
|
|
return 0.0;
|
|
}
|
|
else if(size!=0.0) {
|
|
return (rf->ymax - rf->ymin)/size;
|
|
}
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
void boxsampleclip(struct ImBuf *ibuf, rctf *rf, float *rcol,
|
|
float *gcol, float *bcol, float *acol) /* return color 0.0-1.0 */
|
|
/* struct ImBuf *ibuf; */
|
|
/* rctf *rf; */
|
|
/* float *rcol, *gcol, *bcol, *acol; */
|
|
{
|
|
/* sample box, is clipped already, and minx etc. have been set at ibuf size.
|
|
Enlarge with antialiased edges of the pixels */
|
|
|
|
float muly,mulx,div;
|
|
int ofs;
|
|
int x, y, startx, endx, starty, endy;
|
|
char *rect;
|
|
|
|
startx= (int)floor(rf->xmin);
|
|
endx= (int)floor(rf->xmax);
|
|
starty= (int)floor(rf->ymin);
|
|
endy= (int)floor(rf->ymax);
|
|
|
|
if(startx < 0) startx= 0;
|
|
if(starty < 0) starty= 0;
|
|
if(endx>=ibuf->x) endx= ibuf->x-1;
|
|
if(endy>=ibuf->y) endy= ibuf->y-1;
|
|
|
|
if(starty==endy && startx==endx) {
|
|
|
|
ofs = starty*ibuf->x + startx;
|
|
rect = (char *)(ibuf->rect +ofs);
|
|
*rcol= ((float)rect[0])/255.0f;
|
|
*gcol= ((float)rect[1])/255.0f;
|
|
*bcol= ((float)rect[2])/255.0f;
|
|
/* alpha is global, has been set in function imagewraposa() */
|
|
if(Talpha) {
|
|
*acol= ((float)rect[3])/255.0f;
|
|
}
|
|
}
|
|
else {
|
|
div= *rcol= *gcol= *bcol= *acol= 0.0;
|
|
for(y=starty;y<=endy;y++) {
|
|
ofs = y*ibuf->x +startx;
|
|
rect = (char *)(ibuf->rect+ofs);
|
|
|
|
muly= 1.0;
|
|
|
|
if(starty==endy);
|
|
else {
|
|
if(y==starty) muly= 1.0f-(rf->ymin - y);
|
|
if(y==endy) muly= (rf->ymax - y);
|
|
}
|
|
if(startx==endx) {
|
|
mulx= muly;
|
|
if(Talpha) *acol+= mulx*rect[3];
|
|
*rcol+= mulx*rect[0];
|
|
*gcol+= mulx*rect[1];
|
|
*bcol+= mulx*rect[2];
|
|
div+= mulx;
|
|
}
|
|
else {
|
|
for(x=startx;x<=endx;x++) {
|
|
mulx= muly;
|
|
if(x==startx) mulx*= 1.0f-(rf->xmin - x);
|
|
if(x==endx) mulx*= (rf->xmax - x);
|
|
|
|
if(mulx==1.0) {
|
|
if(Talpha) *acol+= rect[3];
|
|
*rcol+= rect[0];
|
|
*gcol+= rect[1];
|
|
*bcol+= rect[2];
|
|
div+= 1.0;
|
|
}
|
|
else {
|
|
if(Talpha) *acol+= mulx*rect[3];
|
|
*rcol+= mulx*rect[0];
|
|
*gcol+= mulx*rect[1];
|
|
*bcol+= mulx*rect[2];
|
|
div+= mulx;
|
|
}
|
|
rect+=4;
|
|
}
|
|
}
|
|
}
|
|
if(div!=0.0) {
|
|
div*= 255.0;
|
|
|
|
*bcol/= div;
|
|
*gcol/= div;
|
|
*rcol/= div;
|
|
|
|
if(Talpha) *acol/= div;
|
|
}
|
|
else {
|
|
*rcol= *gcol= *bcol= *acol= 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void boxsample(struct ImBuf *ibuf,
|
|
float minx, float miny, float maxx, float maxy,
|
|
float *rcol, float *gcol, float *bcol, float *acol) /* return color 0.0-1.0 */
|
|
/* struct ImBuf *ibuf; */
|
|
/* float minx, miny, maxx, maxy; */
|
|
/* float *rcol, *gcol, *bcol, *acol; */
|
|
{
|
|
/* Sample box, performs clip. minx etc are in range 0.0 - 1.0 .
|
|
* Enlarge with antialiased edges of pixels.
|
|
* If global variable 'imaprepeat' has been set, the
|
|
* clipped-away parts are sampled as well.
|
|
*/
|
|
rctf *rf, stack[8];
|
|
float opp, tot, r, g, b, a, alphaclip= 1.0;
|
|
short count=1;
|
|
|
|
rf= stack;
|
|
rf->xmin= minx*(ibuf->x);
|
|
rf->xmax= maxx*(ibuf->x);
|
|
rf->ymin= miny*(ibuf->y);
|
|
rf->ymax= maxy*(ibuf->y);
|
|
|
|
if(imapextend);
|
|
else if(imaprepeat) clipx_rctf_swap(stack, &count, 0.0, (float)(ibuf->x));
|
|
else {
|
|
alphaclip= clipx_rctf(rf, 0.0, (float)(ibuf->x));
|
|
|
|
if(alphaclip<=0.0) {
|
|
*rcol= *bcol= *gcol= *acol= 0.0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(imapextend);
|
|
else if(imaprepeat) clipy_rctf_swap(stack, &count, 0.0, (float)(ibuf->y));
|
|
else {
|
|
alphaclip*= clipy_rctf(rf, 0.0, (float)(ibuf->y));
|
|
|
|
if(alphaclip<=0.0) {
|
|
*rcol= *bcol= *gcol= *acol= 0.0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(count>1) {
|
|
tot= *rcol= *bcol= *gcol= *acol= 0.0;
|
|
while(count--) {
|
|
boxsampleclip(ibuf, rf, &r, &g, &b, &a);
|
|
|
|
opp= square_rctf(rf);
|
|
tot+= opp;
|
|
|
|
*rcol+= opp*r;
|
|
*gcol+= opp*g;
|
|
*bcol+= opp*b;
|
|
if(Talpha) *acol+= opp*a;
|
|
rf++;
|
|
}
|
|
if(tot!= 0.0) {
|
|
*rcol/= tot;
|
|
*gcol/= tot;
|
|
*bcol/= tot;
|
|
if(Talpha) *acol/= tot;
|
|
}
|
|
}
|
|
else {
|
|
boxsampleclip(ibuf, rf, rcol, gcol, bcol, acol);
|
|
}
|
|
|
|
if(Talpha==0) *acol= 1.0;
|
|
|
|
if(alphaclip!=1.0) {
|
|
/* this is for laetr investigation, premul or not? */
|
|
/* *rcol*= alphaclip; */
|
|
/* *gcol*= alphaclip; */
|
|
/* *bcol*= alphaclip; */
|
|
*acol*= alphaclip;
|
|
}
|
|
}
|
|
|
|
void filtersample(struct ImBuf *ibuf,
|
|
float fx, float fy,
|
|
float *rcol, float *gcol, float *bcol, float *acol)
|
|
/* return color 0.0-1.0 */
|
|
/* struct ImBuf *ibuf; */ /* fx en fy tussen 0.0 en 1.0 */
|
|
/* float fx, fy; */
|
|
/* float *rcol, *gcol, *bcol, *acol; */
|
|
{
|
|
/* with weighted filter 3x3
|
|
* left or right collumn is always 0
|
|
* upper or lower row is awlays 0
|
|
*/
|
|
|
|
int fac, fac1, fac2, fracx, fracy, filt[4];
|
|
int ix, iy, x4;
|
|
unsigned int r=0, g=0, b=0, a=0;
|
|
char *rowcol, *rfilt[4];
|
|
|
|
ix= (int)( 256.0*fx );
|
|
fracx= (ix & 255);
|
|
ix= (ix>>8);
|
|
iy= (int)( 256.0*fy );
|
|
fracy= (iy & 255);
|
|
iy= (iy>>8);
|
|
|
|
if(ix>=ibuf->x) ix= ibuf->x-1;
|
|
if(iy>=ibuf->y) iy= ibuf->y-1;
|
|
|
|
rowcol= (char *)(ibuf->rect+ iy*ibuf->x +ix);
|
|
|
|
rfilt[0]= rfilt[1]= rfilt[2]= rfilt[3]= rowcol;
|
|
x4= 4*ibuf->x;
|
|
|
|
if(fracx<128) {
|
|
if(ix>0) {
|
|
rfilt[0]-= 4;
|
|
rfilt[2]-=4;
|
|
}
|
|
else if(imaprepeat) {
|
|
rfilt[0]+= x4-4;
|
|
rfilt[2]+= x4-4;
|
|
}
|
|
|
|
if(fracy<128) {
|
|
/* case left-under */
|
|
fac1= 128+fracy;
|
|
fac2= 128-fracy;
|
|
|
|
if(iy>0) {
|
|
rfilt[3]-= x4;
|
|
rfilt[2]-= x4;
|
|
}
|
|
else if(imaprepeat) {
|
|
fac= x4*(ibuf->y-1) ;
|
|
rfilt[3]+= fac;
|
|
rfilt[2]+= fac;
|
|
}
|
|
}
|
|
else {
|
|
/* case left-upper */
|
|
fac2= 384-fracy;
|
|
fac1= fracy-128;
|
|
|
|
if(iy<ibuf->y-1) {
|
|
rfilt[1]+= x4;
|
|
rfilt[0]+= x4;
|
|
}
|
|
else if(imaprepeat) {
|
|
fac= x4*(ibuf->y-1) ;
|
|
rfilt[1]-= fac;
|
|
rfilt[0]-= fac;
|
|
}
|
|
}
|
|
|
|
filt[1]=filt[3]= 128+ fracx;
|
|
filt[0]=filt[2]= 128- fracx;
|
|
filt[0]*= fac1;
|
|
filt[1]*= fac1;
|
|
filt[2]*= fac2;
|
|
filt[3]*= fac2;
|
|
}
|
|
else {
|
|
if(fracy<128) {
|
|
/* case right-under */
|
|
fac1= 128+fracy;
|
|
fac2= 128-fracy;
|
|
|
|
if(iy>0) {
|
|
rfilt[3]-= x4;
|
|
rfilt[2]-= x4;
|
|
}
|
|
else if(imaprepeat) {
|
|
fac= x4*(ibuf->y-1) ;
|
|
rfilt[3]+= fac;
|
|
rfilt[2]+= fac;
|
|
}
|
|
}
|
|
else {
|
|
/* case right-upper */
|
|
fac2= 384-fracy;
|
|
fac1= fracy-128;
|
|
|
|
if(iy<ibuf->y-1) {
|
|
rfilt[1]+= x4;
|
|
rfilt[0]+= x4;
|
|
}
|
|
else if(imaprepeat) {
|
|
fac= x4*(ibuf->y-1) ;
|
|
rfilt[1]-= fac;
|
|
rfilt[0]-= fac;
|
|
}
|
|
}
|
|
filt[0]=filt[2]= 384-fracx;
|
|
filt[1]=filt[3]= fracx-128;
|
|
filt[0]*= fac1;
|
|
filt[1]*= fac1;
|
|
filt[2]*= fac2;
|
|
filt[3]*= fac2;
|
|
|
|
if(ix<ibuf->x-1) {
|
|
rfilt[1]+= 4;
|
|
rfilt[3]+=4;
|
|
}
|
|
else if(imaprepeat) {
|
|
rfilt[1]-= x4-4;
|
|
rfilt[3]-= x4-4;
|
|
}
|
|
}
|
|
|
|
for(fac=3; fac>=0; fac--) {
|
|
rowcol= rfilt[fac];
|
|
r+= filt[fac]*rowcol[0];
|
|
g+= filt[fac]*rowcol[1];
|
|
b+= filt[fac]*rowcol[2];
|
|
if(Talpha) a+= filt[fac]*rowcol[3]; /* alpha is global */
|
|
}
|
|
*rcol= ((float)r)/16777216.0f;
|
|
*gcol= ((float)g)/16777216.0f;
|
|
*bcol= ((float)b)/16777216.0f;
|
|
if(Talpha) *acol= ((float)a)/16777216.0f;
|
|
|
|
}
|
|
|
|
|
|
int imagewraposa(Tex *tex, float *texvec, float *dxt, float *dyt)
|
|
{
|
|
struct Image *ima;
|
|
struct ImBuf *ibuf, *previbuf;
|
|
float fx, fy, minx, maxx, miny, maxy, dx, dy, fac1, fac2, fac3, fac4;
|
|
float maxd, pixsize, val1, val2, val3;
|
|
int curmap;
|
|
|
|
#ifdef IMAGE_C_ARG_CHECK
|
|
if (!tex) {
|
|
printf("imagewraposa: null pointer to texture\n");
|
|
}
|
|
#endif
|
|
|
|
ima= tex->ima;
|
|
#ifdef IMAGE_C_ARG_CHECK
|
|
if (!ima) {
|
|
printf("imagewraposa: null pointer to image\n");
|
|
}
|
|
#endif
|
|
|
|
Tin= Ta= Tr= Tg= Tb= 0.0;
|
|
|
|
if(ima==0 || ima->ok== 0) {
|
|
return 0;
|
|
}
|
|
|
|
if(ima->ibuf==0) ima_ibuf_is_nul(tex);
|
|
|
|
if (ima->ok) {
|
|
|
|
if(tex->imaflag & TEX_MIPMAP) {
|
|
if(ima->mipmap[0]==0) makemipmap(ima);
|
|
}
|
|
|
|
ibuf = ima->ibuf;
|
|
|
|
Talpha= 0;
|
|
if(tex->imaflag & TEX_USEALPHA) {
|
|
if(tex->imaflag & TEX_CALCALPHA);
|
|
else Talpha= 1;
|
|
}
|
|
|
|
if(tex->imaflag & TEX_IMAROT) {
|
|
fy= texvec[0];
|
|
fx= texvec[1];
|
|
}
|
|
else {
|
|
fx= texvec[0];
|
|
fy= texvec[1];
|
|
}
|
|
|
|
if(ibuf->flags & IB_fields) {
|
|
if(R.r.mode & R_FIELDS) { /* field render */
|
|
if(R.flag & R_SEC_FIELD) { /* correction for 2nd field */
|
|
/* fac1= 0.5/( (float)ibuf->y ); */
|
|
/* fy-= fac1; */
|
|
}
|
|
else { /* first field */
|
|
fac1= 0.5f/( (float)ibuf->y );
|
|
fy+= fac1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* pixel coordinates */
|
|
|
|
minx= MIN3(dxt[0],dyt[0],dxt[0]+dyt[0] );
|
|
maxx= MAX3(dxt[0],dyt[0],dxt[0]+dyt[0] );
|
|
miny= MIN3(dxt[1],dyt[1],dxt[1]+dyt[1] );
|
|
maxy= MAX3(dxt[1],dyt[1],dxt[1]+dyt[1] );
|
|
|
|
/* tex_sharper has been removed */
|
|
|
|
minx= tex->filtersize*(maxx-minx)/2.0f;
|
|
miny= tex->filtersize*(maxy-miny)/2.0f;
|
|
|
|
if(tex->imaflag & TEX_IMAROT) SWAP(float, minx, miny);
|
|
|
|
if(minx>0.25) minx= 0.25;
|
|
else if(minx<0.00001f) minx= 0.00001f; /* side faces of unit-cube */
|
|
if(miny>0.25) miny= 0.25;
|
|
else if(miny<0.00001f) miny= 0.00001f;
|
|
|
|
|
|
/* repeat and clip */
|
|
|
|
/* watch it: imaprepeat is global value (see boxsample) */
|
|
imaprepeat= (tex->extend==TEX_REPEAT);
|
|
imapextend= (tex->extend==TEX_EXTEND);
|
|
|
|
if(tex->extend == TEX_CHECKER) {
|
|
int xs, ys, xs1, ys1, xs2, ys2, boundary;
|
|
|
|
xs= (int)floor(fx);
|
|
ys= (int)floor(fy);
|
|
|
|
// both checkers available, no boundary exceptions, checkerdist will eat aliasing
|
|
if( (tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN) ) {
|
|
fx-= xs;
|
|
fy-= ys;
|
|
}
|
|
else {
|
|
|
|
xs1= (int)floor(fx-minx);
|
|
ys1= (int)floor(fy-miny);
|
|
xs2= (int)floor(fx+minx);
|
|
ys2= (int)floor(fy+miny);
|
|
boundary= (xs1!=xs2) || (ys1!=ys2);
|
|
|
|
if(boundary==0) {
|
|
if( (tex->flag & TEX_CHECKER_ODD)==0) {
|
|
if((xs+ys) & 1);
|
|
else return 0;
|
|
}
|
|
if( (tex->flag & TEX_CHECKER_EVEN)==0) {
|
|
if((xs+ys) & 1) return 0;
|
|
}
|
|
fx-= xs;
|
|
fy-= ys;
|
|
}
|
|
else {
|
|
if(tex->flag & TEX_CHECKER_ODD) {
|
|
if((xs1+ys) & 1) fx-= xs2;
|
|
else fx-= xs1;
|
|
|
|
if((ys1+xs) & 1) fy-= ys2;
|
|
else fy-= ys1;
|
|
}
|
|
if(tex->flag & TEX_CHECKER_EVEN) {
|
|
if((xs1+ys) & 1) fx-= xs1;
|
|
else fx-= xs2;
|
|
|
|
if((ys1+xs) & 1) fy-= ys1;
|
|
else fy-= ys2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* scale around center, (0.5, 0.5) */
|
|
if(tex->checkerdist<1.0) {
|
|
fx= (fx-0.5)/(1.0-tex->checkerdist) +0.5;
|
|
fy= (fy-0.5)/(1.0-tex->checkerdist) +0.5;
|
|
minx/= (1.0-tex->checkerdist);
|
|
miny/= (1.0-tex->checkerdist);
|
|
}
|
|
}
|
|
|
|
if(tex->extend == TEX_CLIPCUBE) {
|
|
if(fx+minx<0.0 || fy+miny<0.0 || fx-minx>1.0 || fy-miny>1.0 || texvec[2]<-1.0 || texvec[2]>1.0) {
|
|
return 0;
|
|
}
|
|
}
|
|
else if(tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
|
|
if(fx+minx<0.0 || fy+miny<0.0 || fx-minx>1.0 || fy-miny>1.0) {
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
if(tex->extend==TEX_EXTEND) {
|
|
if(fx>1.0) fx = 1.0;
|
|
else if(fx<0.0) fx= 0.0;
|
|
}
|
|
else {
|
|
if(fx>1.0) fx -= (int)(fx);
|
|
else if(fx<0.0) fx+= 1-(int)(fx);
|
|
}
|
|
|
|
if(tex->extend==TEX_EXTEND) {
|
|
if(fy>1.0) fy = 1.0;
|
|
else if(fy<0.0) fy= 0.0;
|
|
}
|
|
else {
|
|
if(fy>1.0) fy -= (int)(fy);
|
|
else if(fy<0.0) fy+= 1-(int)(fy);
|
|
}
|
|
}
|
|
|
|
/* warning no return! */
|
|
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
|
|
ibuf->rect+= (ibuf->x*ibuf->y);
|
|
}
|
|
|
|
/* choice: */
|
|
if(tex->imaflag & TEX_MIPMAP) {
|
|
|
|
dx= minx;
|
|
dy= miny;
|
|
maxd= MAX2(dx, dy);
|
|
if(maxd>0.5) maxd= 0.5;
|
|
|
|
pixsize = 1.0f/ (float) MIN2(ibuf->x, ibuf->y);
|
|
|
|
curmap= 0;
|
|
previbuf= ibuf;
|
|
while(curmap<BLI_ARRAY_NELEMS(ima->mipmap) && ima->mipmap[curmap]) {
|
|
if(maxd < pixsize) break;
|
|
previbuf= ibuf;
|
|
ibuf= ima->mipmap[curmap];
|
|
pixsize= 1.0f / (float)MIN2(ibuf->x, ibuf->y); /* this used to be 1.0 */
|
|
curmap++;
|
|
}
|
|
|
|
if(previbuf!=ibuf || (tex->imaflag & TEX_INTERPOL)) {
|
|
/* sample at least 1 pixel */
|
|
if (minx < 0.5f / ima->ibuf->x) minx = 0.5f / ima->ibuf->x;
|
|
if (miny < 0.5f / ima->ibuf->y) miny = 0.5f / ima->ibuf->y;
|
|
}
|
|
|
|
if(tex->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
|
|
/* a bit extra filter */
|
|
minx*= 1.35f;
|
|
miny*= 1.35f;
|
|
|
|
boxsample(ibuf, fx-2.0f*minx, fy-2.0f*miny, fx+minx, fy+miny, &Tr, &Tg, &Tb, &Ta);
|
|
val1= Tr+Tg+Tb;
|
|
boxsample(ibuf, fx-minx, fy-2.0f*miny, fx+2.0f*minx, fy+miny, &fac1, &fac2, &fac3, &fac4);
|
|
val2= fac1+fac2+fac3;
|
|
boxsample(ibuf, fx-2.0f*minx, fy-miny, fx+minx, fy+2.0f*miny, &fac1, &fac2, &fac3, &fac4);
|
|
val3= fac1+fac2+fac3;
|
|
|
|
if(previbuf!=ibuf) { /* interpolate */
|
|
|
|
boxsample(previbuf, fx-2.0f*minx, fy-2.0f*miny, fx+minx, fy+miny, &fac1, &fac2, &fac3, &fac4);
|
|
|
|
/* calc rgb */
|
|
dx= 2.0f*(pixsize-maxd)/pixsize;
|
|
if(dx>=1.0f) {
|
|
Ta= fac4; Tb= fac3;
|
|
Tg= fac2; Tr= fac1;
|
|
}
|
|
else {
|
|
dy= 1.0f-dx;
|
|
Tb= dy*Tb+ dx*fac3;
|
|
Tg= dy*Tg+ dx*fac2;
|
|
Tr= dy*Tr+ dx*fac1;
|
|
if(Talpha) Ta= dy*Ta+ dx*fac4;
|
|
}
|
|
|
|
val1= dy*val1+ dx*(fac1+fac2+fac3);
|
|
boxsample(previbuf, fx-minx, fy-2.0f*miny, fx+2.0f*minx, fy+miny, &fac1, &fac2, &fac3, &fac4);
|
|
val2= dy*val2+ dx*(fac1+fac2+fac3);
|
|
boxsample(previbuf, fx-2.0f*minx, fy-miny, fx+minx, fy+2.0f*miny, &fac1, &fac2, &fac3, &fac4);
|
|
val3= dy*val3+ dx*(fac1+fac2+fac3);
|
|
}
|
|
|
|
/* don't switch x or y! */
|
|
tex->nor[0]= (val1-val2);
|
|
tex->nor[1]= (val1-val3);
|
|
}
|
|
else {
|
|
maxx= fx+minx;
|
|
minx= fx-minx;
|
|
maxy= fy+miny;
|
|
miny= fy-miny;
|
|
|
|
boxsample(ibuf, minx, miny, maxx, maxy, &Tr, &Tg, &Tb, &Ta);
|
|
|
|
if(previbuf!=ibuf) { /* interpolate */
|
|
boxsample(previbuf, minx, miny, maxx, maxy, &fac1, &fac2, &fac3, &fac4);
|
|
|
|
fx= 2.0f*(pixsize-maxd)/pixsize;
|
|
|
|
if(fx>=1.0) {
|
|
Ta= fac4; Tb= fac3;
|
|
Tg= fac2; Tr= fac1;
|
|
} else {
|
|
fy= 1.0f-fx;
|
|
Tb= fy*Tb+ fx*fac3;
|
|
Tg= fy*Tg+ fx*fac2;
|
|
Tr= fy*Tr+ fx*fac1;
|
|
if(Talpha) Ta= fy*Ta+ fx*fac4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if((tex->imaflag & TEX_INTERPOL)) {
|
|
/* sample 1 pixel minimum */
|
|
if (minx < 0.5f / ima->ibuf->x) minx = 0.5f / ima->ibuf->x;
|
|
if (miny < 0.5f / ima->ibuf->y) miny = 0.5f / ima->ibuf->y;
|
|
}
|
|
|
|
if(tex->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
|
|
|
|
/* a bit extra filter */
|
|
minx*= 1.35f;
|
|
miny*= 1.35f;
|
|
|
|
boxsample(ibuf, fx-2.0f*minx, fy-2.0f*miny, fx+minx, fy+miny, &Tr, &Tg, &Tb, &Ta);
|
|
val1= Tr+Tg+Tb;
|
|
|
|
boxsample(ibuf, fx-minx, fy-2.0f*miny, fx+2.0f*minx, fy+miny, &fac1, &fac2, &fac3, &fac4);
|
|
val2= fac1+fac2+fac3;
|
|
|
|
boxsample(ibuf, fx-2.0f*minx, fy-miny, fx+miny, fy+2.0f*miny, &fac1, &fac2, &fac3, &fac4);
|
|
val3= fac1+fac2+fac3;
|
|
|
|
/* don't switch x or y! */
|
|
tex->nor[0]= (val1-val2);
|
|
tex->nor[1]= (val1-val3);
|
|
}
|
|
else {
|
|
boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, &Tr, &Tg, &Tb, &Ta);
|
|
}
|
|
}
|
|
|
|
BRICONRGB;
|
|
|
|
if(tex->imaflag & TEX_CALCALPHA) {
|
|
Ta= Tin= Ta*MAX3(Tr, Tg, Tb);
|
|
}
|
|
else Tin= Ta;
|
|
if(tex->flag & TEX_NEGALPHA) Ta= 1.0f-Ta;
|
|
|
|
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
|
|
ibuf->rect-= (ibuf->x*ibuf->y);
|
|
}
|
|
|
|
if(tex->nor && (tex->imaflag & TEX_NORMALMAP)) {
|
|
tex->nor[0]= 0.5-Tr;
|
|
tex->nor[1]= 0.5-Tg;
|
|
tex->nor[2]= 0.5-Tb;
|
|
}
|
|
}
|
|
else {
|
|
Tin= 0.0f;
|
|
return 0;
|
|
}
|
|
|
|
if(tex->nor) return 3;
|
|
else return 1;
|
|
}
|
|
|