/** Set the in and out speeds of a host in Bytes per second. **/ static value udpr_setrate(value o, value in, value out) { if( !val_is_abstract(o) || !val_is_kind(o,k_udprhost) ) neko_error(); enet_host_bandwidth_limit((ENetHost *)val_data(o), (enet_uint32)val_int32(in), (enet_uint32)val_int32(out)); return val_true; }
/** Destroy an allocated ENetEvent struct **/ static void destroy_enetevent( value e ) { ENetEvent *event; if( !val_is_abstract(e) || !val_is_kind(e,k_udprevent) ) return; event = (ENetEvent *)val_data(e); if(e == NULL) return; // enet_packet_destroy frees the packet itself. #ifdef ENET_DEBUG printf("*** destroy_enetevent freeing packet\n"); #endif if(event->packet != NULL) enet_packet_destroy (event->packet); //if(event->type == ENET_EVENT_TYPE_DISCONNECT //&& event->peer->data != NULL) //enet_free(event->peer -> data); #ifdef ENET_DEBUG //printf("*** destroy_enetevent freeing event\n"); #endif enet_free(event); #ifdef ENET_DEBUG //printf("*** destroy_enetevent done.\n"); #endif return; }
/** Destroy an ENetPeer structure. **/ static void destroy_enetpeer( value p ) { #ifdef ENET_DEBUG fprintf(stderr, "*** destroy_enetpeer\n"); exit(0); #endif return; ENetPeer *peer; if(!val_is_abstract(p) || !val_is_kind(p, k_udprpeer)) return; peer = (ENetPeer *)val_data(p); if(peer == NULL) return; // force immediate disconnect, if still connected. enet_peer_disconnect_now(peer, 0); // if the peer has an event still, destroy it //free_peer_event(peer); // clear the peer structure enet_peer_reset(peer); // peers never need be deallocated, they are part of an ENetHost #ifdef ENET_DEBUG fprintf(stderr, "*** destroy_enetpeer done.\n"); #endif return; }
EXTERN void val_gc(value v, finalizer f ) { if( !val_is_abstract(v) ) failure("val_gc"); if( f ) GC_REGISTER_FINALIZER_NO_ORDER(v,(GC_finalization_proc)__on_finalize,f,0,0); else GC_REGISTER_FINALIZER_NO_ORDER(v,NULL,NULL,0,0); }
/** Returns the ENetPeer that generated an event, with the Event allocated pointer in Peer->data. The returned ENetPeer must not be destroyed, since it's a copy of an existing peer pointer. Timeout is float number of seconds (0.001 == 1 ms) **/ static value udpr_poll(value h, value timeout) { //ENetPeerHandle hndPeer = enet_host_peer_to_handle(host, event->peer); ENetEvent *event; int res; if( !val_is_abstract(h) || !val_is_kind(h,k_udprhost) ) neko_error(); val_check(timeout,number); enet_uint32 tout = (enet_uint32)(val_number(timeout)*1000); event = (ENetEvent *) enet_malloc (sizeof (ENetEvent)); // Wait up to timeout milliseconds for an event. res = enet_host_service ((ENetHost *)val_data(h), event, tout); if(res <= 0) { if(res == 0) return val_null; neko_error(); } switch (event->type) { case ENET_EVENT_TYPE_NONE: //if(event->peer != NULL) //free_peer_event(event->peer); enet_free(event); return val_null; break; default: // auto frees any existing unhandled event, add this event. #ifdef ENET_DEBUG_FULL if(event->type == ENET_EVENT_TYPE_RECEIVE) fprintf(stderr, "udpr_poll: event type %s %0.*s\n", event_to_string(event->type), event->packet->dataLength, event->packet->data); else fprintf(stderr, "udpr_poll: event type %s\n", event_to_string(event->type)); #endif break; } value v = alloc_abstract(k_udprevent,event); val_gc(v, destroy_enetevent); return v; #ifdef ENET_DEBUG //fprintf(stderr, "udpr_poll: returning peer %x\n", event->peer); #endif //value v = alloc_abstract(k_udprpeer, event->peer); //return v; }
/** Returns an ENetPeer *, or throw if connection fails. **/ static value udpr_connect(value h, value ip, value port, value channels, value timeout) { ENetAddress address; ENetEvent event; ENetHost *host; ENetPeer *peer; int to; if( !val_is_abstract(h) || !val_is_kind(h,k_udprhost) ) neko_error(); // checked in address population //val_check(ip,int); //val_check(port,int); val_check(channels,int); val_check(timeout,int); to = val_int(timeout); if(to < 0) to = 5000; host = (ENetHost *)val_data(h); if(populate_address(&address, ip, port) != val_true) neko_error(); // Initiate the connection with channels 0..channels-1 peer = enet_host_connect (host, &address, (size_t)val_int(channels)); if (peer == NULL) neko_error(); #ifdef ENET_DEBUG fprintf(stderr, "udpr_connect: waiting %d\n", to); #endif /* Wait up to 5 seconds for the connection attempt to succeed. */ if (enet_host_service (host, & event, to) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { // success #ifdef ENET_DEBUG fprintf(stderr, "udpr_connect: returning peer %x\n", peer); #endif value v = alloc_abstract(k_udprpeer,peer); //val_gc(v, destroy_enetpeer); return v; } // timeout has occurred or disconnect received. #ifdef ENET_DEBUG fprintf(stderr, "udpr_connect: *** enet_peer_reset\n"); #endif enet_peer_reset (peer); neko_error(); }
value ftRenderGlyph( value font, value _index, value _size, value _hint ) { if( !val_is_object(font) ) { ft_failure_v("not a freetype font face: ", font ); } value __f = val_field( font, val_id("__f") ); if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) { ft_failure_v("not a freetype font face: ", font ); } FT_Face *face = val_data( __f ); val_check( _size, number ); int size = val_number(_size); FT_Set_Char_Size( *face, size, size, 72, 72 ); val_check( _hint, bool ); int hint = val_bool(_hint); val_check(_index,number); /* int index = FT_Get_Char_Index( *face, (FT_UInt) val_number(_index) ); fprintf( stderr, "char %i is glyph %i\n", (int)val_number(_index), (int)index ); int err = FT_Load_Glyph( *face, index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING ); fprintf( stderr, "Load Glyph idx %i->%i/%i, sz %i, face %p: err 0x%x\n", (int)val_number(_index), index, (int)((*face)->num_glyphs), size>>6, face, err ); */ int err = FT_Load_Char( *face, (FT_ULong)val_number(_index), FT_LOAD_RENDER | (hint?0:FT_LOAD_NO_HINTING) ); if( err ) { fprintf( stderr, "Load_Char failed: %x char index %i\n", err, FT_Get_Char_Index( *face, (FT_UInt) val_number(_index) ) ); val_throw(alloc_string("Could not load requested Glyph")); // return( val_null ); } FT_GlyphSlot glyph = (*face)->glyph; /* err = FT_Render_Glyph( glyph, FT_RENDER_MODE_NORMAL ); if( err || glyph->format != ft_glyph_format_bitmap ) { val_throw(alloc_string("Could not render requested Glyph")); } */ FT_Bitmap bitmap = glyph->bitmap; value ret = alloc_object(NULL); alloc_field( ret, val_id("width"), alloc_int(bitmap.width) ); alloc_field( ret, val_id("height"), alloc_int(bitmap.rows) ); alloc_field( ret, val_id("bitmap"), copy_string( (char*)bitmap.buffer, bitmap.width*bitmap.rows ) ); alloc_field( ret, val_id("x"), alloc_int( glyph->metrics.horiBearingX ) ); alloc_field( ret, val_id("y"), alloc_int( glyph->metrics.horiBearingY ) ); alloc_field( ret, val_id("advance"), alloc_float( glyph->advance.x )); return ret; }
value ftIterateKerningPairs( value font, value callback ) { if( !val_is_object(font) ) { ft_failure_v("not a freetype font face: ", font ); } value __f = val_field( font, val_id("__f") ); if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) { ft_failure_v("not a freetype font face: ", font ); } FT_Face *face = val_data( __f ); if( !FT_HAS_KERNING((*face)) ) { return val_null; } FT_UInt left_index, right_index; FT_ULong left, right; FT_Vector vec; left = FT_Get_First_Char( *face, &left_index ); while( left != 0 ) { right = FT_Get_First_Char( *face, &right_index ); while( right != 0 ) { if( !FT_Get_Kerning( *face, left_index, right_index, FT_KERNING_UNFITTED, &vec ) && vec.x ) { // printf("KERNING %c_%c: %f\n", left, right, vec.x ); val_call3( callback, alloc_int( (int)left ), alloc_int( (int)right ), alloc_float( vec.x ) ); } right = FT_Get_Next_Char( *face, right, &right_index ); } left = FT_Get_Next_Char( *face, left, &left_index ); } return val_true; }
/** $iskind : any -> 'kind -> bool <doc>Tells if a value is of the given kind</doc> **/ static value builtin_iskind( value v, value k ) { val_check_kind(k,neko_k_kind); return val_is_abstract(v) ? alloc_bool(val_kind(v) == (vkind)val_data(k)) : (val_data(k) == k_old_int32 ? alloc_bool(val_is_int32(v)) : val_false); }
value ftIterateGlyphs( value font, value callbacks ) { if( !val_is_object(callbacks) ) { ft_failure_v("not a callback function object: ", callbacks ); } // printf("A\n"); field endGlyph = val_id("endGlyph"); field startContour = val_id("startContour"); field endContour = val_id("endContour"); field lineTo = val_id("lineTo"); field curveTo = val_id("curveTo"); // printf("B\n"); if( !val_is_object(font) ) { ft_failure_v("not a freetype font face: ", font ); } value __f = val_field( font, val_id("__f") ); if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) { ft_failure_v("not a freetype font face: ", font ); } FT_Face *face = val_data( __f ); // printf("C\n"); FT_UInt glyph_index; FT_ULong character; FT_Outline *outline; field f_character = val_id("character"); field f_advance = val_id("advance"); character = FT_Get_First_Char( *face, &glyph_index ); // printf("D\n"); while( character != 0 ) { if( FT_Load_Glyph( *face, glyph_index, FT_LOAD_NO_BITMAP ) ) { // ignore (TODO report?) } else if( (*face)->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) { // ignore (TODO) } else { outline = &((*face)->glyph->outline); int start = 0, end, contour, p; char control, cubic; int n,i; // printf(" 1\n"); for( contour = 0; contour < outline->n_contours; contour++ ) { end = outline->contours[contour]; n=0; for( p = start; p<=end; p++ ) { control = !(outline->tags[p] & 0x01); cubic = outline->tags[p] & 0x02; if( p==start ) { val_ocall2( callbacks, startContour, alloc_int( outline->points[p-n].x ), alloc_int( outline->points[p-n].y ) ); } if( !control && n > 0 ) { importGlyphPoints( &(outline->points[(p-n)+1]), n-1, callbacks, lineTo, curveTo, cubic ); n=1; } else { n++; } } if( n ) { // special case: repeat first point FT_Vector points[n+1]; int s=(end-n)+2; for( i=0; i<n-1; i++ ) { points[i].x = outline->points[s+i].x; points[i].y = outline->points[s+i].y; } points[n-1].x = outline->points[start].x; points[n-1].y = outline->points[start].y; importGlyphPoints( points, n-1, callbacks, lineTo, curveTo, false ); } start = end+1; val_ocall0( callbacks, endContour ); } // printf(" 2\n"); val_ocall2( callbacks, endGlyph, alloc_int( character ), alloc_int( (*face)->glyph->advance.x ) ); // printf(" 3\n"); } // printf(" E\n"); character = FT_Get_Next_Char( *face, character, &glyph_index ); // printf(" F\n"); } // printf(" Goo\n"); return val_true; }