#!/usr/local/bin/bbx use complex use vector use map use b using namespace std typedef complex cmplx cmplx j = cmplx(0,1) random_init() srandom(time(NULL)) double randomd() return random()/(double)RAND_MAX # handlers --------------------------------------------------------- typedef void (*Thunk)(void) typedef void (*OnOffHandler)(bool) # time scheduling code --------------------------------------------- typedef struct timeval timeval bool operator<(const timeval &t1, const timeval &t2) return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec) timeval current_time typedef multimap schedule_t schedule_t schedule rocks_schedule_dump() schedule_t::iterator i = schedule.begin() schedule_t::const_iterator end = schedule.end() warn("%s\n", "- schedule -") for ; i != end; ++i warn("time: %ld : %ld\n", i->first.tv_sec, i->first.tv_usec) warn("%s\n", "------------") rocks_scheduler_gettime() gettimeofday(¤t_time, NULL) #warn("crnt: %ld : %ld\n", current_time.tv_sec, current_time.tv_usec) rocks_scheduler() #warn("%s\n", "start scheduler") csleep(0) repeat #warn("%s\n", "scheduler loop") rocks_scheduler_gettime() #schedule_dump() # start at begin of map, check each if key less than current_time, # execute the thunks and delete the pairs schedule_t::iterator i = schedule.begin() for ; i != schedule.end(); ++i if i->first < current_time #warning("%s\n", "invoking callback") (i->second)() else num dt = timeval_to_rtime(&i->first) - timeval_to_rtime(¤t_time) csleep(dt) break schedule.erase(schedule.begin(), i) #timespec delta #delta.tv_sec = 0 #delta.tv_nsec = 2000000 #warn("%s\n", "about to nanosleep for 2ms") #nanosleep(&delta, NULL) #it was too clunky with these dodgy nanosleeps at(long at_sec, long at_usec, Thunk handler) timeval tv tv.tv_sec = at_sec ; tv.tv_usec = at_usec schedule.insert(make_pair(tv,handler)) # warn("schd: %ld : %ld\n", tv.tv_sec, tv.tv_usec) after(long sleep_sec, long sleep_usec, Thunk handler) long at_sec = current_time.tv_sec + sleep_sec long at_usec = current_time.tv_usec + sleep_usec if at_usec > 1000000 at_usec -= 1000000 ++at_sec at(at_sec, at_usec, handler) after_ms(long sleep_ms, Thunk handler) #warn("after_ms: %ld\n", sleep_ms) after(sleep_ms / 1000, (sleep_ms % 1000) * 1000, handler) # global X11 data ----------------------------------------------------- Display *display Window window Pixmap doublebuffer Colormap colormap GC gc XGCValues gcvalues XFontStruct *_font const char *font_name = "-adobe-helvetica-medium-r-normal--11-80-100-100-p-56-iso8859-1" long black_, white_, red_, blue_, dred, dblue, green_, grey_ long text_fade[256] XEvent event # key handlers ----------------------------------------------- #int first_keycode, last_keycode #OnOffHandler *key_press_release_handlers #Thunk *key_press_handlers map key_press_release_handlers map key_press_handlers #alloc_key_handlers() # XDisplayKeycodes(display, &first_keycode, &last_keycode) # key_press_release_handlers = (OnOffHandler *)Calloc(last_keycode-first_keycode+1, sizeof(OnOffHandler)) # key_press_handlers = (Thunk *)Calloc(last_keycode-first_keycode+1, sizeof(Thunk)) bind(const char *keyname, Thunk handler) KeySym keysym = XStringToKeysym(keyname) key_press_handlers[keysym] = handler bind2(const char *keyname, OnOffHandler handler) KeySym keysym = XStringToKeysym(keyname) key_press_release_handlers[keysym] = handler unbind(const char *keyname) KeySym keysym = XStringToKeysym(keyname) key_press_handlers.erase(keysym) key_press_release_handlers.erase(keysym) command_keyboard(int keycode, int state, int press_release) int shift = state & ShiftMask ? 1 : 0 KeySym keysym = XKeycodeToKeysym(display, keycode, shift) if press_release == 1 Thunk handler = key_press_handlers[keysym] if handler != NULL (*handler)() return OnOffHandler handler = key_press_release_handlers[keysym] if handler != NULL (*handler)(press_release) else #warn("unhandled keypress: %s %d\n", XKeysymToString(XKeycodeToKeysym(display, keycode, shift)), press_release) # text ------------------------------------------------------ intro() videoPrint("rocks 1.03") videoPrint("") videoPrint("Copyright 2003 - 2009 Sam Watkins") videoPrint("This is free software with ABSOLUTELY NO WARRANTY.") videoPrint("For details, type `i' during gameplay.") videoPrint("Type `h' if you don't know how to play.") videoPrint("") # FIXME brace multi-line quoting, newline escaping, implement a clean `print' command too - & polymorphic functions? info() videoPrint("") videoPrint("Happy Birthday, Ana!") videoPrint("") videoPrint("Copyright 2003, 2004 Sam Watkins") videoPrint("") videoPrint(" This program is free software; you can redistribute it and/or modify") videoPrint(" it under the terms of the GNU General Public License as published by") videoPrint(" the Free Software Foundation; either version 2 of the License , or") videoPrint(" (at your option) any later version.") videoPrint("") videoPrint(" This program is distributed in the hope that it will be useful,") videoPrint(" but WITHOUT ANY WARRANTY; without even the implied warranty of") videoPrint(" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the") videoPrint(" GNU General Public License for more details.") videoPrint("") videoPrint(" You should have received a copy of the GNU General Public License") videoPrint(" along with this program. If not, write to") videoPrint("") videoPrint(" The Free Software Foundation, Inc.") videoPrint(" 59 Temple Place, Suite 330") videoPrint(" Boston, MA 02111, USA.") videoPrint("") videoPrint(" You can also obtain a copy of the GPL from the Internet:") videoPrint("") videoPrint(" http://www.gnu.org/licenses/gpl.txt") videoPrint("") videoPrint("") videoPrint("Rocks is a peaceful game.") videoPrint("") videoPrint("") videoPrint("If you enjoy this game, please send me a card!") videoPrint("Cards are an alternative to currency - for more information,") videoPrint("point your browser at:") videoPrint("") videoPrint(" http://cards.sourceforge.net/") videoPrint(" http://cards.sourceforge.net/cgi-bin/view?Sam.Watkins") videoPrint("") videoPrint("") videoPrint(" Sam Watkins ") videoPrint("") print_help() videoPrint("") videoPrint("Your Mission - Pop the Rocks!") videoPrint("") videoPrint(" z left") videoPrint(" x right") videoPrint(" enter thrust") videoPrint(" / retro") videoPrint("") videoPrint(" space hide") videoPrint(" q bang!") videoPrint("") videoPrint(" - previous level") videoPrint(" = restart level") videoPrint(" + next level") videoPrint("") videoPrint(" i info") videoPrint(" h help") videoPrint(" p pause") videoPrint(" Escape quit") videoPrint("") videoPrint("Each rock has a gender and sexual preference!") videoPrint("") videoPrint(" Dark red: straight male") videoPrint(" Dark blue: straight female") videoPrint(" Bright red: gay male") videoPrint(" Bright blue: gay female") videoPrint("") videoPrint("This determines how they interact,") videoPrint("for example dark blue and dark red attract eachother,") videoPrint("and a dark blue will chase a bright red, which will run away!") videoPrint("") videoPrint("Your ship also has gender and sexuality, but initially you don't know what.") videoPrint("You can guess what gender you are based on whether rocks are attracted to") videoPrint("or repelled from you and whether you are attracted to or repelled from them.") videoPrint("Your gender and sexuality change from time to time. A little message") videoPrint("alerts you to this.") videoPrint("") videoPrint("Have fun!") videoPrint("") # configuration --------------------------------------------- #w = 1280 ; h = 1024 int w = 640 , h = 480 int frame_sleep = 10 double resistance = 0.05 double G = 1.5 double max_init_vel = 1.0 double dt = 0.5 # 0.25 int new_level_sleep = 3000 int sleep_of_death = 2000 int start_space = 70 double light = 100 double heavy = 100 double ship_mass = 0 double turn_rate = 0.01 double thrust_rate = 0.03 double retro_rate = 0.01 bool rocks_warp = 0 bool ship_warps = 0 double max_orbit_vel = 3.0 #double prob_coed = 0.7 double prob_coed = 1 double prob_bent = 0 int min_queerity_sleep = 200000000 int max_queerity_sleep = 300000000 # globals ------------------------------------------------ cmplx center = cmplx(w/2, h/2) # level data --------------------------------------------- int level = 1 double g bool coed int gob int sg double level_orbit # state -------------------------------------------------- bool paused = 0 int after_cancel = 0 bool scheduled = 0 struct Rock bool is_bouncy double m double r cmplx x cmplx v cmplx a int gender bool to_be_removed bool bent # virtual ~Rock() {} struct Ship: public Rock bool is_here double t double tv bool thrusting, retroing, lefting, righting, hidden int sg cmplx forwards, right, p0, p1, p2 vector rocks(0) Ship ship warp(Rock &s) if s.x.real() < 0 s.x = cmplx(s.x.real()+w, s.x.imag()) if s.x.real() > w s.x = cmplx(s.x.real()-w, s.x.imag()) if s.x.imag() < 0 s.x = cmplx(s.x.real(), s.x.imag()+h) if s.x.imag() > h s.x = cmplx(s.x.real(), s.x.imag()-h) bounce(Rock &r) if r.x.real() < r.r r.x = cmplx(2*r.r-r.x.real(), r.x.imag()) ; r.v = cmplx(-r.v.real(), r.v.imag()) else if r.x.real() > w - r.r r.x = cmplx(2*(w-r.r)-r.x.real(), r.x.imag()) ; r.v = cmplx(-r.v.real(), r.v.imag()) if r.x.imag() < r.r r.x = cmplx(r.x.real(), 2*r.r-r.x.imag()) ; r.v = cmplx(r.v.real(), -r.v.imag()) else if r.x.imag() > h - r.r r.x = cmplx(r.x.real(), 2*(h-r.r)-r.x.imag()) ; r.v = cmplx(r.v.real(), -r.v.imag()) int next_gender = 1 Rock_init(Rock &self) self.is_bouncy = 1 double q = -0.5 self.m = pow(randomd()*(pow(heavy,q)-pow(light,q))+pow(light,q), 1/q) self.r = sqrt(self.m) repeat #warn("choosing a point for the rock\n") self.x = cmplx(randomd() * (w-self.r*2) + self.r, randomd() * (h-self.r*2) + self.r) if ship.is_here && abs(self.x - ship.x) < start_space continue #warn("not near ship - good!") bool overlapping = 0 # XXX this is hideous vector::iterator r = rocks.begin() vector::const_iterator r1 = rocks.end() for ; r != r1; ++r #warn("comparing for overlap\n") if abs(self.x - (*r)->x) < self.r + (*r)->r overlapping = 1 ; break if ! overlapping break #warn("okay") self.v = randomd()*max_init_vel * exp(j*randomd()*2.0*pi) cmplx d, u d = self.x - center ; u = d/abs(d) self.v += u*j * level_orbit / abs(d) * double(h) * max_orbit_vel if coed # self.gender = int(randomd()*2)*2 - 1 self.gender = next_gender next_gender *= -1 else self.gender = gob self.a = 0.0 self.to_be_removed = 0 self.bent = randomd() 0 long rock_colour(Rock &r) long c if r.gender < 0 if gay(r) c = blue_ else c = dblue else if r.gender > 0 if gay(r) c = red_ else c = dred else c = grey_ return c change_dress(Ship &self) if paused return self.gender = -self.gender self.sg = - self.sg videoPrint("I'm a sweet transvestite...") change_attraction(Ship &self) if paused return self.sg = - self.sg videoPrint("A shiver runs down your spine...") change_gender(Ship &self) if paused return self.gender = -self.gender videoPrint("Ouch! that hurt") change_sexuality(Ship &self) int i = int(randomd()*3) if i == 0 change_dress(self) else if i == 1 change_attraction(self) else change_gender(self) calc(Ship &s) s.forwards = cmplx(sin(s.t), cos(s.t)) * s.r s.right = s.forwards / j s.p0 = 2.0*s.forwards + s.x s.p1 = s.right-s.forwards + s.x s.p2 = -s.right-s.forwards + s.x #warn("%s\n", "calc:") #warn("s.forwards: %f %f\n", s.forwards.real(), s.forwards.imag()) #warn("s.right: %f %f\n", s.right.real(), s.right.imag()) #warn("s.p0: %f %f\n", s.p0.real(), s.p0.imag()) #warn("s.p1: %f %f\n", s.p1.real(), s.p1.imag()) #warn("s.p2: %f %f\n", s.p2.real(), s.p2.imag()) bool bent(Ship &s) return s.sg == sg bang() if paused return videoPrint("bang!\n") unbind("Return") unbind("slash") unbind("z") unbind("x") unbind("q") unbind("space") unbind("p") unbind("plus") unbind("equal") unbind("minus") rocks[0] = NULL ship.is_here = 0 # XXX X11 self.ci.delete() after_ms(sleep_of_death, start) dump_rocks() warn("rocks:\n") if rocks[0] != NULL printf("ship ") else printf("dead ") int i,l l = rocks.size() for i=1; ito_be_removed printf("X ") else printf("O ") printf("\n"); bool check_side(Rock &r, Ship &s, cmplx p, cmplx q) cmplx pq, pqu, pr, d double dpq, dpr, dx, dy pq = q-p ; dpq = abs(pq) ; pqu = pq/dpq pr = r.x-p ; dpr = abs(pr) d = pr / pqu dx = d.real() dy = d.imag() if (dy < r.r && dy >= 0.0 && dx > 0.0 && dx < dpq) || (abs(pr) < r.r) if abs(pr) < r.r && p == s.p0 pop(r) return 1 else bang() return 1 return 0 move(Ship &s) if bent(s) s.a = -s.a if s.thrusting s.a += s.forwards * thrust_rate if s.retroing s.a -= s.forwards * retro_rate if s.lefting s.tv -= turn_rate * dt if s.righting s.tv += turn_rate * dt s.v += s.a * dt s.v *= pow(1-resistance, dt) s.tv *= pow(1-resistance, dt) s.a = 0 s.x += s.v * dt s.t += s.tv * dt if ship_warps warp(s) else bounce(s) calc(s) if ! s.is_bouncy vector::iterator r = rocks.begin() vector::const_iterator r1 = rocks.end() for ; r != r1; ++r check_side(**r, s, s.p0,s.p1) || check_side(**r, s, s.p1,s.p2) || check_side(**r, s, s.p2,s.p0) if rocks[0] == NULL return # XXX X11 s.ci.coords(((s.p0.real(), h-s.p0.imag()), (s.p1.real(), h-s.p1.imag()), (s.p2.real(), h-s.p2.imag()))) thrust(bool p) #warn("THRUST %d\n", p) ship.thrusting = p retro(bool p) #warn("RETRO %d\n", p) ship.retroing = p turnleft(bool p) #warn("LEFT %d\n", p) ship.lefting = p turnright(bool p) #warn("RIGHT %d\n", p) ship.righting = p hide() if paused return ship.hidden = ! ship.hidden ship.is_bouncy = ship.hidden if ship.hidden # XXX X11 ship.ci.coords(((-1,-1),(-1,-1),(-1,-1))) videoPrint("where'd he go?") else videoPrint("thar she blows!") sched_update() #warn("%s\n", "sched_update") if ! scheduled scheduled = 1 after_ms(frame_sleep, update) pause_game() paused = ! paused if ! paused sched_update() delete_all_rocks() vector::iterator r = rocks.begin() vector::const_iterator r1 = rocks.end() for ; r != r1; ++r delete(*r) rocks.resize(0) random_level() coed = randomd() < prob_coed if ! coed gob = int(randomd()*2)*2-1 # sg = int(randomd()*2)*2-1 sg = -1 level_orbit = randomd()-0.5 plant_rocks() after_cancel -= 1 if after_cancel == 0 #warn("%s\n", "planting rocks!") # if rocks[0] == NULL # return int i for i=0; i 0 level -= 1 new_level() do_exit() Exit(0) const char *compliments[] = "Right on, commander!", "Great flying!", "Awesome effort!", "Are you addicted yet?", "Let's see you pass the NEXT level!", "You had me worried for a minute there!", "Fantasic!", "Go for the record!", "This is just too easy for you, isn't it?", "No one got past that rock before!", NULL int ncompliments = 10 level_complete() if ncompliments>0 int i = int(randomd()*ncompliments) videoPrint(compliments[i]) for ; i=0; --a r = rocks[a] if r->to_be_removed delete r for b=a+1; b<=high; ++b rocks[b-1] = rocks[b] --high rocks.resize(high+1) if high == 0 level_complete() complete else move(*r) #dump_rocks() for a=low+1; a<=high; ++a for b=low; b::iterator r = rocks.begin() vector::const_iterator r1 = rocks.end() # draw rocks for ; r != r1; ++r cmplx x = (*r)->x double rad = (*r)->r gcvalues.foreground = rock_colour(**r) XChangeGC(display, gc, GCForeground, &gcvalues) XFillArc(display, doublebuffer, gc, int(x.real() - rad), h-int(x.imag() + rad), int(rad*2), int(rad*2), 0, 64*360) gcvalues.foreground = white_ XChangeGC(display, gc, GCForeground, &gcvalues) XDrawArc(display, doublebuffer, gc, int(x.real() - rad), h-int(x.imag() + rad), int(rad*2), int(rad*2), 0, 64*360) # draw ship if ship.is_here && ! ship.hidden points[0].x = int(ship.p0.real()) points[0].y = h-int(ship.p0.imag()) points[1].x = int(ship.p1.real()) points[1].y = h-int(ship.p1.imag()) points[2].x = int(ship.p2.real()) points[2].y = h-int(ship.p2.imag()) points[3].x = int(ship.p0.real()) points[3].y = h-int(ship.p0.imag()) # self.ci = Polygon(canvas, 0, 0, 0, 0, 0, 0, fill='#005500', outline='white') #warn("ship: %f %f %f %f %f %f\n", ship.p0.real(), ship.p0.imag(), ship.p1.real(), ship.p1.imag(), ship.p2.real(), ship.p2.imag()) gcvalues.foreground = green_ XChangeGC(display, gc, GCForeground, &gcvalues) XFillPolygon(display, doublebuffer, gc, points, 4, Convex, CoordModeOrigin) gcvalues.foreground = white_ XChangeGC(display, gc, GCForeground, &gcvalues) XDrawLines(display, doublebuffer, gc, points, 4, CoordModeOrigin) videoPrint_render() gcvalues.tile = doublebuffer gcvalues.fill_style = FillTiled XChangeGC(display, gc, GCTile|GCFillStyle, &gcvalues) XFillRectangle(display, window, gc, 0, 0, w, h) gcvalues.fill_style = FillSolid XChangeGC(display, gc, GCTile|GCFillStyle, &gcvalues) configure_notify() #warn("%s\n", "config not") . button_event(int button, int type, int x, int y) if button >= 1 && button <= 3 #warn("button %d type %d\n", button, type) # ButtonController *bc = controller->button[button-1] # ((*bc)[type])(x, y) else #warn("unknown button %d\n", button) # the X11 event loop -------------------------------------------------- Bool true_pred(Display *f, XEvent *e, XPointer p) return True sched_check_events() check_events() unsigned int button = 0 #warn("%s\n", "try to get event") while XCheckIfEvent(display, &event, true_pred, NULL) #warn("%s\n", "got an event") which event.type Expose . #warn("expose event - count: %d\n", event.xexpose.count) if (event.xexpose.count == 0) redraw() ConfigureNotify configure_notify() ButtonPress if button != 0 #warn("press %d then press %d - latter ignored\n", button, event.xbutton.button) else button = event.xbutton.button button_event(button, 0, event.xbutton.x, event.xbutton.y) MotionNotify . # We skip all but the most recent motion event. # This might be a bit dodgy, we could skip past a # release/press pair... while XCheckTypedEvent(display, MotionNotify, &event) . button_event(button, 1, event.xmotion.x, event.xmotion.y) ButtonRelease if button == 0 #warn("no press then release b%d - release ignored", event.xbutton.button) else if event.xbutton.button != button #warn("press b%d then release b%d - release ignored", event.xbutton.button) else button_event(button, 2, event.xbutton.x, event.xbutton.y) button = 0 KeyPress command_keyboard(event.xkey.keycode, event.xkey.state, 1) KeyRelease command_keyboard(event.xkey.keycode, event.xkey.state, 0) MapNotify UnmapNotify ReparentNotify break else warn("unhandled event, type: 0x%04x\n", event.type) #warn("%s\n", "no more events for the moment") sched_check_events() # Ship init ----------------------------------------------------------- Ship_init(Ship &self) self.is_here = 1 self.is_bouncy = 0 self.x = center self.v = 0 self.a = 0 self.t = 0 self.tv = 0 self.r = 10 self.thrusting = 0 self.retroing = 0 self.lefting = 0 self.righting = 0 self.hidden = 0 self.m = ship_mass self.gender = int(randomd()*2)*2 - 1 self.sg = int(randomd()*2)*2 - 1 bind2("Return", thrust) bind2("slash", retro) bind2("z", turnleft) bind2("x", turnright) bind("q", bang) bind("space", hide) bind("p", pause_game) bind("plus", next_level) bind("equal", new_level) bind("minus", prev_level) # the main program ---------------------------------------------------- start() Ship_init(ship) # rocks[0] = &ship new_level() sched_update() sched_check_events() after_ms(frame_sleep, check_events) Main() if (display = XOpenDisplay(NULL)) == NULL error("cannot open display\n") #alloc_key_handlers() bind("h", print_help) bind("i", info) bind("Escape", do_exit) Window root XColor color int screen_number screen_number = DefaultScreen(display) white_ = WhitePixel(display, screen_number) black_ = BlackPixel(display, screen_number) colormap = DefaultColormap(display, screen_number) red_ = blue_ = dred = dblue = green_ = grey_ = white_ if XAllocNamedColor(display, colormap, "red", &color, &color) red_ = color.pixel if XAllocNamedColor(display, colormap, "blue", &color, &color) blue_ = color.pixel if XAllocNamedColor(display, colormap, "#550000", &color, &color) dred = color.pixel if XAllocNamedColor(display, colormap, "#000055", &color, &color) dblue = color.pixel if XAllocNamedColor(display, colormap, "#005500", &color, &color) green_ = color.pixel if XAllocNamedColor(display, colormap, "#333333", &color, &color) grey_ = color.pixel rainbow_init() for int i=0; i<256; ++i # char n[8] # sprintf(n, "#%02x%02x%02x", (int)(i*0.6), i, (int)(i*0.4)) # if XAllocNamedColor(display, colormap, n, &color, &color) # text_fade[255-i] = hsv(i*8*360/256.0, i/256.0, i/256.0*0.5) num g = i/256.0 text_fade[255-i] = rgb(g, g, g) if (_font = XLoadQueryFont(display, font_name)) == NULL error("cannot load font\n") gc = DefaultGC(display, screen_number) gcvalues.function = GXcopy gcvalues.foreground = white_ gcvalues.cap_style = CapNotLast gcvalues.line_width = 0 gcvalues.font = _font->fid XChangeGC(display, gc, GCFunction|GCForeground|GCCapStyle|GCLineWidth|GCFont, &gcvalues) root = DefaultRootWindow(display) window = XCreateSimpleWindow(display, root, 0, 0, w, h, 0, white_, black_) doublebuffer = XCreatePixmap(display, window, w, h, XDefaultDepth(display, screen_number)) XSelectInput(display, window, ExposureMask|ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask) XMapWindow(display, window) rocks_scheduler_gettime() intro() random_init() start() sched_queerity() sched_check_events() rocks_scheduler() videoPrintf(const char *format, ...) collect_void(vvideoPrintf, format) vvideoPrintf(const char *format, va_list ap) new(b, buffer, 128) Vsprintf(b, format, ap) videoPrint(buffer_to_cstr(b)) buffer_free(b) int videoPrint_y struct videoPrint_line cstr s int col int y vec _videoPrint_lines, *videoPrint_lines = NULL vec _videoPrint_colours, *videoPrint_colours = NULL videoPrint(const char *s) say(s) if !videoPrint_lines videoPrint_lines = &_videoPrint_lines init(videoPrint_lines, vec, videoPrint_line, 100) if vec_is_empty(videoPrint_lines) videoPrint_y = 5 cstr *lines = split_dup(s, '\n') forary(i, lines) Decl(l, videoPrint_line) l->s = Strdup(i) l->col = 0 l->y = videoPrint_y += font_height() *(videoPrint_line *)vec_push(videoPrint_lines) = *l Free(lines) videoPrint_render() if videoPrint_lines move(w/2, 5) int e = vec_get_size(videoPrint_lines) int o = 0 int i for i=0 ; is int col = l->col++ gcvalues.foreground = text_fade[col/2] XChangeGC(display, gc, GCForeground, &gcvalues) int tw = text_width(s) move(w/2 - tw/2, ly) gprint(s) if col == 511 Free(s) else if o != i *(videoPrint_line*)vec_element(videoPrint_lines, o) = *l ++o if o < i vec_set_size(videoPrint_lines, o) num lx, lx move(num x, num y) lx = x ; ly = y num text_width(char *p) int len = strlen(p) return XTextWidth(_font, p, len) num font_height() return _font->ascent + _font->descent # this one doesn't do word wrapping but does do anchors! gprint(char *p) int len = strlen(p) int text_width = XTextWidth(_font, p, len) use(text_width) # XDrawString(display, buf, gc, (int)(SX(lx)-text_width*(_xanc+1)/2.0+1), (int)(SY(ly)+(_font->ascent+_font->descent)*(_yanc-1)/2.0+1)+_font->ascent, p, len) # the anchoring uses the ascent portion of the box only, this looks better # XDrawString(display, doublebuffer, gc, (int)(SX(lx)-text_width*(_xanc+1)/2.0+1), (int)(SY(ly)+_font->ascent*(_yanc+1)/2.0+0.5), p, len) XDrawString(display, doublebuffer, gc, lx, ly+_font->ascent, p, len) move(lx, ly + font_height()) # Rsleep(1) font(cstr name, int size) let(xfontname, Format("-*-%s-r-normal--%d-*-100-100-p-*-iso8859-1", name, size)) xfont(xfontname) Free(xfontname) xfont(char *font_name) # XXX does this have a memory leak? if (_font = XLoadQueryFont(display, font_name)) == NULL error("cannot load font %s", font_name) gcvalues.font = _font->fid XChangeGC(display, gc, GCFont, &gcvalues) def font(name) xfont(name) def hsv(hue, sat, val) _hsv(angle2rad(hue), sat, val) colour _hsv(num hue, num sat, num val) num r = rb_red_power * (cos(hue-rb_red_angle)+1)/2 num g = rb_green_power * (cos(hue-rb_green_angle)+1)/2 num b = rb_blue_power * (cos(hue-rb_blue_angle)+1)/2 r *= sat g *= sat b *= sat r = 1-(1-r)*(1-val) g = 1-(1-g)*(1-val) b = 1-(1-b)*(1-val) return rgb(r, g, b) colour rgb(num red_, num green_, num blue_) char name[8] int r, g, b r = iclamp(red_*256, 0, 255) g = iclamp(green_*256, 0, 255) b = iclamp(blue_*256, 0, 255) snprintf(name, sizeof(name), "#%02x%02x%02x", r, g, b) XColor colour if XAllocNamedColor(display, colormap, name, &colour, &colour) return colour.pixel return white_ Def trig_unit deg