changeset 154:6ce68c1f7405

Tank can fire bullet. 1. Add the redraw subject on redraw_man_t. 2. mb_c_source.m4 & mb_c_header.m4 are changed to free & remove shapes. 3. Add rdman_coord_subtree_free() to remove a subtree of coords. 4. Fix bug of rdman_remove_shape().
author Thinker K.F. Li <thinker@branda.to>
date Tue, 30 Sep 2008 02:44:06 +0800
parents 9870b049b7f6
children 6749f6639924
files dox/first_program.h examples/tank/tank_main.c src/observer.h src/paint.c src/redraw_man.c src/redraw_man.h src/shift.c tools/mb_c_header.m4 tools/mb_c_source.m4
diffstat 9 files changed, 287 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/dox/first_program.h	Sat Sep 27 02:40:42 2008 +0800
+++ b/dox/first_program.h	Tue Sep 30 02:44:06 2008 +0800
@@ -16,9 +16,9 @@
  * programs.
  *
  * For example, to translate foo.svg with steps
- * - $(PREFIX)/bin/svg2code.py foo.svg foo.mb
- * - m4 -I $(PREFIX)/share/mb mb_c_source.m4 foo.mb > foo.c
- * - m4 -I $(PREFIX)/share/mb mb_c_header.m4 foo.mb > foo.h
+ * - \$(PREFIX)/bin/svg2code.py foo.svg foo.mb
+ * - m4 -I \$(PREFIX)/share/mb mb_c_source.m4 foo.mb > foo.c
+ * - m4 -I \$(PREFIX)/share/mb mb_c_header.m4 foo.mb > foo.h
  *
  * foo.h declares a structure, named 'foo' and two functions,
  * foo_new() and foo_free(). An instance of 'foo' holds all objects for
