1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348 |
- #include "scegra.h"
- #include "eruta.h"
- #include "bevec.h"
- #include "image.h"
- #include "rebox.h"
- #include "bad.h"
- #include "draw.h"
- #include "str.h"
- #include "flags.h"
- #include "store.h"
- #include "state.h"
- #include "laytext.h"
- #include <string.h>
- #define SCEGRA_TEXT_MAX 128
- enum ScegraNodeFlags_ {
- SCEGRA_NODE_HIDE = 1
- };
- enum ScegraNodeKind_ {
- SCEGRA_NODE_UNKNOWN = 0,
- SCEGRA_NODE_BITMAP,
- SCEGRA_NODE_BOX,
- SCEGRA_NODE_LINE,
- SCEGRA_NODE_TRIANGLE,
- SCEGRA_NODE_SPLINE,
- SCEGRA_NODE_PIXEL,
- SCEGRA_NODE_POLYGON,
- SCEGRA_NODE_PRIM,
- SCEGRA_NODE_TEXT,
- SCEGRA_NODE_LONGTEXT,
- };
- /* A very simple scene graph, mainly for drawing the UI that will be managed from
- * the scripting side of things. To avoid memory allocation, limit the amount of
- * vertices allowed to SCERGRA_VERTEX_MAX (32) and characters allowed for a
- * string to 128. (enough to fill the screen with a font of 5 pixels wide).
- * Of course this is all for a LINE of text, the scegra will use multiple text
- * text lines for multiline displays.
- */
- struct ScegraRound_ {
- float start_theta, delta_theta;
- };
- struct ScegraBitmap_ {
- BeVec src_pos, src_size;
- float angle;
- int image_id;
- };
- struct ScegraBox_ {
- BeVec round;
- };
- struct ScegraLine_ {
- float _unused;
- };
- struct ScegraTriangle_ {
- float x1, y1, x2, y2, x3, y3;
- };
- struct ScegraSpline_ {
- float vertices[8];
- };
- struct ScegraPixel_ {
- float x1, y1;
- };
- struct ScegraPolygon_ {
- float vertices[SCEGRA_VERTEX_MAX];
- int vertex_count;
- };
- struct ScegraPrim_ {
- ALLEGRO_VERTEX vertices[SCEGRA_VERTEX_MAX];
- int vertex_count;
- };
- struct ScegraText_ {
- float x1, x2, y, diff;
- char text[SCEGRA_TEXT_MAX];
- int from, until;
- };
- /* For long text that can scroll and display letter per letter. */
- struct ScegraLongText_ {
- float x1, x2, y, diff;
- char * text;
- int line_start, line_stop, line_pos; /* Current text "window". */
- int line_max, line_height; /* text constants. */
- int page_lines; /* Text "window" size for one "page" of text in amount of lines. */
- int paused;
- double delay_total;
- };
- /** Union: ScegraData.
- * A union of different types of vertex data for drawing the various primitives
- * and bitmaps.
- */
- union ScegraData_ {
- struct ScegraPixel_ pixel;
- struct ScegraLine_ line;
- struct ScegraTriangle_ triangle;
- struct ScegraBox_ box;
- struct ScegraBitmap_ bitmap;
- struct ScegraPolygon_ polygon;
- struct ScegraRound_ round;
- struct ScegraSpline_ spline;
- struct ScegraPrim_ prim;
- struct ScegraText_ text;
- struct ScegraLongText_ longtext;
- };
- typedef union ScegraData_ ScegraData;
- struct ScegraNode_ {
- int id;
- int z;
- int step;
- int kind;
- int flags;
- double delay;
- BeVec pos;
- BeVec size;
- BeVec speed;
- struct ScegraStyle_ style;
- union ScegraData_ data;
- ScegraDraw * draw;
- ScegraUpdate * update;
- ScegraDone * done;
- };
- /* Scene graph struct. */
- struct Scegra_ {
- ScegraNode * nodes;
- int node_max;
- };
- #define SCEGRA_NODES_MAX 10000
- #define SCEGRA_LONGTEXT_LINE_POS_MAX 99999
- /* Static storage for nodes. */
- static ScegraNode scegra_nodes[SCEGRA_NODES_MAX];
- /* Nodes pointers sorted in drawing order. */
- static ScegraNode * scegra_nodes_todraw[SCEGRA_NODES_MAX];
- /* How many nodes to draw this time. */
- static int scegra_to_draw = 0;
- void
- scegranode_done(ScegraNode * self) {
- if (!self) return;
- if (self->done) self->done(self);
- self->id = -1;
- self->z = -1;
- }
- ScegraNode *
- scegranode_initall(ScegraNode * node, int kind, int id, BeVec pos, BeVec siz,
- ScegraData data,
- ScegraStyle style, ScegraDraw * draw, ScegraUpdate * update) {
- if(!node) return NULL;
- scegranode_done(node);
- node->id = id;
- node->z = id;
- node->pos = pos;
- node->size = siz;
- node->speed = bevec0();
- node->data = data;
- node->style = style;
- node->draw = draw;
- node->update = update;
- node->step = 0;
- node->flags = 0;
- node->done = NULL;
- node->kind = kind;
- node->delay = 0.05;
- return node;
- }
- /* Gets pointer to the font for this scegra node, or to a default font. */
- static Font * scegra_get_font(ScegraNode * self) {
- Font * font;
- /* Use default font if font not loaded. */
- font = store_get_font(self->style.font_id);
- if (!font) font = state_font(state_get());
- return font;
- }
- /** Gets the current text page for a longtext. */
- int scegranode_page(ScegraNode * node) {
- struct ScegraLongText_ * lt;
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- lt = &node->data.longtext;
- return lt->line_start / lt->page_lines;
- }
- /** Gets the last page number for a longtext or negative on error. */
- int scegranode_last_page(ScegraNode * node) {
- struct ScegraLongText_ * lt;
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- lt = &node->data.longtext;
- return lt->line_max / lt->page_lines;
- }
- /** Advances long text to the given page. Automatically unpauses as well. */
- int scegranode_page_(ScegraNode * node, int page) {
- struct ScegraLongText_ * lt;
- int line;
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- if (page < 0) return -4;
- lt = &node->data.longtext;
- line = page * lt->page_lines;
- /* Check for page overflow. */
- if (line >= lt->line_max) {
- return -5;
- }
- lt->paused = false;
- lt->line_start = line;
- /* Negative delay is instant display. */
- if (node->delay < 0) {
- lt->line_stop = lt->line_start + lt->page_lines;
- lt->line_pos = SCEGRA_LONGTEXT_LINE_POS_MAX;
- } else {
- lt->line_stop = lt->line_start + 1;
- lt->line_pos = 0;
- }
- return page;
- }
- void
- scegranode_longtext_done(ScegraNode * self) {
- free(self->data.longtext.text);
- self->data.longtext.text = NULL;
- }
- void scegra_update_generic(ScegraNode * self, double dt) {
- self->pos = bevec_add(self->pos, bevec_mul(self->speed, dt));
- }
- /* This function is the helper callback that implements
- * updating scrolled/partial text for Longtexts.
- */
- static bool scegra_update_custom_partial_text(int line_num, const char *line,
- int size, void *extra) {
- ScegraNode * self = extra;
- struct ScegraLongText_ * st = &self->data.longtext;
- st->line_max = line_num;
- /* Don't draw lines before start but keep on drawing (for later lines) */
- if (line_num < st->line_start) return true;
- /* Don't draw lines after stop, but keep calculating to get correct amount of lines */
- if (line_num >= st->line_stop) return true;
- /* Reveal letter by letter on last line */
- if (line_num == (st->line_stop - 1)) {
- /* Advance the position automatically if not paused. */
- if (!st->paused) {
- st->line_pos++;
- }
- /* Reached eol, advance to next line. */
- if (st->line_pos >= size) {
- /* Is if the text window is full, pause, otherwise show the next line. */
- if ((st->line_stop - st->line_start) >= st->page_lines) {
- st->paused = true;
- } else {
- st->line_stop++;
- st->line_pos = 0;
- }
- }
- }
- (void) line;
- return true;
- }
- /* Updates the longtext, enables scrolling and per character display. */
- void scegra_update_longtext(ScegraNode * self, double dt) {
- scegra_update_generic(self, dt);
- float width = self->size.x - self->style.margin * 2;
- struct ScegraLongText_ * st = &self->data.longtext;
- char * text = self->data.longtext.text ?
- self->data.longtext.text : "NULL";
- /* Delay advence of characters somewhat. */
- st->delay_total += dt;
- if (st->delay_total < self->delay) return;
- st->delay_total = 0;
-
- st->line_max = 0;
- al_do_multiline_text(scegra_get_font(self), width,
- (const char *) text, scegra_update_custom_partial_text, self);
- st->line_max++;
-
- /* pause if the last line is reached, and prevent overflow. */
- if (st->line_stop > st->line_max) {
- st->paused = true;
- st->line_pos = SCEGRA_LONGTEXT_LINE_POS_MAX;
- st->line_stop = st->line_max;
- }
- }
- /* Returns TRUE if the longtext node is at the end of the text to display,
- * false if not (more text to display) */
- int scegranode_longtext_at_end(ScegraNode * node) {
- struct ScegraLongText_ * lt;
- if (!node) return FALSE;
- if (node->id < 0) return FALSE;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return FALSE;
- lt = &node->data.longtext;
- return ((lt->line_stop >= lt->line_max) &&
- (lt->line_pos >= SCEGRA_LONGTEXT_LINE_POS_MAX));
- }
- void scegra_draw_box(ScegraNode * self) {
- BeVec p2;
- p2 = bevec_add(self->pos, self->size);
- float thick = self->style.border_thickness;
-
- if (self->style.background_image_id >= 0) {
- ALLEGRO_BITMAP * bmp = store_get_bitmap(self->style.background_image_id);
- /* XXX: need another param for corner size or is the autodetect OK? */
- image_blitscale9(bmp, self->pos.x, self->pos.y, self->size.x, self->size.y,
- -1, -1);
- // self->data.box.round.x, self->data.box.round.y);
- } else {
- al_draw_filled_rounded_rectangle(self->pos.x, self->pos.y, p2.x, p2.y,
- self->data.box.round.x, self->data.box.round.y, self->style.background_color
- );
- }
- if (self->style.border_thickness > 0.0f) {
- al_draw_rounded_rectangle(self->pos.x + thick/2, self->pos.y + thick/2, p2.x - thick/2, p2.y - thick/2,
- self->data.box.round.x - thick/4, self->data.box.round.y - thick/4, self->style.border_color,
- thick);
- }
- }
- /* Calculates the x and y position where to draw text, taking alignment and
- * margin into consideration. */
- static BeVec
- scegra_calculate_text_position(ScegraNode * self) {
- BeVec result;
- int flags = self->style.text_flags;
- result.x = self->pos.x + self->style.margin;
- result.y = self->pos.y + self->style.margin;
- if (flags & ALLEGRO_ALIGN_CENTER) {
- result.x = self->pos.x + self->style.margin + self->size.x / 2;
- } else if (flags & ALLEGRO_ALIGN_RIGHT) {
- result.x = self->pos.x + self->size.x - self->style.margin;
- }
- return result;
- }
- void scegra_draw_text(ScegraNode * self) {
- Font * font;
- int flags;
- BeVec pos = scegra_calculate_text_position(self);
- font = scegra_get_font(self);
- flags = self->style.text_flags | ALLEGRO_ALIGN_INTEGER;
- /* Draw the text twice, once offset in bg color to produce a shadow,
- and once normally with foreground color. */
- al_draw_text(font, self->style.background_color, pos.x + 1, pos.y + 1,
- flags, self->data.text.text);
- al_draw_text(font, self->style.color, pos.x, pos.y,
- flags, self->data.text.text);
- }
- /** Calculates the amount of lines that scegra_draw_partial_text can draw
- * at most with this text. */
- static int scegra_partial_text_lines(ALLEGRO_FONT * font, float w,
- const char * text)
- {
- (void) font; (void) w; (void) text;
- return 0; /* XXX todo */
- }
- /* This function is the helper callback that implements the actual drawing
- * for scegra_draw_partial_text.
- */
- static bool scegra_draw_custom_partial_text(int line_num, const char *line,
- int size, void *extra) {
- float x, y;
- ScegraNode * self = extra;
- struct ScegraLongText_ * st = &self->data.longtext;
- ALLEGRO_USTR_INFO info;
- int real_size, flags;
- double width;
- ALLEGRO_FONT * font;
- BeVec pos;
-
- font = scegra_get_font(self);
- flags = self->style.text_flags | ALLEGRO_ALIGN_INTEGER;
- pos = scegra_calculate_text_position(self);
-
-
- /* Don't draw lines before start but keep on drawing (for later lines) */
- if (line_num < st->line_start) return true;
- /* Don't draw lines after stop, drawing is done */
- if (line_num >= st->line_stop) return false;
- real_size = size;
- /* calculate position */
- x = pos.x;
- y = pos.y + (st->line_height * (line_num - st->line_start));
- /* Reveal letter by letter on last line */
- if (line_num == (st->line_stop - 1)) {
- real_size = (st->line_pos < size) ? st->line_pos : size;
- /* Draw continuation marker if paused. */
- if (st->paused) {
- float x1, y1, x2, y2, x3, y3;
- y2 = y + 8;
- x2 = x + self->size.x - self->style.margin;
- x1 = x2 - 8;
- y1 = y2;
- x3 = x2 - 4;
- y3 = y2 + 8;
- al_draw_filled_triangle(x1, y1, x2, y2, x3, y3, self->style.color);
- }
- }
- al_draw_ustr(font, self->style.background_color,
- x + 1, y + 1, flags, al_ref_buffer(&info, line, real_size));
- al_draw_ustr(font, self->style.color,
- x, y, flags, al_ref_buffer(&info, line, real_size));
-
- return true;
- }
- /* Allows to draw a multi line text partially, from line_start up to
- * line_stop
- * Scraws scrolling text from a prefilled struct. */
- void scegra_draw_partial_text(ScegraNode * self) {
- float width = self->size.x - self->style.margin * 2;
- struct ScegraLongText_ * st = &self->data.longtext;
- char * text = self->data.longtext.text ?
- self->data.longtext.text : "NULL";
- /* It's a bit of a hack that this ends up here... */
- if (st->line_height < 1.0) {
- st->line_height = al_get_font_line_height(scegra_get_font(self));
- }
-
- al_do_multiline_text(scegra_get_font(self), width,
- (const char *) text, scegra_draw_custom_partial_text, self);
-
- }
- void scegra_draw_longtext(ScegraNode * self) {
- Font * font;
- int flags;
- const char * text;
- float width;
- BeVec pos = scegra_calculate_text_position(self);
- font = scegra_get_font(self);
- flags = self->style.text_flags | ALLEGRO_ALIGN_INTEGER;
- text = self->data.longtext.text ?
- self->data.longtext.text : "NULL";
- width = self->size.x - self->style.margin * 2;
- scegra_draw_partial_text(self);
-
- /* Draw the text twice, once offset in bg color to produce a shadow,
- and once normally with foreground color. */
- /*
- al_draw_multiline_text(font, self->style.background_color,
- pos.x + 1, pos.y + 1, width, 0, flags, text);
- al_draw_multiline_text(font, self->style.color,
- pos.x, pos.y, width, 0, flags, text);
- **/
- }
- void scegra_draw_image(ScegraNode * self) {
- Image * image;
- int flags = self->style.image_flags;
- float angle = self->data.bitmap.angle;
- float cx, cy, dx, dy, xscale, yscale;
- cx = self->data.bitmap.src_pos.x + self->data.bitmap.src_size.x / 2;
- cy = self->data.bitmap.src_pos.y + self->data.bitmap.src_size.y / 2;
- dx = self->pos.x + self->size.x / 2;
- dy = self->pos.y + self->size.y / 2;
- xscale = self->size.x / self->data.bitmap.src_size.x;
- yscale = self->size.y / self->data.bitmap.src_size.y;
-
- image = store_get_bitmap(self->data.bitmap.image_id);
- /* Draw missing image rectangle. */
- if (!image) {
- BeVec p2;
- p2 = bevec_add(self->pos, self->size);
- al_draw_filled_rounded_rectangle(self->pos.x, self->pos.y, p2.x, p2.y,
- self->data.box.round.x, self->data.box.round.y, self->style.background_color
- );
- } else {
- al_draw_tinted_scaled_rotated_bitmap(image, self->style.color, cx, cy, dx, dy, xscale, yscale, angle, flags);
- }
- }
- ScegraStyle * scegrastyle_initempty(ScegraStyle * self) {
- if (!self) return NULL;
- self->background_image_id = -1;
- self->color = al_map_rgba_f(1.0,1.0,1.0,1.0);
- self->background_color = al_map_rgba_f(0.0,0.0,0.0,0.0);
- self->border_color = al_map_rgba_f(1.0,1.0,1.0,1.0);
- self->font_id = -1;
- self->line_join_style = 0;
- self->line_miter_limit = 1;
- self->border_thickness = -1;
- self->image_flags = 0;
- self->text_flags = 0;
- self->margin = 0;
- return self;
- }
- ScegraNode *
- scegranode_init_box(ScegraNode * self, int id, BeVec pos, BeVec siz, BeVec round, ScegraStyle style) {
- ScegraData data;
- if (!self) return NULL;
- data.box.round = round;
- scegranode_initall(self, SCEGRA_NODE_BOX,
- id, pos, siz, data, style, scegra_draw_box, scegra_update_generic);
- return self;
- }
- ScegraNode *
- scegranode_init_text(ScegraNode * self, int id, BeVec pos, BeVec siz, const char * text, ScegraStyle style) {
- ScegraData data;
- if (!self) return NULL;
- strncpy(data.text.text, text, SCEGRA_TEXT_MAX);
- data.text.text[SCEGRA_TEXT_MAX - 1] = '\0';
- scegranode_initall(self, SCEGRA_NODE_TEXT,
- id, pos, siz, data, style, scegra_draw_text, scegra_update_generic);
- return self;
- }
- int scegranode_set_longtext_text(ScegraNode * self, const char * text) {
- free(self->data.longtext.text);
- self->data.longtext.text = cstr_dup((char *)text);
- if (!self->data.longtext.text) return -1;
- self->data.longtext.line_start = 0;
- self->data.longtext.line_stop = 1;
- self->data.longtext.line_pos = 0;
- self->data.longtext.delay_total = 0.0;
- scegranode_page_(self, 0);
- return 0;
- }
- ScegraNode *
- scegranode_init_longtext
- (ScegraNode * self, int id, BeVec pos, BeVec siz, char * text, ScegraStyle style) {
- ScegraData data;
- if (!self) return NULL;
- memset(&data.longtext, 0, sizeof(data.longtext));
- data.longtext.page_lines = 4;
- data.longtext.line_start = 0;
- data.longtext.line_stop = 1;
- data.longtext.paused = 0;
- scegranode_initall(self, SCEGRA_NODE_LONGTEXT,
- id, pos, siz, data, style, scegra_draw_longtext, scegra_update_longtext);
- scegranode_set_longtext_text(self, text);
-
- self->done = scegranode_longtext_done;
- scegranode_page_(self, 0);
-
- return self;
- }
- ScegraNode *
- scegranode_init_image_ex(
- ScegraNode * self, int id, BeVec pos, BeVec siz, int image_id, ScegraStyle style,
- BeVec spos, BeVec ssiz, float angle, int flags) {
- ScegraData data;
- if (!self) return NULL;
- data.bitmap.angle = angle;
- data.bitmap.image_id = image_id;
- data.bitmap.src_pos = spos;
- data.bitmap.src_size = ssiz;
- scegranode_initall(self, SCEGRA_NODE_BITMAP,
- id, pos, siz, data, style, scegra_draw_image, scegra_update_generic);
- self->style.image_flags = flags;
- return self;
- }
- ScegraNode *
- scegranode_init_image(ScegraNode * self, int id, BeVec pos, BeVec siz, int image_id, ScegraStyle style) {
- int w, h;
- if (siz.x <= 0.0) { if (store_get_bitmap_width(image_id, &w)) siz.x = w; }
- if (siz.y <= 0.0) { if (store_get_bitmap_height(image_id, &h)) siz.y = h; }
- return scegranode_init_image_ex(self, id, pos, siz, image_id, style, bevec0(), siz, 0.0, 0);
- }
- /* Returns nonzero if the scegranode is in use, false if not */
- static int scegranode_in_use_p(ScegraNode * node) {
- return node->id != -1;
- }
- /* Returns nonzero if the scene graph node id is in use. Also returns
- * false if the ID is out of range. */
- int scegra_id_in_use_p(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return FALSE;
- return scegranode_in_use_p(node);
- }
- /* Returns the first free ID that is larger than the minimum. Returns
- * negative if no more ID's are free. */
- int scegra_get_free_id(int minimum) {
- int index;
- if (minimum < 0) return -1;
- for (index = minimum; index < SCEGRA_NODES_MAX; index++) {
- if (!scegra_id_in_use_p(index)) {
- return index;
- }
- }
- return -1;
- }
- /* Returns maximum amount of nodes. */
- int scegra_nodes_max() {
- return SCEGRA_NODES_MAX;
- }
- /* Initializes the simple 2D scene graph */
- void scegra_init() {
- int index;
- for (index = 0; index < SCEGRA_NODES_MAX; index++) {
- ScegraNode * node = scegra_nodes + index;
- node->id = -1; /* Negative id means unused; */
- }
- scegra_to_draw = 0;
- }
- /* End the use of the simple 2D scene graph */
- void scegra_done() {
- int index;
- for (index = 0; index < SCEGRA_NODES_MAX; index++) {
- ScegraNode * node = scegra_nodes + index;
- scegranode_done(node);
- }
- scegra_to_draw = 0;
- }
- /* Compares a scene graph node with another, for drawing order. Things with low
- z come before those with high z, and with same z, low id comes before high id.
- qsort compatible. No NULL values allowed!!! */
- static inline int scegranode_compare_for_drawing(const void * p1, const void * p2) {
- register const ScegraNode * self = *((ScegraNode **) p1);
- register const ScegraNode * other = *((ScegraNode **) p2);
- register int self_val, other_val;
- /* Compare Z if no nulls. */
- self_val = self->z;
- other_val = other->z;
- if (self_val < other_val) return -1;
- if (self_val > other_val) return 1;
- /* compare id if z is equal */
- self_val = self->id;
- other_val = other->id;
- if (self_val < other_val) return -1;
- if (self_val > other_val) return 1;
- return 0;
- }
- /* Updates the 2d scene graph. */
- void scegra_update(double dt) {
- register int index;
- scegra_to_draw = 0;
-
- for (index = 0; index < SCEGRA_NODES_MAX; index++) {
- register ScegraNode * node = scegra_nodes + index;
- if (node->id < 0) continue; /* Negative id means unused; */
-
- if(node->update) {
- node->update(node, dt);
- }
- /* Only add node to draw array if not hidden and drawable. */
- if((!flags_get(node->flags, SCEGRA_NODE_HIDE)) && (node->draw)) {
- scegra_nodes_todraw[scegra_to_draw] = node;
- scegra_to_draw++;
- }
- }
- /* Sort scene graph nodes for drawing. */
- qsort(scegra_nodes_todraw, scegra_to_draw,
- sizeof(ScegraNode*), scegranode_compare_for_drawing);
- }
- /* Draws the 2d scene graph. */
- void scegra_draw() {
- int index;
- /* All nodes in the todraw will be drawn up to scegra_to_draw,
- there are no other drawable bodes in there. */
- for (index = 0; index < scegra_to_draw; index++) {
- ScegraNode * node = scegra_nodes_todraw[index];
- node->draw(node);
- }
- }
- /* Returns true if out of bounds for the scene graph, or false if ok. */
- int scegra_out_of_bounds(int index) {
- if (index < 0) return TRUE;
- if (index > scegra_nodes_max()) return TRUE;
- return FALSE;
- }
- /* Returns a node from the scene graph or NULL if out of bounds. */
- ScegraNode * scegra_get_node(int index) {
- if (scegra_out_of_bounds(index)) return NULL;
- return scegra_nodes + index;
- }
- /* Returns the ID of the scene graph node at index. -1 means it's free,
- *-2 means out of range. */
- int scegra_get_id(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- return node->id;
- }
- /* Sets the scene graph node as not in use. */
- int scegra_disable_node(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- scegranode_done(node);
- return node->id = -1;
- }
- /* Initializes the node as a box. */
- int scegra_make_box(int id, BeVec pos, BeVec siz, BeVec round, ScegraStyle style) {
- ScegraNode * node = scegra_get_node(id);
- if (!node) return -2;
- scegranode_init_box(node, id, pos, siz, round, style);
- return node->id;
- }
- /* Initialies the node at index as a text. Text can only span one line and must be short.
- Line wrapping must be implemented by making many text nodes for every line of text. */
- int scegra_make_text(int id, BeVec pos, BeVec siz, const char * text, ScegraStyle style) {
- ScegraNode * node = scegra_get_node(id);
- if (!node) return -2;
- scegranode_init_text(node, id, pos, siz, text, style);
- return node->id;
- }
- /* Initialies the node at index as a long text. Long text is arbitrary size and will
- * wrap automatically to the width of the scegra element. */
- int scegra_make_longtext(int id, BeVec pos, BeVec siz, char * text, ScegraStyle style) {
- ScegraNode * node = scegra_get_node(id);
- if (!node) return -2;
- scegranode_init_longtext(node, id, pos, siz, text, style);
- return node->id;
- }
- /* Initializes the node at index as an image node. */
- int scegra_make_image(int id, BeVec pos, BeVec siz, int image_id, ScegraStyle style) {
- ScegraNode * node = scegra_get_node(id);
- if (!node) return -2;
- scegranode_init_image(node, id, pos, siz, image_id, style);
- return node->id;
- }
- /* Gets the style of the scegra object, or if not active, gets a default style. */
- ScegraStyle scegra_get_style(int sindex) {
- ScegraStyle style;
- ScegraNode * snode = scegra_get_node(sindex);
- if (snode && (snode->id >= 0)) {
- style = snode->style;
- } else {
- scegrastyle_initempty(&style);
- }
- return style;
- }
- /* Initializes the node as a box with a style copied from the node at sindex,
- * or if that is not in use, a default style. */
- int scegra_make_box_style_from(int id, BeVec pos, BeVec siz, BeVec round, int sindex) {
- return scegra_make_box(id, pos, siz, round, scegra_get_style(sindex));
- }
- /* Initializes the node as a text with a style copied from the node at sindex,
- * or if that is not in use, a default style. */
- int scegra_make_text_style_from(int id, BeVec pos, BeVec siz, const char * text, int sindex) {
- return scegra_make_text(id, pos, siz, text, scegra_get_style(sindex));
- }
- /* Initializes the node as a text long with a style copied from the node at sindex,
- * or if that is not in use, a default style. */
- int scegra_make_longtext_style_from(int id, BeVec pos, BeVec siz, const char * text, int sindex) {
- return scegra_make_longtext(id, pos, siz, (char *)text, scegra_get_style(sindex));
- }
- /* Initializes the node as a image with a style copied from the node at sindex,
- * or if that is not in use, a default style. */
- int scegra_make_image_style_from(int id, BeVec pos, BeVec siz, int image_id, int sindex) {
- return scegra_make_image(id, pos, siz, image_id, scegra_get_style(sindex));
- }
- /* Returns the Z level of the scene graph node at index. -1 means it's free,
- *-2 means out of range. */
- int scegra_z(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- return node->z;
- }
- /* Sets the Z level of the scene graph node at index. -1 means it's free,
- *-2 means out of range. */
- int scegra_z_(int index, int z) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- return node->z = z;
- }
- /* Sets the FG color of the scegra node (used to draw, e.g. text or lines (but not borders) */
- int scegra_color_(int index, int r, int g, int b, int a) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.color = al_map_rgba(r, g, b, a);
- return node->z;
- }
- /* Sets the border color of the scegra node (used to draw, e.g. text or lines (but not borders) */
- int scegra_border_color_(int index, int r, int g, int b, int a) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.border_color = al_map_rgba(r, g, b, a);
- return node->z;
- }
- /* Sets the background color of the scegra node (used to draw, e.g. text or lines (but not borders) */
- int scegra_background_color_(int index, int r, int g, int b, int a) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.background_color = al_map_rgba(r, g, b, a);
- return node->z;
- }
- /* Sets the border thickness. Set 0 or negative to disable border. */
- int scegra_border_thickness_(int index, float t) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.border_thickness = t;
- return node->z;
- }
- /* Sets the margin. Set 0 or negative to disable border. */
- int scegra_margin_(int index, float m) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.margin = m;
- return node->z;
- }
- /* Sets the scegra node's position. */
- int scegra_position_(int index, float x, float y) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->pos = bevec(x, y);
- return node->z;
- }
- /* Sets the scegra node's size. */
- int scegra_size_(int index, float w, float h) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->size = bevec(w, h);
- return node->z;
- }
- /* Sets the scegra node's speed. */
- int scegra_speed_(int index, float x, float y) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->speed = bevec(x, y);
- return node->z;
- }
- /* Sets the scegra node's background image id . */
- int scegra_background_image_id_(int index, int rindex) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.background_image_id = rindex;
- return node->z;
- }
- /* Sets the scegra node's background font id . */
- int scegra_font_id_(int index, int rindex) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.font_id = rindex;
- return node->z;
- }
- /* Sets the scegra node's foreground image id . */
- int scegra_image_id_(int index, int rindex) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->data.bitmap.image_id = rindex;
- return node->z;
- }
- /* Sets the scegra node to be visible or hidden depending on is_visible. */
- int scegra_visible_(int index, int is_visible) {
- int result;
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- result = flags_get(node->flags, SCEGRA_NODE_HIDE) ? 1 : 0;
- flags_put(&node->flags, SCEGRA_NODE_HIDE, !is_visible);
- return result;
- }
- /* Sets the scegra node's drawing angle for images. */
- int scegra_angle_(int index, float angle) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->data.bitmap.angle = angle;
- return node->z;
- }
- /* Sets the scegra node's drawing flags for images. */
- int scegra_image_flags_(int index, int flags) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.image_flags = flags;
- return node->z;
- }
- /* Sets the scegra node's drawing flags for texts. */
- int scegra_text_flags_(int index, int flags) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- node->style.text_flags = flags;
- return node->z;
- }
- /* Updates the scegra node's text if it is a text or longtext. Returns the node's z value
- * on sucess or negative on failure, if it is not a text or longtext node. */
- int scegra_text_(int index, const char * text) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind == SCEGRA_NODE_TEXT) {
- strncpy(node->data.text.text, text, SCEGRA_TEXT_MAX);
- } else if (node->kind == SCEGRA_NODE_LONGTEXT) {
- scegranode_longtext_done(node);
- scegranode_set_longtext_text(node, text);
- } else {
- return -3;
- }
- return node->z;
- }
- /* Somewhat unrelated, show or hide the system mouse cursor.
- * Returns the state after calling, true means show, false means not shown.
- */
- int scegra_show_system_mouse_cursor(int show) {
- ALLEGRO_DISPLAY * display;
- display = al_get_current_display();
- if(!display) return FALSE;
- if (show) {
- return al_show_mouse_cursor(display);
- } else {
- return (!al_hide_mouse_cursor(display));
- }
- }
- /** Gets the speed of the scregra node. Returns negative on error. */
- int scegra_speed(int index, float * x, float * y) {
- ScegraNode * node = scegra_get_node(index);
- if (!x || !y) return -3;
- if (!node) return -2;
- if (node->id < 0) return -1;
- (*x) = node->speed.x;
- (*y) = node->speed.y;
- return node->z;
- }
- /** Gets the size of the scregra node. Returns negative on error. */
- int scegra_size(int index, float * w, float * h) {
- ScegraNode * node = scegra_get_node(index);
- if (!w || !h) return -3;
- if (!node) return -2;
- if (node->id < 0) return -1;
- (*w) = node->size.x;
- (*h) = node->size.y;
- return node->z;
- }
- int scegra_position(int index, float *x, float * y) {
- /** Gets the positiob of the scregra node. Returns negative on error. */
- ScegraNode * node = scegra_get_node(index);
- if (!x || !y) return -3;
- if (!node) return -2;
- if (node->id < 0) return -1;
- (*x) = node->pos.x;
- (*y) = node->pos.y;
- return node->z;
- }
- int scegra_border_thickness(int index, float * t);
- int scegra_background_color(int index, int * r, int * g,int * b,int * a);
- int scegra_border_color(int index,int * r,int * g,int * b, int * a);
- int scegra_color(int index, int * r, int * g, int * b,int * a);
- /** Returns the natural size of the bitmap of the image. Will be
- * set to -1 if the bitmap isn't loaded yet.
- */
- int scegra_image_bitmap_size(int index, int * w, int * h) {
- int image_id;
- ScegraNode * node = scegra_get_node(index);
- if (!w || !h) return -3;
- if (!node) return -2;
- if (node->id < 0) return -1;
- image_id = node->data.bitmap.image_id;
- if(!store_get_bitmap_width(image_id, w)) (*w) = -1;
- if(!store_get_bitmap_height(image_id, h)) (*h) = -1;
- return node->z;
- }
- /** Sets the last line to display for a long text */
- int scegra_line_stop_(int index, int stop) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- node->data.longtext.line_stop = stop;
- return node->z;
- }
- /** Sets the first line to display for a long text */
- int scegra_line_start_(int index, int start) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- node->data.longtext.line_start = start;
- return node->z;
- }
- /** Sets display delay between individual characters for a long text */
- int scegra_delay_(int index, double delay) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- node->delay = delay;
- return node->z;
- }
- /** Gets the last line to display for a long text or negative on error*/
- int scegra_line_stop(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- return node->data.longtext.line_stop;
- }
- /** Gets the first line to display for a long text */
- int scegra_line_start(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- return node->data.longtext.line_start;
- }
- /** Gets display delay between individual characters for a long text */
- double scegra_delay(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- return node->delay;
- }
- /** Sets amount of shown lines for a long text */
- int scegra_page_lines_(int index, int lines) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- node->data.longtext.page_lines = lines;
- return node->z;
- }
- /** Gets amount of lines for a "page" of long text */
- int scegra_page_lines(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- return node->data.longtext.page_lines;
- }
- /** Sets paused state of long text */
- int scegra_paused_(int index, int paused) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- node->data.longtext.paused = paused;
- return node->z;
- }
- /** Gets paused state of long text */
- int scegra_paused(int index) {
- ScegraNode * node = scegra_get_node(index);
- if (!node) return -2;
- if (node->id < 0) return -1;
- if (node->kind != SCEGRA_NODE_LONGTEXT) return -3;
- return node->data.longtext.paused;
- }
- /** Gets the current text page for a longtext. */
- int scegra_page(int index) {
- ScegraNode * node = scegra_get_node(index);
- return scegranode_page(node);
- }
- /** Gets the number of the last text page for a longtext. */
- int scegra_last_page(int index) {
- ScegraNode * node = scegra_get_node(index);
- return scegranode_last_page(node);
- }
- /** Returns nonzero if the long text is at the end of it's display. */
- int scegra_at_end(int index) {
- ScegraNode * node = scegra_get_node(index);
- return scegranode_longtext_at_end(node);
- }
- /** Advances long text to the given page. Automatically unpauses as well. */
- int scegra_page_(int index, int page) {
- ScegraNode * node = scegra_get_node(index);
- return scegranode_page_(node, page);
- }
- /** Advances long text to the next page. Automatically unpauses as well. */
- int scegra_next_page(int index) {
- int page = scegra_page(index);
- if (page < 0) return page;
- return scegra_page_(index, page + 1);
- }
- /** Advances long text to the previous page. Automatically unpauses as well. */
- int scegra_previous_page(int index) {
- int page = scegra_page(index);
- if (page < 0) return page;
- return scegra_page_(index, page - 1);
- }
- /*
- void scegra_drawframe(ScegraNode * self) {
- draw_frame(self->box.at.x, self->box.at.y,
- self->box.size.x, self->box.size.y,
- self->style.bordersize, self->style.forecolor,
- self->style.backcolor);
- }
- void scegra_drawroundframe(ScegraNode * self) {
- draw_roundframe(self->box.at.x , self->box.at.y,
- self->box.size.x, self->box.size.y,
- self->style.bordersize, self->style.forecolor,
- self->style.backcolor);
- }
- */
- /*
- * ALLEGRO drawing functions:
- *
- al_draw_arc (3) - Allegro 5 API
- al_draw_bitmap (3) - Allegro 5 API
- al_draw_bitmap_region (3) - Allegro 5 API
- al_draw_circle (3) - Allegro 5 API
- al_draw_ellipse (3) - Allegro 5 API
- al_draw_elliptical_arc (3) - Allegro 5 API
- al_draw_filled_circle (3) - Allegro 5 API
- al_draw_filled_ellipse (3) - Allegro 5 API
- al_draw_filled_pieslice (3) - Allegro 5 API
- al_draw_filled_polygon (3) - Allegro 5 API
- al_draw_filled_polygon_with_holes (3) - Allegro 5 API
- al_draw_filled_rectangle (3) - Allegro 5 API
- al_draw_filled_rounded_rectangle (3) - Allegro 5 API
- al_draw_filled_triangle (3) - Allegro 5 API
- al_draw_indexed_prim (3) - Allegro 5 API
- al_draw_justified_text (3) - Allegro 5 API
- al_draw_justified_textf (3) - Allegro 5 API
- al_draw_justified_ustr (3) - Allegro 5 API
- q (3) - Allegro 5 API
- al_draw_pieslice (3) - Allegro 5 API
- al_draw_pixel (3) - Allegro 5 API
- al_draw_polygon (3) - Allegro 5 API
- al_draw_polygon_with_holes (3) - Allegro 5 API
- al_draw_polyline (3) - Allegro 5 API
- al_draw_polyline_ex (3) - Allegro 5 API
- al_draw_prim (3) - Allegro 5 API
- al_draw_rectangle (3) - Allegro 5 API
- al_draw_ribbon (3) - Allegro 5 API
- al_draw_rotated_bitmap (3) - Allegro 5 API
- al_draw_rounded_rectangle (3) - Allegro 5 API
- al_draw_scaled_bitmap (3) - Allegro 5 API
- al_draw_scaled_rotated_bitmap (3) - Allegro 5 API
- al_draw_soft_line (3) - Allegro 5 API
- al_draw_soft_triangle (3) - Allegro 5 API
- al_draw_spline (3) - Allegro 5 API
- al_draw_text (3) - Allegro 5 API
- al_draw_textf (3) - Allegro 5 API
- al_draw_tinted_bitmap (3) - Allegro 5 API
- al_draw_tinted_bitmap_region (3) - Allegro 5 API
- al_draw_tinted_rotated_bitmap (3) - Allegro 5 API
- al_draw_tinted_scaled_bitmap (3) - Allegro 5 API
- al_draw_tinted_scaled_rotated_bitmap (3) - Allegro 5 API
- al_draw_tinted_scaled_rotated_bitm... (3) - Allegro 5 API
- al_draw_triangle (3) - Allegro 5 API
- al_draw_ustr (3) - Allegro 5 API
- al_draw_vertex_buffer (3) - Allegro 5 API
- So the most important drawing functions I'll implement and
- group together are:
- * Circle / arc drawing and Ellipse / elliptical arc drawing.
- * Rectangle drawing and Rounded rectangle drawing.
- * Triangle drawing.
- * Polygon drawing.
- * Line drawing.
- * Point drawing.
- * Spline Drawing.
- * Bitmap Drawing.
- */
- #define TUPLE(A,B) tuple_##A##B
- #define DEFINE_TUPLE(A, B) typedef struct TUPLE(A,B) { A head; B tail; } TUPLE(A,B)
- #define TUPLE_HEAD(T) (T).head
- #define TUPLE_TAIL(T) (T).tail
- #define TUPLEPTR_HEAD(T) (T)->head
- #define TUPLEPTR_TAIL(T) (T)->tail
- typedef char * charp;
- DEFINE_TUPLE(int, charp);
|