Re: [AD] per-thread transformation and blending mode

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


On 2010-06-26, Peter Wang <novalazy@xxxxxxxxxx> wrote:
> On 2010-06-24, Trent Gamblin <trent@xxxxxxxxxx> wrote:
> > On Thu, June 24, 2010 5:18 pm, Peter Wang said:
> > >> Another idea would be to keep it per-target-bitmap. For example if you
> > >> use transformations to make the coordinate system go from 0,0 to 1,1 for
> > >> the whole backbuffer it would be annoying if you have to reset it each
> > >> time you switch back from drawing to another bitmap.
> > >
> > > Good idea.  Each bitmap has its own clipping rectangle, and I think
> > > transformations go along with that.
> > >
> > > I *think* I would prefer the blending mode to be per-thread, though.
> > 
> > In practice I find that transformations and blending are things that change
> > often, even if the target bitmap doesn't change. If you're drawing a 3d (or
> > say a 2d skeletal animation), you're going to be switching transforms a lot,
> > and the case is the same for blending when you're drawing complicated scenes.
> > Therefore, I think they should go in the most logical place. I'm not sure
> > which of TLS and bitmap is the most logical, but I'd prefer TLS unless I'm
> > missing something. But actually the example quoted is something that would
> > happen often too... so I could be wrong.
> 
> I think one of the main uses of transformations would be to set up a
> logical coordinate system for the display.  From that perspective, it
> would make sense for transformations to be per-bitmap.
> 
> It would make sub-bitmaps even more useful, too.  You could set up a
> game-oriented coordinate system for the whole screen, and on top of that
> you create an overlay as a sub-bitmap and use the usual pixel-based
> coordinate system.

I managed to implement per-bitmap transforms for OpenGL, and I tried out
the subbitmap-overlay-transform idea in ex_tranform (patch attached).  I
think it's pretty cool.  If others agree I would like to go ahead with it.
I'd also need someone to make the changes for D3D.

Still trying to think of a convincing argument either way for blending modes.

Peter
diff --git a/examples/ex_transform.c b/examples/ex_transform.c
index 051e13d..50a14bd 100644
--- a/examples/ex_transform.c
+++ b/examples/ex_transform.c
@@ -12,16 +12,17 @@ int main(int argc, const char *argv[])
     const char *filename;
     ALLEGRO_DISPLAY *display;
     ALLEGRO_BITMAP *buffer, *bitmap, *subbitmap, *buffer_subbitmap;
+    ALLEGRO_BITMAP *overlay;
     ALLEGRO_TIMER *timer;
     ALLEGRO_EVENT_QUEUE *queue;
     ALLEGRO_TRANSFORM transform;
-    ALLEGRO_TRANSFORM identity;
     bool software = false;
     bool redraw = false;
     bool blend = false;
     bool use_subbitmap = false;
     int w, h;
     ALLEGRO_FONT* font;
+    ALLEGRO_FONT* soft_font;
 
     if (argc > 1) {
        filename = argv[1];
@@ -48,6 +49,7 @@ int main(int argc, const char *argv[])
     }
     
     subbitmap = al_create_sub_bitmap(al_get_backbuffer(display), 50, 50, 640 - 50, 480 - 50);
+    overlay = al_create_sub_bitmap(al_get_backbuffer(display), 100, 100, 300, 50);
     
     al_set_window_title(display, filename);
 
@@ -55,13 +57,17 @@ int main(int argc, const char *argv[])
     if (!bitmap) {
        abort_example("%s not found or failed to load\n", filename);
     }
+    font = al_load_font("data/bmpfont.tga", 0, 0);
+    if (!font) {
+       abort_example("data/bmpfont.tga not found or failed to load\n");
+    }
+
     al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
     buffer = al_create_bitmap(640, 480);
     buffer_subbitmap = al_create_sub_bitmap(buffer, 50, 50, 640 - 50, 480 - 50);