--- a/examples/tank/tank_main.c	Sat Sep 27 02:40:42 2008 +0800
+++ b/examples/tank/tank_main.c	Tue Sep 30 02:44:06 2008 +0800
@@ -40,17 +40,32 @@
  * \brief Tank elf module provides control functions of tanks in game.
  * @{
  */
+struct _tank_bullet {
+    redraw_man_t *rdman;
+    coord_t *coord_pos;
+    coord_t *coord_rot;
+    bullet_t *bullet_obj;
+    int start_map_x, start_map_y;
+    int direction;
+    mb_progm_t *progm;
+    mb_timeval_t start_time;
+    observer_t *ob_redraw;
+};
+typedef struct _tank_bullet tank_bullet_t;
+enum { BU_UP = 0, BU_RIGHT, BU_DOWN, BU_LEFT };
+
 struct _tank {
     coord_t *coord_pos;		/*!< \brief coordinate for position */
     coord_t *coord_rot;		/*!< \brief coordinate for rotation */
+    coord_t *coord_center;
     int map_x, map_y;
     int direction;
     mb_progm_t *progm;
+    tank_bullet_t *bullet;
 };
 typedef struct _tank tank_t;
 enum { TD_UP = 0, TD_RIGHT, TD_DOWN, TD_LEFT };
 
-
 /* @} */
 
 typedef struct _tank_rt tank_rt_t;
@@ -92,6 +107,7 @@
     tank->map_y = map_y;
     tank->direction = TD_UP;
     tank->progm = NULL;
+    tank->bullet = NULL;
 
     memset(coord_pos->matrix, 0, sizeof(co_aix[6]));
     coord_pos->matrix[0] = 1;
@@ -233,6 +249,174 @@
 
 /* @} */
 
+/*! \brief Make coord objects for bullet elfs. */
+static void make_bullet_elf_coords(redraw_man_t *rdman, coord_t **coord_pos,
+				   coord_t **coord_rot,
+				   coord_t **coord_center) {
+    coord_t *coord_back;
+
+    *coord_pos = rdman_coord_new(rdman, rdman->root_coord);
+
+    coord_back = rdman_coord_new(rdman, *coord_pos);
+    coord_back->matrix[2] = 25;
+    coord_back->matrix[5] = 25;
+    rdman_coord_changed(rdman, coord_back);
+
+    *coord_rot = rdman_coord_new(rdman, coord_back);
+
+    *coord_center = rdman_coord_new(rdman, *coord_rot);
+    (*coord_center)->matrix[2] = -5;
+    (*coord_center)->matrix[5] = +15;
+    rdman_coord_changed(rdman, *coord_center);
+}
+
+static tank_bullet_t *tank_bullet_new(redraw_man_t *rdman,
+				      int map_x, int map_y,
+				      int direction) {
+    tank_bullet_t *bullet;
+    coord_t *coord_center;
+    co_aix *matrix;
+    static float _sins[] = { 0, 1, 0, -1};
+    static float _coss[] = { 1, 0, -1, 0};
+    float _sin, _cos;
+
+    bullet = O_ALLOC(tank_bullet_t);
+    bullet->rdman = rdman;
+
+    make_bullet_elf_coords(rdman, &bullet->coord_pos,
+			   &bullet->coord_rot,
+			   &coord_center);
+    bullet->bullet_obj = bullet_new(rdman, coord_center);
+    
+    bullet->start_map_x = map_x;
+    bullet->start_map_y = map_y;
+    bullet->direction = direction;
+    bullet->progm = NULL;
+
+    matrix = bullet->coord_pos->matrix;
+    matrix[2] = map_x * 50;
+    matrix[5] = map_y * 50;
+    rdman_coord_changed(rdman, bullet->coord_pos);
+
+    _sin = _sins[direction];
+    _cos = _coss[direction];
+    matrix = bullet->coord_rot->matrix;
+    matrix[0] = _cos;
+    matrix[1] = -_sin;
+    matrix[3] = _sin;
+    matrix[4] = _cos;
+
+    return bullet;
+}
+
+static void tank_bullet_free(tank_bullet_t *bullet) {
+    bullet_free(bullet->bullet_obj);
+    rdman_coord_subtree_free(bullet->rdman, bullet->coord_pos);
+}
+
+static void bullet_go_out_map_and_redraw(event_t *event, void *arg) {
+    tank_t *tank = (tank_t *)arg;
+    tank_bullet_t *bullet;
+    ob_factory_t *factory;
+    subject_t *redraw;
+
+    bullet = tank->bullet;
+    mb_progm_free(bullet->progm);
+    rdman_force_clean(bullet->rdman);
+    factory = rdman_get_ob_factory(bullet->rdman);
+    redraw = rdman_get_redraw_subject(bullet->rdman);
+    subject_remove_observer(factory, redraw, bullet->ob_redraw);
+    tank_bullet_free(tank->bullet);
+    tank->bullet = NULL;
+}
+
+static void bullet_go_out_map(event_t *event, void *arg) {
+    tank_t *tank = (tank_t *)arg;
+    tank_bullet_t *bullet;
+    redraw_man_t *rdman;
+    subject_t *redraw;
+    ob_factory_t *factory;
+    
+    /*! \todo Simplify the procdure of using observer pattern. */
+    bullet = tank->bullet;
+    rdman = bullet->rdman;
+    factory = rdman_get_ob_factory(rdman);
+    redraw = rdman_get_redraw_subject(rdman);
+    bullet->ob_redraw =
+	subject_add_observer(factory, redraw,
+			     bullet_go_out_map_and_redraw, tank);
+}
+
+static void tank_fire_bullet(tank_rt_t *tank_rt, tank_t *tank) {
+    X_MB_runtime_t *xmb_rt;
+    redraw_man_t *rdman;
+    int map_x, map_y;
+    int shift_x, shift_y;
+    int shift_len;
+    int dir;
+    tank_bullet_t *bullet;
+    mb_progm_t *progm;
+    mb_word_t *word;
+    mb_action_t *act;
+    mb_timeval_t start, playing;
+    mb_timeval_t now;
+    ob_factory_t *factory;
+    mb_tman_t *tman;
+    subject_t *subject;
+    static int map_xy_adj[][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
+
+    if(tank->bullet != NULL)
+	return;
+
+    xmb_rt = tank_rt->mb_rt;
+    rdman = X_MB_rdman(xmb_rt);
+    tman = X_MB_tman(xmb_rt);
+
+    dir = tank->direction;
+    map_x = tank->map_x + map_xy_adj[dir][0];
+    map_y = tank->map_y + map_xy_adj[dir][1];
+    tank->bullet = tank_bullet_new(rdman, map_x, map_y, dir);
+    bullet = tank->bullet;
+
+    switch(dir) {
+    case TD_UP:
+	shift_len = map_y + 1;
+	shift_x = 0;
+	shift_y = -shift_len * 50;
+	break;
+    case TD_RIGHT:
+	shift_len = 16 - map_x;
+	shift_x = shift_len * 50;
+	shift_y = 0;
+	break;
+    case TD_DOWN:
+	shift_len = 12 - map_y;
+	shift_x = 0;
+	shift_y = shift_len * 50;
+	break;
+    case TD_LEFT:
+	shift_len = map_x + 1;
+	shift_x = -shift_len * 50;
+	shift_y = 0;
+	break;
+    }
+
+    progm = mb_progm_new(2, rdman);
+    MB_TIMEVAL_SET(&start, 0, 0);
+    MB_TIMEVAL_SET(&playing, shift_len / 4, (shift_len % 4) * 250000);
+    word = mb_progm_next_word(progm, &start, &playing);
+    act = mb_shift_new(shift_x, shift_y, bullet->coord_pos, word);
+    bullet->progm = progm;
+    
+    subject = mb_progm_get_complete(progm);
+    factory = rdman_get_ob_factory(rdman);
+    subject_add_observer(factory, subject, bullet_go_out_map, tank);
+
+    get_now(&now);
+    MB_TIMEVAL_CP(&bullet->start_time, &now);
+    mb_progm_start(progm, tman, &now);
+}
+
 #define CHANGE_POS(g, x, y) do {			\
 	(g)->root_coord->matrix[0] = 1.0;		\
 	(g)->root_coord->matrix[2] = x;			\
@@ -271,6 +455,7 @@
 	break;
 
     case 0x20:			/* space */
+	tank_fire_bullet(tank_rt, tank_rt->tank1);
 	break;
     case 0xff0d:		/* enter */
     default:
--- a/src/observer.h	Sat Sep 27 02:40:42 2008 +0800
+++ b/src/observer.h	Tue Sep 30 02:44:06 2008 +0800
@@ -42,7 +42,7 @@
 #define SUBF_BUSY 0x2		/*!< \brief in subject_notify() */
 #define SUBF_FREE 0x4		/*!< \brief in postponding subject_free() */
 
-enum {OBJT_GEO, OBJT_COORD, OBJT_KB, OBJT_PROGM};
+enum {OBJT_GEO, OBJT_COORD, OBJT_KB, OBJT_PROGM, OBJT_RDMAN};
 
 struct _mouse_event {
     event_t event;
@@ -72,7 +72,8 @@
 
 enum {EVT_MOUSE_OVER, EVT_MOUSE_OUT, EVT_MOUSE_MOVE,
       EVT_MOUSE_BUT_PRESS, EVT_MOUSE_BUT_RELEASE,
-      EVT_KB_PRESS, EVT_KB_RELEASE, EVT_PROGM_COMPLETE};
+      EVT_KB_PRESS, EVT_KB_RELEASE, EVT_PROGM_COMPLETE,
+      EVT_RDMAN_REDRAW };
 
 extern subject_t *subject_new(ob_factory_t *factory,
 			      void *obj, int obj_type);
--- a/src/paint.c	Sat Sep 27 02:40:42 2008 +0800
+++ b/src/paint.c	Tue Sep 30 02:44:06 2008 +0800
@@ -26,7 +26,7 @@
     paint_color_t *color = (paint_color_t *)paint;
 
     shnode_list_free(color->rdman, paint->members);
-    free(paint);
+    elmpool_elm_free(color->rdman->paint_color_pool, paint);
 }
 
 paint_t *paint_color_new(redraw_man_t *rdman,
--- a/src/redraw_man.c	Sat Sep 27 02:40:42 2008 +0800
+++ b/src/redraw_man.c	Tue Sep 30 02:44:06 2008 +0800
@@ -271,6 +271,9 @@
     rdman->ob_factory.observer_free = ob_observer_free;
     rdman->ob_factory.get_parent_subject = ob_get_parent_subject;
 
+    rdman->redraw =
+	subject_new(&rdman->ob_factory, rdman, OBJT_RDMAN);
+
     rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool);
     if(rdman->root_coord == NULL)
 	redraw_man_destroy(rdman);
@@ -364,7 +367,9 @@
 
 /*! \brief Remove a shape object from redraw manager.
  *
+ * \note Shapes should be removed after redrawing or when rdman is in clean.
  * \todo redraw shape objects that overlaid with removed one.
+ * \todo To allow shapes be removed at anytime.
  */
 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) {
     geo_t *geo;
@@ -375,7 +380,7 @@
     geo_detach_coord(geo, coord);
     subject_free(&rdman->ob_factory, geo->mouse_event);
     sh_detach_geo(shape);
-    elmpool_elm_free(rdman->geo_pool, shape->geo);
+    elmpool_elm_free(rdman->geo_pool, geo);
     sh_detach_coord(shape);
     return OK;
 }
