Re: [AD] depth buffer API

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


On Sun, 13 May 2012 16:36:13 +0200
Elias Pschernig <elias.pschernig@xxxxxxxxxx> wrote:
> 
> Actually, it shouldn't be a big problem - we can simply re-use it. And
> we should, else it just makes it likely to use the wrong one,
> considering how C doesn't check for using the right enum type.
> 

Implemented it, works nicely both in Linux/OpenGL and Wine/D3D.

It seems for some reason we always had the depth test enabled in D3D
so far (but I don't really know the D3D code well enough to be sure I
follow everything). This patch makes it so the depth test is disabled
by default though and you have to enable it with al_set_render_state.
(Like it always was under Linux/OSX).

I'll try and update the Wine/OpenGL and OSX/OpenGL versions (should be
easy) and add an example, then commit.

As the TODO comments say, in the future we probably should optimize
things like this to not have so many redundant state changes. With
OpenGL each gl* call is quite a performance hit (not sure about
SetRenderState with D3D, probably similar).

I also want a way to make the depth buffer work when drawing to an
off-screen bitmap, but I'm not really sure yet what is needed for that.
With OpenGL, we probably need to attach a depth buffer to each FBO we
create or something.
diff --git a/cmake/FileList.cmake b/cmake/FileList.cmake
index 0c85b36..d231a07 100644
--- a/cmake/FileList.cmake
+++ b/cmake/FileList.cmake
@@ -63,6 +63,7 @@ set(ALLEGRO_SRC_WIN_FILES
 set(ALLEGRO_SRC_D3D_FILES
     src/win/d3d_bmp.cpp
     src/win/d3d_disp.cpp
+    src/win/d3d_render_state.cpp
     )
 
 set(ALLEGRO_SRC_OPENGL_FILES
@@ -71,6 +72,7 @@ set(ALLEGRO_SRC_OPENGL_FILES
     src/opengl/ogl_display.c
     src/opengl/ogl_draw.c
     src/opengl/ogl_lock.c
+    src/opengl/ogl_render_state.c
     )
 
 set(ALLEGRO_SRC_WGL_FILES
diff --git a/docs/src/refman/graphics.txt b/docs/src/refman/graphics.txt
index cddf03f..ccef8a2 100644
--- a/docs/src/refman/graphics.txt
+++ b/docs/src/refman/graphics.txt
@@ -560,7 +560,19 @@ the last display created in a thread.
 
 Clear the complete target bitmap, but confined by the clipping rectangle.
 
-See also: [ALLEGRO_COLOR], [al_set_clipping_rectangle]
+See also: [ALLEGRO_COLOR], [al_set_clipping_rectangle], [al_clear_depth_buffer]
+
+### API: al_clear_depth_buffer
+
+Clear the depth buffer (confined by the clipping rectangle) to the given
+value. A depth buffer is only availabe if it was requested with
+[al_set_new_display_option] and the requirement could be met by the
+[al_crate_display] call creating the current display. Operations involving the
+depth buffer (not this clear operation though) are also affected by
+[al_set_render_state].
+
+See also: [al_clear_to_color], [al_set_clipping_rectangle], [al_set_render_state],
+   [al_set_new_display_option]
 
 ### API: al_draw_bitmap
 
@@ -1290,3 +1302,72 @@ handler.
 
 See also: [al_save_bitmap], [al_register_bitmap_saver_f], [al_init_image_addon]
 
+
+## Render State
+
+### API: ALLEGRO_RENDER_STATE
+
+Possible render states are:
+
+ALLEGRO_ALPHA_TEST
+:   If this is set to 1, the values of ALLEGRO_ALPHA_FUNCTION and
+    ALLEGRO_ALPHA_TEST_VALUE define a comparison function which is performed
+    for each pixel. Only if it evaluates to true the pixel is written. Otherwise
+    no subsequent processing (like depth test or blending) is performed.
+
+ALLEGRO_ALPHA_FUNCTION
+:   One of [ALLEGRO_RENDER_FUNCTION], only used when ALLEGRO_ALPHA_TEST is 1.
+
+ALLEGRO_ALPHA_TEST_VALUE
+:   Only used when ALLEGRO_ALPHA_TEST is 1.
+
+ALLEGRO_WRITE_MASK
+:   This determines how the framebuffer and depthbuffer are updated whenever a
+    pixel is written (if alpha and/or depth testing is enabled, after all such
+    enabled tests succeed). Depth values are only written if ALLEGRO_DEPTH_TEST
+    is 1, in addition to the write mask flag being set.
+
+ALLEGRO_DEPTH_TEST
+:   If this is set to 1, compare the depth value of any newly written pixels with
+    the depth value already in the buffer, according to ALLEGRO_DEPTH_FUNCTION.
+    Allegro primitives with no explicit z coordinate will write a value of 0 into
+    the depth buffer.
+
+ALLEGRO_DEPTH_FUNCTION
+:   One of [ALLEGRO_RENDER_FUNCTION], only used when ALLEGRO_DEPTH_TEST is 1.
+
+See also: [al_set_render_state]
+
+### API: ALLEGRO_RENDER_FUNCTION
+
+Possible functions are:
+
+-   ALLEGRO_RENDER_NEVER
+-   ALLEGRO_RENDER_ALWAYS
+-   ALLEGRO_RENDER_LESS
+-   ALLEGRO_RENDER_EQUAL 
+-   ALLEGRO_RENDER_LESS_EQUAL   
+-   ALLEGRO_RENDER_GREATER        
+-   ALLEGRO_RENDER_NOT_EQUAL
+-   ALLEGRO_RENDER_GREATER_EQUAL
+
+### API: ALLEGRO_WRITE_MASK_FLAGS
+
+Each enabled bit means the corresponding value is written, a disabled bit
+means it is not.
+
+-  ALLEGRO_MASK_RED
+-  ALLEGRO_MASK_GREEN
+-  ALLEGRO_MASK_BLUE
+-  ALLEGRO_MASK_ALPHA
+-  ALLEGRO_MASK_DEPTH
+-  ALLEGRO_MASK_RGB Same as RED | GREEN | BLUE.
+-  ALLEGRO_MASK_RGBA Same as RGB | ALPHA.
+
+### API: al_set_render_state
+
+Set one of several render attributes. This function does nothing if the target
+bitmap is a memory bitmap.
+
+See also: [ALLEGRO_RENDER_STATE], [ALLEGRO_RENDER_FUNCTION],
+   [ALLEGRO_WRITE_MASK_FLAGS]
diff --git a/include/allegro5/allegro.h b/include/allegro5/allegro.h
index 302f09e..7c24f07 100644
--- a/include/allegro5/allegro.h
+++ b/include/allegro5/allegro.h
@@ -48,6 +48,7 @@
 #include "allegro5/transformations.h"
 #include "allegro5/bitmap_io.h"
 #include "allegro5/bitmap.h"
+#include "allegro5/render_state.h"
 
 #include "allegro5/tls.h"
 
diff --git a/include/allegro5/display.h b/include/allegro5/display.h
index f766d8b..40599f9 100644
--- a/include/allegro5/display.h
+++ b/include/allegro5/display.h
@@ -160,6 +160,7 @@ AL_FUNC(ALLEGRO_EVENT_SOURCE *, al_get_display_event_source, (ALLEGRO_DISPLAY *d
 /* Primitives */
 AL_FUNC(void, al_clear_to_color, (ALLEGRO_COLOR color));
 AL_FUNC(void, al_draw_pixel, (float x, float y, ALLEGRO_COLOR color));
+AL_FUNC(void, al_clear_depth_buffer, (float x));
 
 AL_FUNC(void, al_set_display_icon, (ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *icon));
 
diff --git a/include/allegro5/internal/aintern_bitmap.h b/include/allegro5/internal/aintern_bitmap.h
index 10a1807..598a7be 100644
--- a/include/allegro5/internal/aintern_bitmap.h
+++ b/include/allegro5/internal/aintern_bitmap.h
@@ -3,6 +3,7 @@
 
 #include "allegro5/display.h"
 #include "allegro5/bitmap.h"
+#include "allegro5/render_state.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/allegro5/internal/aintern_direct3d.h b/include/allegro5/internal/aintern_direct3d.h
index d136106..85bb2aa 100644
--- a/include/allegro5/internal/aintern_direct3d.h
+++ b/include/allegro5/internal/aintern_direct3d.h
@@ -79,6 +79,7 @@ typedef struct ALLEGRO_DISPLAY_D3D
 AL_FUNC(void, _al_d3d_set_blender, (ALLEGRO_DISPLAY_D3D *disp));
 
 void _al_d3d_destroy_bitmap(ALLEGRO_BITMAP *bitmap);
+void _al_d3d_update_render_state(ALLEGRO_DISPLAY *display);
 
 
 #ifdef __cplusplus
diff --git a/include/allegro5/internal/aintern_display.h b/include/allegro5/internal/aintern_display.h
index 7224c81..7e9dec5 100644
--- a/include/allegro5/internal/aintern_display.h
+++ b/include/allegro5/internal/aintern_display.h
@@ -77,6 +77,9 @@ struct ALLEGRO_DISPLAY_INTERFACE
    void (*acknowledge_drawing_resume)(ALLEGRO_DISPLAY *d);
       
    void (*change_display_option)(ALLEGRO_DISPLAY *display, int option, int val);
+
+   void (*clear_depth_buffer)(ALLEGRO_DISPLAY *display, float x);
+   void (*update_render_state)(ALLEGRO_DISPLAY *display);
 };
 
 
@@ -92,6 +95,13 @@ typedef struct ALLEGRO_BLENDER
    int blend_alpha_dest;
 } ALLEGRO_BLENDER;
 
+typedef struct _ALLEGRO_RENDER_STATE {
+   int write_mask;
+   int depth_test, depth_function;
+   int alpha_test, alpha_function, alpha_test_value;
+} _ALLEGRO_RENDER_STATE;
+
+
 /* These are settings Allegro itself doesn't really care about on its
  * own, but which users may want to specify for a display anyway.
  */
@@ -136,6 +146,8 @@ struct ALLEGRO_DISPLAY
 
    ALLEGRO_TRANSFORM proj_transform;
    ALLEGRO_TRANSFORM view_transform;
+
+   _ALLEGRO_RENDER_STATE render_state; 
 };
 
 int  _al_score_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref);
diff --git a/include/allegro5/internal/aintern_opengl.h b/include/allegro5/internal/aintern_opengl.h
index d37545c..42e7b41 100644
--- a/include/allegro5/internal/aintern_opengl.h
+++ b/include/allegro5/internal/aintern_opengl.h
@@ -163,6 +163,8 @@ AL_FUNC(bool, _al_opengl_set_blender, (ALLEGRO_DISPLAY *disp));
 AL_FUNC(char const *, _al_gl_error_string, (GLenum e));
 void ogl_setup_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap);
 
