// 0 < distance <= infinity // 0 <= split < 1 // split = 2f means no collision internal void GetCollisionData(WallData *wall, out float cur_dist, out float cur_split) { // Medium performance impact. float drx = wall->geom_direction.x, dry = wall->geom_direction.y; float det = direction.x * dry - direction.y * drx; // Caching can only be used here if (det == 0) // Parallel { cur_dist = float.PositiveInfinity; cur_split = 2f; return; } float spldet = direction.x * (start.y - wall->geom_start.y) - direction.y * (start.x - wall->geom_start.x); float dstdet = wall->geom_direction.x * (start.y - wall->geom_start.y) - wall->geom_direction.y * (start.x - wall->geom_start.x); float spltmp = spldet / det; float dsttmp = dstdet / det; if (spltmp < 0 || spltmp >= 1 || dsttmp <= 0) // dsttmp = 0 means column height = x/0. { cur_dist = float.PositiveInfinity; cur_split = 2f; return; } cur_split = spltmp; cur_dist = dsttmp; }
internal Texture texture; // Yes, by value. internal static WallData *Create(Vector start, Vector end, Texture texture) { WallData *result = (WallData *)Marshal.AllocHGlobal(sizeof(WallData)); result->texture = texture; result->geom_direction = end - start; result->geom_start = start; return(result); }
internal static WallData *Create(Vector start, float angle, float length, Texture texture) { WallData *result = (WallData *)Marshal.AllocHGlobal(sizeof(WallData)); Vector dir = new Vector(angle) * length; result->texture = texture; result->geom_direction = dir; result->geom_start = start; return(result); }
private WallData *NearestWallTest(SceneData *map, out float nearest_dist, out float nearest_hratio) { nearest_dist = float.PositiveInfinity; nearest_hratio = 2f; WallData * nearest = null; WallData **pptr = map->walls; while (*pptr != null) { //Medium performance impact. GetCollisionData(*pptr, out float cur_dist, out float cur_split); if (cur_dist < nearest_dist) { nearest_hratio = cur_split; nearest_dist = cur_dist; nearest = *pptr; } pptr++; } return(nearest); }
internal WallData *NearestWall(SceneData *map, out float nearest_dist, out float nearest_ratio) { nearest_dist = float.PositiveInfinity; nearest_ratio = 2f; int wallcount = map->wall_count; WallData **cur = map->walls; WallData * nearest = null; for (int i = 0; i < wallcount; i++) { //walls cannot be null. GetCollisionData(*cur, out float cur_dist, out float cur_ratio); if (cur_dist < nearest_dist) { nearest_ratio = cur_ratio; nearest_dist = cur_dist; nearest = *cur; } cur++; } return(nearest); }
private unsafe static void CLRRender(PixelBuffer target, SceneData *scene) // Must be changed { //Caching frequently used values. uint * buffer = target.uint0; int width = target.width; int height = target.height; Texture background = scene->background; if (ParallelRendering) { Parallel.For(0, width, Loop); } else { for (int i = 0; i < width; i++) { Loop(i); } } void Loop(int ray_id) //for (int ray_id = 0; ray_id < rendererData->bitmap_width; ray_id++) { //Caching float ray_cos = cache->cosines[ray_id]; float ray_angle = cache->angles[ray_id] + scene->activeObserver->rotation; Ray ray = new Ray(scene->activeObserver->position, ray_angle); //Cast the ray towards every wall. WallData *nearest = ray.NearestWall(scene, out float nearest_dist, out float nearest_ratio); if (nearest_ratio != 2f) { float columnHeight = (cache->colHeight1 / (ray_cos * nearest_dist)); //Wall column size in pixels float column_start = (height - columnHeight) / 2f; float column_end = (height + columnHeight) / 2f; int draw_column_start = (int)column_start; int draw_column_end = (int)column_end; if (draw_column_start < 0) { draw_column_start = 0; } if (draw_column_end > height) { draw_column_end = height; } for (int line = 0; line < draw_column_start; line++) { //PURPOSELY REPEATED CODE! float background_hratio = ray_angle / 360 + 1; //Temporary bugfix to avoid hratio being < 0 float screenVratio = (float)line / height; float background_vratio = (1 - ray_cos) / 2 + ray_cos * screenVratio; uint color = background.MapPixel(background_hratio, background_vratio); buffer[width * line + ray_id] = color; } for (int line = draw_column_start; line < draw_column_end; line++) { float vratio = (line - column_start) / columnHeight; uint pixel = nearest->texture.MapPixel(nearest_ratio, vratio); buffer[width * line + ray_id] = pixel; } for (int line = draw_column_end; line < height; line++) { //PURPOSELY REPEATED CODE! float background_hratio = ray_angle / 360 + 1; //Temporary bugfix to avoid hratio being < 0 float screenVratio = (float)line / height; float background_vratio = (1 - ray_cos) / 2 + ray_cos * screenVratio; uint color = background.MapPixel(background_hratio, background_vratio); buffer[width * line + ray_id] = color; } } else { for (int line = 0; line < height; line++) { //Critical performance impact. //PURPOSELY REPEATED CODE! float background_hratio = ray_angle / 360 + 1; float screenVratio = (float)line / height; float background_vratio = (1 - ray_cos) / 2 + ray_cos * screenVratio; uint color = background.MapPixel(background_hratio, background_vratio); buffer[width * line + ray_id] = color; } } } }
internal void Add(WallData *wall) { walls[wall_count++] = wall; walls[wall_count] = null; }
internal static void Delete(WallData *item) { Marshal.FreeHGlobal((IntPtr)item); }