@@ -449,6 +454,29 @@
     return OK;
 }
 
+int rdman_coord_subtree_free(redraw_man_t *rdman, coord_t *subtree) {
+    coord_t *coord, *prev_coord;
+    int r;
+
+    if(subtree == NULL)
+	return OK;
+
+    prev_coord = postorder_coord_subtree(subtree, NULL);
+    for(coord = postorder_coord_subtree(subtree, prev_coord);
+	coord != NULL;
+	coord = postorder_coord_subtree(subtree, coord)) {
+	r = rdman_coord_free(rdman, prev_coord);
+	if(r != OK)
+	    return ERR;
+	prev_coord = coord;
+    }
+    r = rdman_coord_free(rdman, prev_coord);
+    if(r != OK)
+	return ERR;
+
+    return OK;
+}
+
 /*! \brief Mark a coord is changed.
  *
  * A changed coord_t object is marked as dirty and put
@@ -921,6 +949,9 @@
     int r;
     int n_dirty_areas;
     area_t **dirty_areas;
+    event_t event;
+    ob_factory_t *factory;
+    subject_t *redraw;
 
     r = clean_rdman_dirties(rdman);
     if(r != OK)
@@ -940,6 +971,12 @@
     }
     rdman->n_dirty_areas = 0;
 
+    factory = rdman_get_ob_factory(rdman);
+    redraw = rdman_get_redraw_subject(rdman);
+    event.type = EVT_RDMAN_REDRAW;
+    event.tgt = event.cur_tgt = redraw;
+    subject_notify(factory, redraw, &event);
+
     return OK;
 }
 
--- a/src/redraw_man.h	Sat Sep 27 02:40:42 2008 +0800
+++ b/src/redraw_man.h	Tue Sep 30 02:44:06 2008 +0800
@@ -55,6 +55,8 @@
     cairo_t *backend;
 
     ob_factory_t ob_factory;
+
+    subject_t *redraw;		/*!< \brief Notified after redrawing. */
 } redraw_man_t;
 
 extern int redraw_man_init(redraw_man_t *rdman, cairo_t *cr,
@@ -68,6 +70,7 @@
 extern int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape);
 extern coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent);
 extern int rdman_coord_free(redraw_man_t *rdman, coord_t *coord);