+void _al_ogl_update_render_state(ALLEGRO_DISPLAY *display);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/allegro5/render_state.h b/include/allegro5/render_state.h
index fa5a37e..76f74ff 100644
--- a/include/allegro5/render_state.h
+++ b/include/allegro5/render_state.h
@@ -5,6 +5,8 @@
    extern "C" {
 #endif
 
+/* Enum: ALLEGRO_RENDER_STATE
+ */
 typedef enum ALLEGRO_RENDER_STATE {
    /* We re-use the ALPHA_TEST value, just must make sure to not duplicate. */
    ALLEGRO_RENDER_STATE_ALPHA_TEST = 0x0010,
@@ -15,6 +17,8 @@ typedef enum ALLEGRO_RENDER_STATE {
    ALLEGRO_ALPHA_TEST_VALUE,
 } ALLEGRO_RENDER_STATE;
 
+/* Enum: ALLEGRO_RENDER_FUNCTION
+ */
 typedef enum ALLEGRO_RENDER_FUNCTION {
    ALLEGRO_RENDER_NEVER,
    ALLEGRO_RENDER_ALWAYS,
@@ -26,6 +30,8 @@ typedef enum ALLEGRO_RENDER_FUNCTION {
    ALLEGRO_RENDER_GREATER_EQUAL,
 } ALLEGRO_RENDER_FUNCTION;
 
+/* Enum: ALLEGRO_WRITE_MASK_FLAGS
+ */
 typedef enum ALLEGRO_WRITE_MASK_FLAGS {
    ALLEGRO_MASK_RED = 1 << 0,
    ALLEGRO_MASK_GREEN = 1 << 1,
diff --git a/src/display.c b/src/display.c
index 9510974..1663ac4 100644
--- a/src/display.c
+++ b/src/display.c
@@ -71,6 +71,13 @@ ALLEGRO_DISPLAY *al_create_display(int w, int h)
    display->cache_texture = 0;
 
    display->display_invalidated = 0;
+
+   display->render_state.write_mask = ALLEGRO_MASK_RGBA | ALLEGRO_MASK_DEPTH;
+   display->render_state.depth_test = false;
+   display->render_state.depth_function = ALLEGRO_RENDER_LESS;
+   display->render_state.alpha_test = false;
+   display->render_state.alpha_function = ALLEGRO_RENDER_ALWAYS;
+   display->render_state.alpha_test_value = 0;
    
    _al_vector_init(&display->bitmaps, sizeof(ALLEGRO_BITMAP*));
 
@@ -219,6 +226,25 @@ void al_clear_to_color(ALLEGRO_COLOR color)
 
 
 
+/* Function: al_clear_depth_buffer
+ */
+void al_clear_depth_buffer(float z)
+{
+   ALLEGRO_BITMAP *target = al_get_target_bitmap();
+   ASSERT(target);
+
+   if (target->flags & ALLEGRO_MEMORY_BITMAP) {
+      /* has no depth buffer */
+   }
+   else {
+      ALLEGRO_DISPLAY *display = target->display;
+      ASSERT(display);
+      display->vt->clear_depth_buffer(display, z);
+   }
+}
+
+
+
 /* Function: al_draw_pixel
  */
 void al_draw_pixel(float x, float y, ALLEGRO_COLOR color)
@@ -601,4 +627,38 @@ void al_acknowledge_drawing_resume(ALLEGRO_DISPLAY *display)
    }
 }
 
+/* Function: al_set_render_state
+ */
+void al_set_render_state(ALLEGRO_RENDER_STATE state, int value)
+{
+   ALLEGRO_DISPLAY *display = al_get_current_display();
+
+   if (!display) return;
+
+   switch (state) {
+      case ALLEGRO_ALPHA_TEST:
+         display->render_state.alpha_test = value;
+         break;
+      case ALLEGRO_WRITE_MASK:
+         display->render_state.write_mask = value;
+         break;
+      case ALLEGRO_DEPTH_TEST:
+         display->render_state.depth_test = value;
+         break;
+      case ALLEGRO_DEPTH_FUNCTION:
+         display->render_state.depth_function = value;
+         break;
+      case ALLEGRO_ALPHA_FUNCTION:
+         display->render_state.alpha_function = value;
+         break;
+      case ALLEGRO_ALPHA_TEST_VALUE:
+         display->render_state.alpha_test_value = value;
+         break;
+   }
+
+   if (display->vt && display->vt->update_render_state) {
+      display->vt->update_render_state(display);
+   }
+}
+
 /* vim: set sts=3 sw=3 et: */
diff --git a/src/opengl/ogl_draw.c b/src/opengl/ogl_draw.c
index 0bccd9f..d4c0f79 100644
--- a/src/opengl/ogl_draw.c
+++ b/src/opengl/ogl_draw.c
@@ -501,11 +501,22 @@ static void ogl_set_projection(ALLEGRO_DISPLAY *d)
    }
 }
 
+static void ogl_clear_depth_buffer(ALLEGRO_DISPLAY *display, float x)
+{
+   (void)display;
+   glClearDepth(x);
+   /* We may want to defer this to the next glClear call as a combined
+    * color/depth clear may be faster.
+    */
+   glClear(GL_DEPTH_BUFFER_BIT);
+}
+
 /* Add drawing commands to the vtable. */
 void _al_ogl_add_drawing_functions(ALLEGRO_DISPLAY_INTERFACE *vt)
 {
    vt->clear = ogl_clear;
    vt->draw_pixel = ogl_draw_pixel;
+   vt->clear_depth_buffer = ogl_clear_depth_buffer;
    
    vt->flush_vertex_cache = ogl_flush_vertex_cache;
    vt->prepare_vertex_cache = ogl_prepare_vertex_cache;
diff --git a/src/win/d3d_disp.cpp b/src/win/d3d_disp.cpp
index b2bb0ee..33726ff 100644
--- a/src/win/d3d_disp.cpp
+++ b/src/win/d3d_disp.cpp
@@ -419,12 +419,12 @@ static void d3d_reset_state(ALLEGRO_DISPLAY_D3D *disp)
    disp->scissor_state.left   = -1;
    disp->scissor_state.right  = -1;
 
-   disp->device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
-   disp->device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
    disp->device->SetRenderState(D3DRS_LIGHTING, FALSE);
    disp->device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    disp->device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
 
+   _al_d3d_update_render_state((ALLEGRO_DISPLAY *)disp);
+
    if (disp->device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP) != D3D_OK)
       ALLEGRO_ERROR("SetSamplerState failed\n");
    if (disp->device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP) != D3D_OK)
