work by default for power-of-two textures.
Improved texture painting across different images a bit.
*/
void set_mipmap(int mipmap);
-/**
- * Returns the current setting for mipmapping.
- */
-int get_mipmap(void);
-
/**
* Enables or disable linear mipmap setting for realtime images (textures).
* Note that this will will destroy all texture bindings in OpenGL.
void free_all_realtime_images(void);
void make_repbind(struct Image *ima);
int set_tpage(struct MTFace *tface);
+
+void texpaint_enable_mipmap(void);
+void texpaint_disable_mipmap(void);
+
void draw_tface_mesh(struct Object *ob, struct Mesh *me, int dt);
struct EdgeHash *get_tface_mesh_marked_edge_info(struct Mesh *me);
void init_realtime_GL(void);
#define IMA_NOCOLLECT 32
/* tpageflag */
-#define IMA_TILES 1
-#define IMA_TWINANIM 2
-#define IMA_COLCYCLE 4 /* Depreciated */
+#define IMA_TILES 1
+#define IMA_TWINANIM 2
+#define IMA_COLCYCLE 4 /* Depreciated */
+#define IMA_MIPMAP_COMPLETE 8 /* all mipmap levels in OpenGL texture set? */
#endif
}
}
-
/**
* Returns the current setting for mipmapping.
*/
-int get_mipmap(void)
+static int get_mipmap(void)
{
- return fDoMipMap;
+ return fDoMipMap && (!(G.f & G_TEXTUREPAINT));
}
/**
}
glBindTexture( GL_TEXTURE_2D, *bind);
- if (!fDoMipMap)
+ if (!get_mipmap())
{
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);
} 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);
+
+ ima->tpageflag |= IMA_MIPMAP_COMPLETE;
}
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
void update_realtime_image(Image *ima, int x, int y, int w, int h)
{
- if (ima->repbind || fDoMipMap || !ima->bindcode || !ima->ibuf ||
+ if (ima->repbind || get_mipmap() || !ima->bindcode || !ima->ibuf ||
(!is_pow2(ima->ibuf->x) || !is_pow2(ima->ibuf->y)) ||
(w == 0) || (h == 0)) {
/* these special cases require full reload still */
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
+
+ if(ima->tpageflag & IMA_MIPMAP_COMPLETE)
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
}
if(ima->bindcode) {
glDeleteTextures(1, (GLuint *)&ima->bindcode);
ima->bindcode= 0;
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
if(ima->repbind) {
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
MEM_freeN(ima->repbind);
ima->repbind= NULL;
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
}
{
Image* ima;
- ima= G.main->image.first;
- while(ima) {
+ for(ima=G.main->image.first; ima; ima=ima->id.next)
free_realtime_image(ima);
- ima= ima->id.next;
+}
+
+/* these two functions are called on entering and exiting texture paint mode,
+ temporary disabling/enabling mipmapping on all images for quick texture
+ updates with glTexSubImage2D. images that didn't change don't have to be
+ re-uploaded to OpenGL */
+void texpaint_disable_mipmap(void)
+{
+ Image* ima;
+
+ if(!fDoMipMap)
+ return;
+
+ for(ima=G.main->image.first; ima; ima=ima->id.next) {
+ if(ima->bindcode) {
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ }
+}
+
+void texpaint_enable_mipmap(void)
+{
+ Image* ima;
+
+ if(!fDoMipMap)
+ return;
+
+ for(ima=G.main->image.first; ima; ima=ima->id.next) {
+ if(ima->bindcode) {
+ if(ima->tpageflag & IMA_MIPMAP_COMPLETE) {
+ int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
+
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ else
+ free_realtime_image(ima);
+ }
}
}
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
MEM_freeN(ima->repbind);
ima->repbind= 0;
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
ima->totbind= ima->xrep*ima->yrep;
if(ima->totbind>1) {
if(G.f & G_VERTEXPAINT)
set_vpaint();
if(G.f & G_TEXTUREPAINT)
- G.f &= ~G_TEXTUREPAINT;
+ set_texturepaint();
if(G.f & G_WEIGHTPAINT)
set_wpaint();
if(me)
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
- if(G.f & G_TEXTUREPAINT)
+ if(G.f & G_TEXTUREPAINT) {
G.f &= ~G_TEXTUREPAINT;
+ texpaint_enable_mipmap();
+ }
else if (me) {
G.f |= G_TEXTUREPAINT;
brush_check_exists(&G.scene->toolsettings->imapaint.brush);
+ texpaint_disable_mipmap();
}
allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
}
/* Get the barycentric coordinates of 2d point p in 2d triangle (v1, v2, v3) */
if (texpaint) {
- /* pick face and image */
+ /* pick new face and image */
if (facesel_face_pick(s->me, mval, &newfaceindex, 0)) {
newimage = (Image*)((s->me->mtface+newfaceindex)->tpage);
- texpaint_pick_uv(s->ob, s->me, newfaceindex, mval, newuv);
+ if(newimage && newimage->ibuf && newimage->ibuf->rect)
+ texpaint_pick_uv(s->ob, s->me, newfaceindex, mval, newuv);
+ else
+ newimage = NULL;
}
else
newuv[0] = newuv[1] = 0.0f;
/* see if stroke is broken, and if so finish painting in old position */
if (s->image) {
- if (newimage == s->image) {
- texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
- texpaint_pick_uv(s->ob, s->me, newfaceindex, prevmval, bkuv);
+ texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
+ texpaint_pick_uv(s->ob, s->me, newfaceindex, prevmval, bkuv);
+
+ if (newimage == s->image)
breakstroke= texpaint_break_stroke(s->uv, fwuv, bkuv, newuv);
- }
else
breakstroke= 1;
}
+ else
+ fwuv[0]= fwuv[1]= 0.0f;
if (breakstroke) {
texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
- redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, fwuv,
- time, 1, pressure);
+ redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint,
+ fwuv, time, 1, pressure);
imapaint_clear_partial_redraw();
brush_painter_break_stroke(painter);
}
/* paint in new image */
if (newimage) {
if (breakstroke)
- redraw|= imapaint_paint_sub_stroke(s, painter, newimage, texpaint,
- bkuv, time, 0, pressure);
- redraw|= imapaint_paint_sub_stroke(s, painter, newimage, texpaint, newuv,
- time, 1, pressure);
+ redraw|= imapaint_paint_sub_stroke(s, painter, newimage,
+ texpaint, bkuv, time, 0, pressure);
+ redraw|= imapaint_paint_sub_stroke(s, painter, newimage, texpaint,
+ newuv, time, 1, pressure);
}
/* update state */
init_realtime_GL();
init_gl_stuff();
+ if(G.f & G_TEXTUREPAINT)
+ texpaint_enable_mipmap();
+
if(G.scene->camera==0 || G.scene->camera->type!=OB_CAMERA)
error("no (correct) camera");
static void RestoreState(void)
{
+ if(G.f & G_TEXTUREPAINT)
+ texpaint_disable_mipmap();
+
curarea->win_swap = 0;
curarea->head_swap=0;
allqueue(REDRAWVIEW3D, 1);
set_faceselect();
if(G.f & G_VERTEXPAINT)
set_vpaint();
- if(G.f & G_TEXTUREPAINT) {
- G.f &= ~G_TEXTUREPAINT;
- allqueue(REDRAWVIEW3D, 0);
- allqueue(REDRAWBUTSEDIT, 0);
- }
+ if(G.f & G_TEXTUREPAINT)
+ set_texturepaint();
if(G.f & G_WEIGHTPAINT)
set_wpaint();
}