Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Allegro 5 3D projections

This thread is locked; no one can reply to it. rss feed Print
Allegro 5 3D projections
Mark Oates
Member #1,146
March 2001
avatar

Now that the newer version of allegro has 3D routines, I'm trying to set things up to play around with.

I've looked at ex_projection.c and tried to adapt what's going on there. I'm still at a block and haven't been able to find any general purpose tutorial, explanation on the wiki, or even any good discussions on the forums of the general "pipeline" of how a proper 3D scene could be achieved using Allegro 5.

I want to properly use vertex and index buffers, and I think I understand how they work (even though I haven't used one yet).

What do I need to set-up? How do I need to affect my models before render?
How does a camera fit into this?

Here's where I'm at:

#SelectExpand
1class Model // as in a 3D Model 2{ 3public: 4 std::vector<ALLEGRO_VERTEX> vertex; 5 ALLEGRO_VERTEX vtx[3]; 6 //placement3d place; 7 8 Model(int size) 9 { 10 vertex.push_back(build_vertex(-size, -size, 0, color::green, 0, 0)); 11 vertex.push_back(build_vertex(size, -size, 0, color::green, 0, 0)); 12 vertex.push_back(build_vertex(size, size, 0, color::blue, 0, 0)); 13 } 14 15 void draw() 16 { 17 al_draw_prim(&vertex[0], NULL, NULL, 0, vertex.size(), ALLEGRO_PRIM_TRIANGLE_STRIP); 18 } 19}; 20 21 22 23class Project : public Screen 24{ 25public: 26 ALLEGRO_TRANSFORM camera_transform; 27 Model model; 28 Project(Display *display) 29 : Screen(display) 30 , model(100) 31 {} 32 static void setup_3d_projection(ALLEGRO_TRANSFORM *projection) 33 { 34 ALLEGRO_DISPLAY *display = al_get_current_display(); 35 int dw = al_get_display_width(display); 36 int dh = al_get_display_height(display); 37 al_perspective_transform(projection, -180 * dw / dh, -180, 180, 38 180 * dw / dh, 180, 3000); 39 al_set_projection_transform(display, projection); 40 } 41 void primary_timer_func() 42 { 43 setup_3d_projection(&camera_transform); 44 model.draw(); 45 } 46};

I think if I get a bare-bones example that renders two rotating textured cubes that z-buffer properly, I would be ok.

Trezker
Member #1,739
December 2001
avatar

Mark Oates
Member #1,146
March 2001
avatar

Hmm, I was hoping I wouldn't have to describe my framework.

The Project class inherits Screen and then overrides Screen::primary_timer_func().

Afterwhich, the flip is called.

  for (unsigned d=0; d<Display::displays.size(); d++)
  {
    Display::displays[d]->set_as_target_bitmap();
    al_clear_to_color(Display::displays[d]->_background_color);
    for (unsigned i=0; i<screens.size(); i++)
    {
      if (screens[i]->display == Display::displays[d])
        screens[i]->primary_timer_func();
    }
    Display::displays[d]->flip(); // <-- here
  }

A Screen is anything, like a menu screen, a game screen, a world map screen. You can nest several screens at the same time, so you would have a world screen and a hud screen at the same time.

But that's all tangential.

TLDR; the flip is in there.

beoran
Member #12,636
March 2011

Interesting! I never thought about drawing a 3D model with an Allegro al_draw_prim... Does that even work? I'll try it myself later if no one else steps up.

SiegeLord
Member #7,827
October 2006
avatar

Not cubes and not textured, but those parts are not really relevant, are they?

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_primitives.h> 3#include "stdio.h" 4 5int main() 6{ 7 al_init(); 8 9 auto dw = 800; 10 auto dh = 600; 11 12 al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); 13 auto d = al_create_display(dw, dh); 14 15 if(!d) 16 { 17 printf("Failed to create display\n"); 18 return 1; 19 } 20 21 al_install_keyboard(); 22 23 auto queue = al_create_event_queue(); 24 auto timer = al_create_timer(1.0 / 60.0); 25 26 al_register_event_source(queue, al_get_timer_event_source(timer)); 27 al_register_event_source(queue, al_get_keyboard_event_source()); 28 al_start_timer(timer); 29 30 al_init_primitives_addon(); 31 32 int ind[] = 33 { 34 0, 1, 2, 35 0, 1, 3, 36 0, 2, 3, 37 1, 2, 3 38 }; 39 40 ALLEGRO_VERTEX vtx[4]; 41 vtx[0].x = -200; 42 vtx[0].y = -200; 43 vtx[0].z = -200; 44 vtx[0].color = al_map_rgb_f(0, 0, 1); 45 46 vtx[1].x = 0; 47 vtx[1].y = -200; 48 vtx[1].z = 200; 49 vtx[1].color = al_map_rgb_f(0, 1, 0); 50 51 vtx[2].x = 200; 52 vtx[2].y = -200; 53 vtx[2].z = -200; 54 vtx[2].color = al_map_rgb_f(1, 0, 1); 55 56 vtx[3].x = 0; 57 vtx[3].y = 200; 58 vtx[3].z = 0; 59 vtx[3].color = al_map_rgb_f(1, 1, 1); 60 61 float theta = 0; 62 ALLEGRO_TRANSFORM transform; 63 64 int mode = 0; 65 bool done = false; 66 bool redraw = true; 67 while(!done) 68 { 69 ALLEGRO_EVENT ev; 70 al_wait_for_event(queue, &ev); 71 switch(ev.type) 72 { 73 case ALLEGRO_EVENT_KEY_DOWN: 74 switch(ev.keyboard.keycode) 75 { 76 case ALLEGRO_KEY_ESCAPE: 77 done = true; 78 break; 79 } 80 break; 81 case ALLEGRO_EVENT_TIMER: 82 theta += 0.01; 83 redraw = true; 84 break; 85 } 86 87 if(al_is_event_queue_empty(queue) && redraw) 88 { 89 al_clear_to_color(al_map_rgb_f(0, 0, 0)); 90 al_clear_depth_buffer(1000); 91 al_set_render_state(ALLEGRO_DEPTH_TEST, 1); 92 93 al_identity_transform(&transform); 94 al_rotate_transform_3d(&transform, 0, 1, 0, theta); 95 al_translate_transform_3d(&transform, 100, 0, -800); 96 al_use_transform(&transform); 97 98 al_draw_indexed_prim(vtx, NULL, NULL, ind, 12, ALLEGRO_PRIM_TRIANGLE_LIST); 99 100 al_identity_transform(&transform); 101 al_rotate_transform_3d(&transform, 0, 1, 0, theta / 2); 102 al_translate_transform_3d(&transform, -100, 0, -800); 103 al_use_transform(&transform); 104 105 al_draw_indexed_prim(vtx, NULL, NULL, ind, 12, ALLEGRO_PRIM_TRIANGLE_LIST); 106 107 al_identity_transform(&transform); 108 al_perspective_transform(&transform, -dw / 2, -dh / 2, dw / 2, dw / 2, dh / 2, 10000); 109 al_set_projection_transform(d, &transform); 110 111 al_flip_display(); 112 113 redraw = false; 114 } 115 } 116}

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Mark Oates
Member #1,146
March 2001
avatar

SiegeLord said:

Not cubes and not textured, but those parts are not really relevant, are they?

Not at all. :) Your post was tremendously helpful. I managed to make some progress. I still don't quite get that the perspective_transform/projection_transform is not related to drawing the primitives themselves. When drawing the primitives, are they not (actually) fully drawn until the flip? And how they are drawn is relative to the projection as set at some point before the flip?