+extern int rdman_coord_subtree_free(redraw_man_t *rdman, coord_t *subtree);
 extern int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord);
 extern int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape);
 extern int rdman_redraw_changed(redraw_man_t *rdman);
@@ -116,6 +119,7 @@
 extern shape_t *find_shape_at_pos(redraw_man_t *rdman,
 				  co_aix x, co_aix y, int *in_stroke);
 #define rdman_get_ob_factory(rdman) (&(rdman)->ob_factory)
+#define rdman_get_redraw_subject(rdman) ((rdman)->redraw)
 
 
 #endif /* __REDRAW_MAN_H_ */
--- a/src/shift.c	Sat Sep 27 02:40:42 2008 +0800
+++ b/src/shift.c	Tue Sep 30 02:44:06 2008 +0800
@@ -91,6 +91,7 @@
     shift->action.stop = mb_shift_stop;
     shift->action.free = mb_shift_free;
 
+    /*! \note mb_shift_new() will add itself to the specified word. */
     mb_word_add_action(word, (mb_action_t *)shift);
 
     return (mb_action_t *)shift;
--- a/tools/mb_c_header.m4	Sat Sep 27 02:40:42 2008 +0800
+++ b/tools/mb_c_header.m4	Tue Sep 30 02:44:06 2008 +0800
@@ -48,6 +48,7 @@
 typedef struct $1 $1_t;
 
 struct $1 {
+    redraw_man_t *rdman;
     coord_t *root_coord;]
 $2[]dnl
 [};
--- a/tools/mb_c_source.m4	Sat Sep 27 02:40:42 2008 +0800
+++ b/tools/mb_c_source.m4	Tue Sep 30 02:44:06 2008 +0800
@@ -213,14 +213,17 @@
 ]])
 
 define([F_ADD_PATH],[[
+    rdman_remove_shape(rdman, obj->$1);
     obj->$1->free(obj->$1);
 ]])
 
 define([F_ADD_RECT],[[
+    rdman_remove_shape(rdman, obj->$1);
     obj->$1->free(obj->$1);
 ]])
 
 define([F_ADD_TEXT],[[
+    rdman_remove_shape(rdman, obj->$1);
     obj->$1->free(obj->$1);
 ]])
 
@@ -257,6 +260,42 @@
 define([SHAPE_MATRIX],)
 divert[]])
 
+define([REVERSE_VARS],[divert([-1])
+define([__REV_VAR],[])
+define([PUSH_REV], [
+	pushdef([__REV_VAR])
+	define([__REV_VAR], ]QUOTE(QUOTE($[]1))[)])
+define([POP_ALL_REV], [dnl
+ifelse(__REV_VAR, [], ,[UNQUOTE(__REV_VAR)[]dnl
+popdef([__REV_VAR])[]POP_ALL_REV[]])])
+define([RIMPORT], [
+	define(]QUOTE($[]1)[,
+		[PUSH_REV(]]QUOTE(QUOTE($[]1))[[(]QUOTE($[]@)[))])
+])
+RIMPORT([ADD_LINEAR_PAINT])
+RIMPORT([ADD_RADIAL_PAINT])
+RIMPORT([COLOR_STOP])
+RIMPORT([REF_STOPS_RADIAL])
+RIMPORT([REF_STOPS_LINEAR])
+RIMPORT([ADD_PATH])
+RIMPORT([ADD_RECT])
+RIMPORT([ADD_COORD])
+RIMPORT([ADD_TEXT])
+RIMPORT([FILL_SHAPE])
+RIMPORT([STROKE_SHAPE])
+RIMPORT([FILL_SHAPE_WITH_PAINT])
+RIMPORT([STROKE_SHAPE_WITH_PAINT])
+RIMPORT([STROKE_WIDTH])
+RIMPORT([GROUP_HIDE])
+RIMPORT([RECT_HIDE])
+RIMPORT([PATH_HIDE])
+RIMPORT([COORD_TRANSLATE])
+RIMPORT([COORD_MATRIX])
+RIMPORT([SHAPE_TRANSLATE])
+RIMPORT([SHAPE_MATRIX])
+divert[]dnl
+])
+
 define([MADBUTTERFLY],[dnl
 [#include <stdio.h>
 #include <stdlib.h>
@@ -274,6 +313,7 @@
 [
     obj = ($1_t *)malloc(sizeof($1_t));
     if(obj == NULL) return NULL;
+    obj->rdman = rdman;
 ]SETUP_VARS
     obj->root_coord = rdman_coord_new(rdman, parent_coord);
 $2
@@ -282,7 +322,16 @@
 
 void $1_free($1_t *obj) {
     grad_stop_t *stops = NULL;
-]CLEAR_VARS[]$2[
+    redraw_man_t *rdman;
+
+    rdman = obj->rdman;
+]REVERSE_VARS[]dnl
+divert([-1])dnl
+$2[]dnl
+divert[]dnl
+CLEAR_VARS[]dnl
+POP_ALL_REV[
+    rdman_coord_subtree_free(rdman, obj->root_coord);
     free(obj);
 }
 ]dnl