@@ -2006,6 +2006,8 @@ static bool d3d_set_current_display(ALLEGRO_DISPLAY *d)
    if (d3d_display->do_reset)
       return false;
 
+   _al_d3d_update_render_state(d);
+
    return true;
 }
 
@@ -2125,19 +2127,31 @@ void _al_d3d_set_blender(ALLEGRO_DISPLAY_D3D *d3d_display)
 static void d3d_clear(ALLEGRO_DISPLAY *al_display, ALLEGRO_COLOR *color)
 {
    ALLEGRO_BITMAP *target = al_get_target_bitmap();
-   ALLEGRO_BITMAP_EXTRA_D3D *d3d_target;
    ALLEGRO_DISPLAY_D3D* d3d_display = (ALLEGRO_DISPLAY_D3D*)al_display;
    
    if (target->parent) target = target->parent;
    
-   d3d_target = get_extra(target);
-
    if (d3d_display->device_lost)
       return;
    if (d3d_display->device->Clear(0, NULL, D3DCLEAR_TARGET,
-      D3DCOLOR_ARGB((int)(color->a*255), (int)(color->r*255), (int)(color->g*255), (int)(color->b*255)),
-      0, 0) != D3D_OK) {
-         ALLEGRO_ERROR("Clear failed\n");
+         D3DCOLOR_ARGB((int)(color->a*255), (int)(color->r*255),
+         (int)(color->g*255), (int)(color->b*255)), 0, 0) != D3D_OK) {
+      ALLEGRO_ERROR("Clear failed\n");
+   }
+}
+
+static void d3d_clear_depth_buffer(ALLEGRO_DISPLAY *al_display, float z)
+{
+   ALLEGRO_BITMAP *target = al_get_target_bitmap();
+   ALLEGRO_DISPLAY_D3D* d3d_display = (ALLEGRO_DISPLAY_D3D*)al_display;
+   
+   if (target->parent) target = target->parent;
+
+   if (d3d_display->device_lost)
+      return;
+   if (d3d_display->device->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, z, 0)
+         != D3D_OK) {
+      ALLEGRO_ERROR("Clear zbuffer failed\n");
    }
 }
 