Also, after some digging in my framework code, I found that a line:

al_set_target_bitmap(al_get_backbuffer(d));

is causing the 3D to not render correctly. If I put it into your code thusly:

...

if(al_is_event_queue_empty(queue) && redraw)
{
   al_set_target_bitmap(al_get_backbuffer(d));

   ...
}

...

it has the same result. I initially use that line to "reset" the drawing back so that the next screen can be drawn without any states set by the prior screen.

SiegeLord
Member #7,827
October 2006
avatar

When drawing the primitives, are they not (actually) fully drawn until the flip?

That is undefined, but that's not really what you want to know... they take into account the transformations that were active at the time of the function call.

Quote:

is causing the 3D to not render correctly

Projection transforms are very poorly implemented in A5 right now. The usual transformations ( al_use_transform) are a bitmap-local state, while the projection transformations ( al_set_projection_transform) are display local and are reset to be orthographic whenever you change target bitmaps. This is a disaster I noticed years ago, but haven't had time to fix myself.

Quote:

it has the same result.

So the solution is to do this:

#SelectExpand
1if(al_is_event_queue_empty(queue) && redraw) 2{ 3 al_set_target_bitmap(al_get_backbuffer(d)); 4 5 // Set the projection transform back 6 al_identity_transform(&transform); 7 al_perspective_transform(&transform, -dw / 2, -dh / 2, dw / 2, dw / 2, dh / 2, 10000); 8 al_set_projection_transform(d, &transform); 9 10 al_clear_to_color(al_map_rgb_f(0, 0, 0)); 11 al_clear_depth_buffer(1000); 12 al_set_render_state(ALLEGRO_DEPTH_TEST, 1); 13 14 al_identity_transform(&transform); 15 al_rotate_transform_3d(&transform, 0, 1, 0, theta); 16 al_translate_transform_3d(&transform, 100, 0, -800); 17 al_use_transform(&transform); 18 19 al_draw_indexed_prim(vtx, NULL, NULL, ind, 12, ALLEGRO_PRIM_TRIANGLE_LIST); 20 21 al_identity_transform(&transform); 22 al_rotate_transform_3d(&transform, 0, 1, 0, theta / 2); 23 al_translate_transform_3d(&transform, -100, 0, -800); 24 al_use_transform(&transform); 25 26 al_draw_indexed_prim(vtx, NULL, NULL, ind, 12, ALLEGRO_PRIM_TRIANGLE_LIST); 27 28 al_flip_display(); 29 30 redraw = false; 31}

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Mark Oates
Member #1,146
March 2001
avatar

Not too terribly exciting, but I'm happy with what I've managed to accomplish so far :)

{"name":"608537","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/d\/0d38c4b169abf0c592eb6dbf494517bc.png","w":960,"h":540,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/d\/0d38c4b169abf0c592eb6dbf494517bc"}608537
{"name":"608540","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/1\/b1db0c150a901b24beae2da4b76d1717.png","w":960,"h":540,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/1\/b1db0c150a901b24beae2da4b76d1717"}608540

beoran
Member #12,636
March 2011

Cool! How do you get the textures on there?

Mark Oates
Member #1,146
March 2001
avatar

Textures are very easy. In the ALLEGRO_VERTEX there are 6 values:

struct ALLEGRO_VERTEX {
  float x, y, z;
  float u, v;
  ALLEGRO_COLOR color;
};

(u, v) are the (x, y) coordinates of the texture in pixel coordinates. If you overshoot or undershoot (u, v) to the width/height of the texture then the texture will loop.

When you draw the prim (via al_draw_prim or whatnot) then you pass the ALLEGRO_BITMAP texture in to that function.

beoran
Member #12,636
March 2011

I see, I should have thought about it myself! Drat, now I want to program a classic dungeon crawler in Allegro... one day! :)

Go to: