{#808080FF}static void craft_pane(RowContext* ctx){{
{#808080FF}	mu_Context* mu = ctx->mu;
{#808080FF}	DriftGameState* state = ctx->state;
{#808080FF}	
{#808080FF}	// TODO this needs to get cleaned up.
{#808080FF}	DriftScanType scan_type = DRIFT_ITEMS[ctx->selected].scan;
{#808080FF}	const char* name = DRIFT_ITEMS[ctx->selected].name;
{#808080FF}	static const char* LOADED;
{#808080FF}	if(LOADED != name){{
{#808080FF}		LOADED = name;
{#808080FF}		
{#808080FF}		DriftDraw* draw = ctx->draw;
{#808080FF}		char* filename = DriftSMPrintf(draw->mem, "gfx/scans/%s...
{#808080FF}		
{#808080FF}		// Normalize file name.
{#808080FF}		for(char* c = filename; *c; c++){{
{#808080FF}			if('A' <= *c && *c <='Z') *c += 0x20;
{#808080FF}			if(*c == ' ') *c = '_';
{#808080FF}		}
{#808080FF}		DRIFT_LOG("loading scan image '%s'", filename);
{#808080FF}		
{#808080FF}		DriftImage img = DriftAssetLoadImage(DriftSystemMem, fil...
{#808080FF}		img.pixels = DriftRealloc(DriftSystemMem, img.pixels, im...
{#808080FF}		
{#808080FF}		const DriftGfxDriver* driver = draw->shared->driver;
{#808080FF}		uint queue = tina_job_switch_queue(draw->job, DRIFT_JOB_...
{#808080FF}		driver->load_texture_layer(driver, draw->shared->atlas_t...
{#808080FF}		tina_job_switch_queue(draw->job, queue);
{#808080FF}	}
{#808080FF}	
{#808080FF}	mu_layout_row(mu, 1, (int[]){{256}, 64); {{
{#808080FF}		mu_Rect r = mu_layout_next(mu);
{#808080FF}		mu_draw_icon(mu, -DRIFT_SPRITE_SCAN_IMAGE, r, (mu_Color)...
{#808080FF}	}
{#808080FF}	
{#808080FF}	bool is_recipe_known = state->scan_progress[scan_type] == ...
{#808080FF}	bool can_only_have_one = DRIFT_ITEMS[ctx->selected].can_on...
{#808080FF}	bool can_craft = is_recipe_known && (!can_only_have_one ||...
{#808080FF}	
{#808080FF}	const DriftCraftableItem* craftable = DRIFT_CRAFTABLES + c...
{#808080FF}	const DriftIngredient* ingredients = craftable->ingredient...
{#808080FF}	uint ingredient_count = 0, known_count = 0;
{#808080FF}	while(ingredient_count < DRIFT_CRAFTABLE_MAX_INGREDIENTS){...
{#808080FF}		DriftItemType ingredient_type = ingredients[ingredient_c...
{#808080FF}		if(ingredient_type == DRIFT_ITEM_NONE) break;
{#808080FF}		
{#808080FF}		uint have = state->inventory[ingredient_type], need = in...
{#808080FF}		bool have_enough = have >= need;
{#808080FF}		bool ingredient_known = state->scan_progress[DRIFT_ITEMS...
{#808080FF}		known_count += ingredient_known;
{#808080FF}		can_craft &= have_enough && ingredient_known;
{#808080FF}		
{#808080FF}		ingredient_count++;
{#808080FF}	}
{#808080FF}	
{#808080FF}	mu_layout_row(mu, 2, (int[]){{-90, -1}, 0);
{#808080FF}	mu_layout_begin_column(mu); {{
{#808080FF}		int cols[] = {{-70, -1};
{#808080FF}		mu_layout_row(mu, 2, cols, UI_LINE_HEIGHT);
{#808080FF}		const char* label = (is_recipe_known ? name : STR_CORRUP...
{#808080FF}		const char* color = (is_recipe_known ? DRIFT_TEXT_WHITE ...
{#808080FF}		mu_labelf(mu, "%s%s", color, label);
{#808080FF}		
{#808080FF}		if(is_recipe_known){{
{#808080FF}			mu_labelf(mu, DRIFT_TEXT_GRAY"(have %2d)", state->inve...
{#808080FF}		}
{#808080FF}		
{#808080FF}		for(uint i = 0; i < ingredient_count; i++){{
{#808080FF}			uint ingredient_type = ingredients[i].type;
{#808080FF}			const char* ingredient_name = DRIFT_ITEMS[ingredient_t...
{#808080FF}			if(state->scan_progress[DRIFT_ITEMS[ingredient_type].s...
{#808080FF}				mu_layout_row(mu, 1, (int[]){{-1}, UI_LINE_HEIGHT);
{#808080FF}				mu_labelf(mu, DRIFT_TEXT_GRAY"- "DRIFT_TEXT_RED"UNKN...
{#808080FF}			} else {{
{#808080FF}				uint have = state->inventory[ingredient_type], need ...
{#808080FF}				bool enough = have >= need;
{#808080FF}				const char* color = enough ? DRIFT_TEXT_GREEN : DRIF...
{#808080FF}				mu_layout_row(mu, 2, cols, UI_LINE_HEIGHT);
{#808080FF}				mu_labelf(mu, DRIFT_TEXT_GRAY"- %s", ingredient_name...
{#808080FF}				
{#808080FF}				if(is_recipe_known) mu_labelf(mu, "%s %3d / %2d", co...
{#808080FF}			}
{#808080FF}		}
{#808080FF}	} mu_layout_end_column(mu);
{#808080FF}	mu_layout_begin_column(mu); {{
{#808080FF}		mu_layout_row(mu, 1, (int[]){{-1}, 0);
{#808080FF}		if(can_craft){{
{#808080FF}			if(mu_button(mu, "Craft {{@ACCEPT}") || ctx->focused){...
{#808080FF}				state->inventory[ctx->selected] += craftable->makes ...
{#808080FF}				for(uint p = 0; p < ingredient_count; p++){{
{#808080FF}					state->inventory[ingredients[p].type] -= ingredien...
{#808080FF}				}
{#808080FF}			}
{#808080FF}			if(craftable->makes) mu_labelf(mu, DRIFT_TEXT_GRAY"(Ma...
{#808080FF}		}else if(known_count == ingredient_count && !is_recipe_k...
{#808080FF}			if(mu_button(mu, "Research {{@ACCEPT}") || ctx->focuse...
{#808080FF}		}
{#808080FF}	} mu_layout_end_column(mu);
{#808080FF}	
{#808080FF}	mu_layout_row(mu, 1, (int[]){{-1}, UI_LINE_HEIGHT);
{#808080FF}	if(known_count < ingredient_count){{
{#808080FF}		mu_label(mu, "{{#008080FF}Scan"DRIFT_TEXT_WHITE" or {{#0...
{#808080FF}	} else if(can_only_have_one && state->inventory[ctx->selec...
{#808080FF}		mu_label(mu, "You've built this upgrade already.");
{#808080FF}	} else if(is_recipe_known && !can_craft){{
{#808080FF}		mu_label(mu, "Insufficient Resources");
{#808080FF}	}
{#808080FF}}