@@ -2950,6 +2964,7 @@ ALLEGRO_DISPLAY_INTERFACE *_al_display_d3d_driver(void)
    vt->destroy_display = d3d_destroy_display;
    vt->set_current_display = d3d_set_current_display;
    vt->clear = d3d_clear;
+   vt->clear_depth_buffer = d3d_clear_depth_buffer;
    vt->draw_pixel = d3d_draw_pixel;
    vt->flip_display = d3d_flip_display;
    vt->update_display_region = d3d_update_display_region;
@@ -2985,6 +3000,8 @@ ALLEGRO_DISPLAY_INTERFACE *_al_display_d3d_driver(void)
    vt->update_transformation = d3d_update_transformation;
    vt->set_projection = d3d_set_projection;
 
+   vt->update_render_state = _al_d3d_update_render_state;
+
    return vt;
 }
 
diff --git a/src/x/xdisplay.c b/src/x/xdisplay.c
index 2ffff5a..ca46996 100644
--- a/src/x/xdisplay.c
+++ b/src/x/xdisplay.c
@@ -822,6 +822,7 @@ static bool xdpy_set_current_display(ALLEGRO_DISPLAY *d)
    }
 
    _al_ogl_set_extensions(ogl->extension_api);
+   _al_ogl_update_render_state(d);
 
    return true;
 }
@@ -1269,6 +1270,7 @@ ALLEGRO_DISPLAY_INTERFACE *_al_display_xglx_driver(void)
    xdpy_vt.get_window_constraints = xdpy_get_window_constraints;
    xdpy_vt.set_display_flag = xdpy_set_display_flag;
    xdpy_vt.wait_for_vsync = xdpy_wait_for_vsync;
+   xdpy_vt.update_render_state = _al_ogl_update_render_state;
 
    _al_xglx_add_cursor_functions(&xdpy_vt);
    _al_ogl_add_drawing_functions(&xdpy_vt);


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