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, ¤t_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 ¤t_display->cur_transform;
+ return &target->transform;
}
/* Function: al_identity_transform