-    al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);
-    
-    font = al_load_font("data/bmpfont.tga", 0, 0);
-    if (!font) {
+
+    soft_font = al_load_font("data/bmpfont.tga", 0, 0);
+    if (!soft_font) {
        abort_example("data/bmpfont.tga not found or failed to load\n");
     }
 
@@ -74,8 +80,11 @@ int main(int argc, const char *argv[])
     
     w = al_get_bitmap_width(bitmap);
     h = al_get_bitmap_height(bitmap);
-    
-    al_identity_transform(&identity);
+
+    al_set_target_bitmap(overlay);
+    al_identity_transform(&transform);
+    al_rotate_transform(&transform, -0.06);
+    al_use_transform(&transform);
 
     while (1) {
         ALLEGRO_EVENT event;
@@ -85,6 +94,12 @@ int main(int argc, const char *argv[])
         if (event.type == ALLEGRO_EVENT_KEY_DOWN) {
             if (event.keyboard.keycode == ALLEGRO_KEY_S) {
                software = !software;
+               if (software) {
+                  /* Restore identity transform on display bitmap. */
+                  ALLEGRO_TRANSFORM identity;
+                  al_identity_transform(&identity);
+                  al_use_transform(&identity);
+               }
             } else if (event.keyboard.keycode == ALLEGRO_KEY_L) {
                blend = !blend;
             } else if (event.keyboard.keycode == ALLEGRO_KEY_B) {
@@ -107,12 +122,6 @@ int main(int argc, const char *argv[])
             else
                tint = al_map_rgba_f(1, 1, 1, 1);
             
-            al_identity_transform(&transform);
-            al_translate_transform(&transform, -640 / 2, -480 / 2);
-            al_scale_transform(&transform, 0.15 + sin(t / 5), 0.15 + cos(t / 5));
-            al_rotate_transform(&transform, t / 50);
-            al_translate_transform(&transform, 640 / 2, 480 / 2);
-            
             if(software) {
                if(use_subbitmap) {
                   al_set_target_bitmap(buffer);
@@ -130,9 +139,16 @@ int main(int argc, const char *argv[])
                   al_set_target_backbuffer(display);
                }
             }
-            
+
+            /* Set the transformation on the target bitmap. */
+            al_identity_transform(&transform);
+            al_translate_transform(&transform, -640 / 2, -480 / 2);
+            al_scale_transform(&transform, 0.15 + sin(t / 5), 0.15 + cos(t / 5));
+            al_rotate_transform(&transform, t / 50);
+            al_translate_transform(&transform, 640 / 2, 480 / 2);
             al_use_transform(&transform);
 
+            /* Draw some stuff */
             al_clear_to_color(al_map_rgb_f(0, 0, 0));
             al_draw_tinted_bitmap(bitmap, tint, 0, 0, 0);
             al_draw_tinted_scaled_bitmap(bitmap, tint, w / 4, h / 4, w / 2, h / 2, w, 0, w / 2, h / 4, 0);//ALLEGRO_FLIP_HORIZONTAL);
@@ -144,16 +160,24 @@ int main(int argc, const char *argv[])
 
             al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
             if(software) {
-               al_draw_text(font, al_map_rgba_f(1, 1, 1, 1),
+               al_draw_text(soft_font, al_map_rgba_f(1, 1, 1, 1),
                   640 / 2, 430, ALLEGRO_ALIGN_CENTRE, "Software Rendering");
-               al_use_transform(&identity);
                al_set_target_backbuffer(display);
                al_draw_bitmap(buffer, 0, 0, 0);
-               al_use_transform(&transform);
             } else {
                al_draw_text(font, al_map_rgba_f(1, 1, 1, 1),
                   640 / 2, 430, ALLEGRO_ALIGN_CENTRE, "Hardware Rendering");
             }
+
+            /* Each target bitmap has its own transformation matrix, so this
+             * overlay is unaffected by the transformations set earlier.
+             */
+            al_set_target_bitmap(overlay);
+            al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);
+            al_draw_text(font, al_map_rgba_f(1, 1, 0, 1),
+               0, 10, ALLEGRO_ALIGN_LEFT, "hello!");
+
+            al_set_target_backbuffer(display);
             al_flip_display();
         }
     }
diff --git a/include/allegro5/internal/aintern_bitmap.h b/include/allegro5/internal/aintern_bitmap.h
index ecbfa35..463bfd8 100644
--- a/include/allegro5/internal/aintern_bitmap.h
+++ b/include/allegro5/internal/aintern_bitmap.h
@@ -52,6 +52,9 @@ struct ALLEGRO_BITMAP
    int lock_flags;
    ALLEGRO_LOCKED_REGION locked_region;
 
+   /* Transformation for this bitmap */
+   ALLEGRO_TRANSFORM transform;
+
    /* Info for sub-bitmaps */
    ALLEGRO_BITMAP *parent;
    int xofs;
diff --git a/include/allegro5/internal/aintern_display.h b/include/allegro5/internal/aintern_display.h
index ca1d158..b8ab4a5 100644
--- a/include/allegro5/internal/aintern_display.h
+++ b/include/allegro5/internal/aintern_display.h
@@ -65,7 +65,7 @@ struct ALLEGRO_DISPLAY_INTERFACE
    void (*flush_vertex_cache)(ALLEGRO_DISPLAY *d);
    void* (*prepare_vertex_cache)(ALLEGRO_DISPLAY *d, int num_new_vertices);
    
-   void (*update_transformation)(ALLEGRO_DISPLAY* d);
+   void (*update_transformation)(ALLEGRO_DISPLAY* d, ALLEGRO_BITMAP *target);
 
    void (*shutdown)(void);
 };
@@ -119,7 +119,6 @@ struct ALLEGRO_DISPLAY
    void* vertex_cache;
    uintptr_t cache_texture;
    
-   ALLEGRO_TRANSFORM cur_transform;
    ALLEGRO_BLENDER cur_blender;
    
    void (*display_invalidated)(ALLEGRO_DISPLAY*, bool);
diff --git a/src/bitmap.c b/src/bitmap.c
index ba67a8a..f857e48 100644
--- a/src/bitmap.c
+++ b/src/bitmap.c
@@ -56,6 +56,7 @@ static ALLEGRO_BITMAP *_al_create_memory_bitmap(int w, int h)
    bitmap->cl = bitmap->ct = 0;
    bitmap->cr_excl = w;
    bitmap->cb_excl = h;
+   al_identity_transform(&bitmap->transform);
    bitmap->parent = NULL;
    bitmap->xofs = bitmap->yofs = 0;
    bitmap->memory = al_malloc(pitch * h);
@@ -108,6 +109,7 @@ ALLEGRO_BITMAP *al_create_bitmap(int w, int h)
    bitmap->ct = 0;
    bitmap->cr_excl = w;
    bitmap->cb_excl = h;
+   al_identity_transform(&bitmap->transform);
    bitmap->parent = NULL;
    bitmap->xofs = 0;
    bitmap->yofs = 0;
@@ -645,6 +647,7 @@ ALLEGRO_BITMAP *al_create_sub_bitmap(ALLEGRO_BITMAP *parent,
    bitmap->cl = bitmap->ct = 0;
    bitmap->cr_excl = w;
    bitmap->cb_excl = h;
+   al_identity_transform(&bitmap->transform);
    bitmap->parent = parent;
    bitmap->xofs = x;
    bitmap->yofs = y;
diff --git a/src/opengl/ogl_bitmap.c b/src/opengl/ogl_bitmap.c
index 39a3986..11c8429 100644
--- a/src/opengl/ogl_bitmap.c
+++ b/src/opengl/ogl_bitmap.c
@@ -1056,6 +1056,7 @@ ALLEGRO_BITMAP *_al_ogl_create_bitmap(ALLEGRO_DISPLAY *d, int w, int h)
    bitmap->bitmap.ct = 0;
    bitmap->bitmap.cr_excl = w;
    bitmap->bitmap.cb_excl = h;
+   al_identity_transform(&bitmap->bitmap.transform);  // XXX back and front buffers should share a transform
 
    bitmap->true_w = true_w;
    bitmap->true_h = true_h;
diff --git a/src/opengl/ogl_draw.c b/src/opengl/ogl_draw.c
index 2b4f880..28715fc 100644
--- a/src/opengl/ogl_draw.c
+++ b/src/opengl/ogl_draw.c
@@ -120,15 +120,6 @@ static void ogl_draw_pixel(ALLEGRO_DISPLAY *d, float x, float y,
       return;
    }
 
-   /* For sub bitmaps. */
-   if(target->parent) {
-      glMatrixMode(GL_MODELVIEW);
-      glPushMatrix();
-      glLoadIdentity();
-      glTranslatef(target->xofs, target->yofs, 0);
-      glMultMatrixf((float*)(d->cur_transform.m));
-   }
-
    vert[0] = x;
    vert[1] = y;
 
@@ -141,10 +132,6 @@ static void ogl_draw_pixel(ALLEGRO_DISPLAY *d, float x, float y,
 
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
-   
-   if(target->parent) {
-      glPopMatrix();
-   }
 }
 
 static void* ogl_prepare_vertex_cache(ALLEGRO_DISPLAY* disp, 
@@ -169,21 +156,11 @@ static void ogl_flush_vertex_cache(ALLEGRO_DISPLAY* disp)
 {
    GLboolean on;
    GLuint current_texture;
-   ALLEGRO_BITMAP* target;
    if(!disp->vertex_cache)
       return;
    if(disp->num_cache_vertices == 0)
       return;
       
-   target = al_get_target_bitmap();
-   if(target->parent) {
-      glMatrixMode(GL_MODELVIEW);
-      glPushMatrix();
-      glLoadIdentity();
-      glTranslatef(target->xofs, target->yofs, 0);
-      glMultMatrixf((float*)(disp->cur_transform.m));
-   }
-   
    glGetBooleanv(GL_TEXTURE_2D, &on);
    if (!on) {
       glEnable(GL_TEXTURE_2D);
@@ -209,20 +186,27 @@ static void ogl_flush_vertex_cache(ALLEGRO_DISPLAY* disp)
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
    
-   if(target->parent) {
-      glPopMatrix();
-   }
-   
    disp->num_cache_vertices = 0;
    if (!on) {
       glDisable(GL_TEXTURE_2D);
    }
 }
 
-static void ogl_update_transformation(ALLEGRO_DISPLAY* disp)
+static void ogl_update_transformation(ALLEGRO_DISPLAY* disp,
+   ALLEGRO_BITMAP *target)
 {
+   (void)disp;
+
    glMatrixMode(GL_MODELVIEW);
-   glLoadMatrixf((float*)(disp->cur_transform.m));
+   if (target->parent) {
+      /* Sub-bitmaps have an additional offset. */
+      glLoadIdentity();
+      glTranslatef(target->xofs, target->yofs, 0);
+      glMultMatrixf((float*)(target->transform.m));
+   }
+   else {
+      glLoadMatrixf((float *)target->transform.m);
+   }
 }
 
 /* Add drawing commands to the vtable. */
diff --git a/src/tls.c b/src/tls.c
index c60800d..0cd14c7 100644
--- a/src/tls.c
+++ b/src/tls.c
@@ -366,7 +366,7 @@ ALLEGRO_DISPLAY *_al_get_current_display(void)
 
    if (!(tls->memory_display.flags & ALLEGRO_INTERNAL)) {
       tls->memory_display.flags |= ALLEGRO_INTERNAL;
-      al_identity_transform(&tls->memory_display.cur_transform);
+      //al_identity_transform(&tls->memory_display.cur_transform);
       _al_initialize_blender(&tls->memory_display.cur_blender);
    }
    return &tls->memory_display;
@@ -425,6 +425,8 @@ void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap)
          new_display->vt &&
          new_display->vt->set_target_bitmap) {
       new_display->vt->set_target_bitmap(new_display, bitmap);
+
+      new_display->vt->update_transformation(new_display, bitmap);
    }
 }
 
@@ -546,7 +548,11 @@ void al_store_state(ALLEGRO_STATE *state, int flags)
    }
    
    if (flags & ALLEGRO_STATE_TRANSFORM) {
-      stored->stored_transform = _al_get_current_display()->cur_transform;
+      ALLEGRO_BITMAP *target = al_get_target_bitmap();
+      if (!target)
+         al_identity_transform(&stored->stored_transform);
+      else
+         stored->stored_transform = target->transform;
    }
 }
 #undef _STORE
@@ -598,7 +604,9 @@ void al_restore_state(ALLEGRO_STATE const *state)
    }
    
    if (flags & ALLEGRO_STATE_TRANSFORM) {
-      _al_get_current_display()->cur_transform = stored->stored_transform;
+      ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
+      if (bitmap)
+         al_use_transform(&stored->stored_transform);
    }
 }
 #undef _STORE
diff --git a/src/transformations.c b/src/transformations.c
index 7a437ab..a56a8cb 100644
--- a/src/transformations.c
+++ b/src/transformations.c
@@ -18,8 +18,9 @@
 #include "allegro5/allegro5.h"
 #include "allegro5/internal/aintern.h"
 #include ALLEGRO_INTERNAL_HEADER
-#include "allegro5/internal/aintern_system.h"
+#include "allegro5/internal/aintern_bitmap.h"
 #include "allegro5/internal/aintern_display.h"
+#include "allegro5/internal/aintern_system.h"
 #include <math.h>
 
 /* ALLEGRO_DEBUG_CHANNEL("transformations") */
@@ -38,24 +39,33 @@ void al_copy_transform(const ALLEGRO_TRANSFORM *src, ALLEGRO_TRANSFORM *dest)
  */
 void al_use_transform(const ALLEGRO_TRANSFORM *trans)
 {
-   ALLEGRO_DISPLAY *current_display = _al_get_current_display();
-   ASSERT(current_display);
-   ASSERT(trans);
+   ALLEGRO_BITMAP *target = al_get_target_bitmap();
+   ALLEGRO_DISPLAY *display;
+   ASSERT(target);
+
+   /* Changes to a back buffer should affect the front buffer, and vice versa.
+    * Currently we rely on the fact that in the OpenGL drivers the back buffer
+    * and front buffer bitmaps are exactly the same, and the DirectX driver
+    * doesn't support front buffer bitmaps.
+    */
+
+   al_copy_transform(trans, &target->transform);
 
-   al_copy_transform(trans, &current_display->cur_transform);
-   if (current_display->vt) {
-      current_display->vt->update_transformation(current_display);
+   display = target->display;
+   if (display) {
+      display->vt->update_transformation(display, target);
    }
 }
 
 /* Function: al_get_current_transform
  */
-const ALLEGRO_TRANSFORM *al_get_current_transform()
+// XXX change this to al_get_bitmap_transform(ALLEGRO_BITMAP *)
+const ALLEGRO_TRANSFORM *al_get_current_transform(void)
 {
-   ALLEGRO_DISPLAY *current_display = _al_get_current_display();
-   ASSERT(current_display);
+   ALLEGRO_BITMAP *target = al_get_target_bitmap();
+   ASSERT(target);
 
-   return &current_display->cur_transform;
+   return &target->transform;
 }
 
 /* Function: al_identity_transform


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/